Skip to content

Instantly share code, notes, and snippets.

@techieji
Created October 25, 2020 21:15
Show Gist options
  • Save techieji/ea0e937bf52efcb17fb240b650d7fd81 to your computer and use it in GitHub Desktop.
Save techieji/ea0e937bf52efcb17fb240b650d7fd81 to your computer and use it in GitHub Desktop.
lisp.py
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