Created
January 7, 2022 09:33
-
-
Save matyklug18/d097ed3c2863384283e32b5f7952ff10 to your computer and use it in GitHub Desktop.
This file contains 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
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