Created
October 25, 2020 21:15
-
-
Save techieji/ea0e937bf52efcb17fb240b650d7fd81 to your computer and use it in GitHub Desktop.
lisp.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import re | |
import operator as op | |
import copy | |
class box: | |
__slots__ = ("obj",) | |
def __init__(self, obj): | |
self.obj = obj | |
def __repr__(self): | |
return f"<box {self.obj}:{type(self.obj)}>" | |
class runner(map): | |
def __init__(self, f, iterator): | |
super().__init__(f, iterator) | |
self.f = f | |
self.i = iterator | |
def __call__(self, ret=False): | |
res = list(copy.deepcopy(self)) | |
if ret: return res | |
def __get_state__(self): | |
pass | |
env = box({ | |
"+": op.add, "-": op.sub, "*": op.mul, "/": op.truediv, | |
"display": print, "string": lambda *args: " ".join(args), | |
"read-line": input, "map": lambda l, f: list(map(f, l)) | |
}) | |
def augExec(aug, fn=lambda: None, restore=True): | |
if restore: before = env.obj | |
env.obj = {**env.obj, **aug} | |
ret = fn() | |
if restore: env.obj = before | |
return ret | |
class proc: | |
__slots__ = ("vars", "body") | |
def __init__(self, vars, body): | |
self.vars = vars | |
self.body = body | |
def __call__(self, *args): | |
auger = dict(zip(self.vars, args)) | |
return augExec(auger, lambda: _run(self.body)) | |
def rmap(f, l): | |
yield from [tuple(rmap(f, x)) if type(x) in [list, tuple] else f(x) for x in l] | |
def transform(element): | |
try: return int(element) | |
except: | |
try: return float(element) | |
except: return element | |
code1 = """ | |
(define 2x+2 | |
(lambda (x) | |
(* 2 (+ x 1)))) | |
(display "Hello World!") | |
""" | |
def parse(text): | |
return tuple(rmap(transform, | |
eval("(" + | |
re.sub(r"\)+", lambda x: x.group(0) + ",", | |
re.sub(r"[^\(\) ]+", lambda x: f"'{x.group(0)}',", | |
re.sub(r"\s", lambda x: " ", | |
re.sub(r'".*"', lambda x: f"(string {x.group(0)[1:-1]})", | |
text.strip() | |
) | |
) | |
) | |
)[:-1] | |
+ ")") | |
)) | |
def _run(parseout): | |
if parseout in env.obj: | |
return env.obj[parseout] | |
if type(parseout) is not tuple: | |
return parseout | |
op, *args = parseout | |
if op == "define": | |
res = _run(args[1]) | |
augExec({args[0]: res}, restore=False) | |
return res | |
elif op == "lambda": | |
return proc(args[0], args[1]) | |
else: | |
return env.obj[op](*map(_run, args)) | |
def run(string: str): | |
lines = string.split(" ") | |
ret = [""] | |
for x in lines: | |
last = ret[-1] | |
if last and last.count("(") == last.count(")"): | |
ret.append(x) | |
else: | |
ret[-1] += " " + x | |
ret = map(parse, map(lambda x: re.sub("\s+", lambda x: " ", x).strip(), ret)) | |
return runner(_run, filter(bool, ret)) | |
def repl(): | |
while True: | |
res = _run(parse(input("> "))) | |
if res is not None: | |
print(res) | |
m = run(code1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment