Skip to content

Instantly share code, notes, and snippets.

@matyklug18
Created January 7, 2022 09:33
Show Gist options
  • Save matyklug18/d097ed3c2863384283e32b5f7952ff10 to your computer and use it in GitHub Desktop.
Save matyklug18/d097ed3c2863384283e32b5f7952ff10 to your computer and use it in GitHub Desktop.
src = """
(def echo (fn (x) (println x)))
(defn hi (x) (println "hi" x))
(hi "world")
(echo "Hello, World!")
(if (== (+ 2 2) (* 2 2)) (echo "Eq works") (echo "Wtf"))
(if (== (+ 0 1) (+ 1 1)) (echo "No, no.") (echo "1 != 2"))
(echo (/ 2 (* 3 2)))
(loop (x 0) (<= x 5) (println x) (recr (+ x 1)))
(echo (input))
"""
from infloats import Float, Fraction
import readline
import traceback
class Node:
def __init__(self, parent):
self.parent = parent
self.childs = []
def append(self, child):
self.childs.append(child)
def get(self, inx):
return self.childs[inx]
def __repr__(self):
return str(self.childs)
def __str__(self): return self.__repr__()
class String:
def __init__(self, value):
self.value = value
def __repr__(self):
return self.value
def __str__(self):
return self.__repr__()
class Symbol:
def __init__(self, value):
self.value = value
def __repr__(self):
return self.value
def __str__(self):
return self.__repr__()
def parse(inp):
curr = Node(None)
root = Node(None)
root.append(curr)
txt = ""
in_str = False
has_elem = False
for i,c in enumerate(inp):
if c == '"':
if in_str:
curr.append(String(txt))
txt = ""
has_elem = False
in_str = not in_str
continue
if in_str:
has_elem = True
txt += c
continue
if c == '(':
curr = Node(curr)
curr.parent.append(curr)
elif c == ')':
if has_elem:
if all((n in "0123456789.") for n in txt):
curr.append(Float(txt))
else:
curr.append(Symbol(txt))
txt = ""
has_elem = False
curr = curr.parent
elif c == ' ':
if has_elem:
if all((n in "0123456789.") for n in txt):
curr.append(Float(txt))
else:
curr.append(Symbol(txt))
txt = ""
has_elem = False
elif c not in ['\n']:
has_elem = True
txt += c
return root.get(0)
class Function:
def __init__(self, quote, value):
self.quote = quote
self.value = value
def g_quote(env, args):
return args
def g_fn(env, names, body):
def run_fn(env, *args):
if len(names.childs) == len(args):
arg_env = {}
for i,n in enumerate(names.childs):
arg_env[n.value] = args[i]
else: print("Argument Mismatch") # TODO error
eval_expr(body, env | arg_env)
return Function(False, run_fn)
def g_def(env, name, value):
env[name.value] = eval_expr(value, env)
def g_if(env, cond, true, false):
if eval_expr(cond, env):
eval_expr(true, env)
else:
eval_expr(false, env)
def g_add(env, *args):
res = args[0]
for a in args[1:]:
res += a
return res
def g_sub(env, *args):
res = args[0]
for a in args[1:]:
res -= a
return res
def g_mul(env, *args):
res = args[0]
for a in args[1:]:
res *= a
return res
def g_div(env, *args):
res = args[0]
for a in args[1:]:
res /= a
return res
def g_do(env, *body):
for b in body:
eval_expr(b, env)
def g_loop(env, param, cond, *body):
locl = {} | env
locl[param.childs[0].value] = param.childs[1]
while eval_expr(cond, locl):
def recr(env, val):
env[param.childs[0].value] = val
locl["recr"] = Function(False, recr)
g_do(locl, *body)
def g_defn(e, n, a, *b):
return g_def(e, n, g_fn(e, a, *b))
gsyms = {
"quote": Function(True, g_quote),
"fn": Function(True, g_fn),
"def": Function(True, g_def),
"defn": Function(True, g_defn),
"if": Function(True, g_if),
"loop": Function(True, g_loop),
"do": Function(True, g_do),
"println": Function(False, lambda *a: print(*(a[1:]))),
"input": Function(False, lambda e, a="": input(a) ),
"==": Function(False, lambda e, a, b: a == b ),
"!=": Function(False, lambda e, a, b: a != b ),
"<": Function(False, lambda e, a, b: a < b ),
"<=": Function(False, lambda e, a, b: a <= b ),
">": Function(False, lambda e, a, b: a > b ),
">=": Function(False, lambda e, a, b: a >= b ),
"!": Function(False, lambda e, a: not a ),
"+": Function(False, g_add),
"-": Function(False, g_sub),
"*": Function(False, g_mul),
"/": Function(False, g_div),
"#t": True,
"#f": False,
}
def eval_expr(node, env):
if type(node) == Node:
inp = node.childs
else:
inp = node
if type(inp) == list:
if type(inp[0]) == Symbol:
sym_name = inp[0].value
if sym_name in env:
val = env[sym_name]
else:
print(f"Symbol not found: {sym_name}")
elif type(inp[0]) == Node:
val = eval_expr(inp[0], env)
if type(val) == Function:
args = inp[1:]
if not val.quote:
args = [eval_expr(e, env) for e in args]
return val.value(env, *args)
else:
print(f"Wrong type {type(inp[0])}")
print(inp[0])
traceback.print_stack()
elif type(inp) == String:
return inp
elif type(inp) == Symbol:
if inp.value in env:
return env[inp.value]
else:
print(f"Symbol not found: {inp.value}")
elif type(inp) in [Float, Fraction, Function]:
return inp
else: print(type(inp), inp)
for ast in parse(src).childs:
#print(ast)
eval_expr(ast, gsyms)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment