Skip to content

Commit

Permalink
rpython: complete the eval_ast merge, add DEBUG-EVAL
Browse files Browse the repository at this point in the history
  • Loading branch information
asarhaddon committed Oct 15, 2024
1 parent 9416545 commit aca6cbe
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 245 deletions.
17 changes: 7 additions & 10 deletions impls/rpython/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,17 @@ def __init__(self, outer=None, binds=None, exprs=None):
else:
self.data[bind.value] = exprs[i]

def find(self, key):
assert isinstance(key, MalSym)
if key.value in self.data: return self
elif self.outer: return self.outer.find(key)
else: return None

def set(self, key, value):
assert isinstance(key, MalSym)
assert isinstance(value, MalType)
self.data[key.value] = value
return value

def get(self, key):
assert isinstance(key, MalSym)
env = self.find(key)
if not env: throw_str("'" + str(key.value) + "' not found")
return env.data[key.value]
assert isinstance(key, unicode)
env = self
while key not in env.data:
env = env.outer
if env is None:
return None
return env.data[key]
30 changes: 12 additions & 18 deletions impls/rpython/step2_eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,14 @@ def READ(str):
return reader.read_str(str)

# eval
def eval_ast(ast, env):
def EVAL(ast, env):
# print(u"EVAL " + printer._pr_str(ast))
if types._symbol_Q(ast):
assert isinstance(ast, MalSym)
if ast.value in env:
return env[ast.value]
else:
raise Exception(u"'" + ast.value + u"' not found")
elif types._list_Q(ast):
res = []
for a in ast.values:
res.append(EVAL(a, env))
return MalList(res)
raise Exception("'" + ast.value + "' not found")
elif types._vector_Q(ast):
res = []
for a in ast.values:
Expand All @@ -33,20 +29,18 @@ def eval_ast(ast, env):
for k in ast.dct.keys():
new_dct[k] = EVAL(ast.dct[k], env)
return MalHashMap(new_dct)
else:
elif not types._list_Q(ast):
return ast # primitive value, return unchanged

def EVAL(ast, env):
#print("EVAL %s" % printer._pr_str(ast))
if not types._list_Q(ast):
return eval_ast(ast, env)

else:
# apply list
if len(ast) == 0: return ast
el = eval_ast(ast, env)
f = el.values[0]
a0 = ast[0]
f = EVAL(a0, env)
args = []
for i in range(1, len(ast)):
args.append(EVAL(ast[i], env))
if isinstance(f, MalFunc):
return f.apply(el.values[1:])
return f.apply(args)
else:
raise Exception("%s is not callable" % f)

Expand All @@ -55,7 +49,7 @@ def PRINT(exp):
return printer._pr_str(exp)

# repl
repl_env = {}
repl_env = {}
def REP(str, env):
return PRINT(EVAL(READ(str), env))

Expand Down
39 changes: 17 additions & 22 deletions impls/rpython/step3_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import mal_readline
import mal_types as types
from mal_types import (MalSym, MalInt, MalStr,
_symbol, _keywordu,
nil, false, _symbol, _keywordu, throw_str,
MalList, _list, MalVector, MalHashMap, MalFunc)
import reader, printer
from env import Env
Expand All @@ -12,15 +12,11 @@ def READ(str):
return reader.read_str(str)

# eval
def eval_ast(ast, env):
def EVAL(ast, env):
if env.get(u"DEBUG-EVAL") not in (None, nil, false):
print(u"EVAL " + printer._pr_str(ast))
if types._symbol_Q(ast):
assert isinstance(ast, MalSym)
return env.get(ast)
elif types._list_Q(ast):
res = []
for a in ast.values:
res.append(EVAL(a, env))
return MalList(res)
return env.get(ast.value) or throw_str("'" + ast.value + "' not found")
elif types._vector_Q(ast):
res = []
for a in ast.values:
Expand All @@ -31,35 +27,34 @@ def eval_ast(ast, env):
for k in ast.dct.keys():
new_dct[k] = EVAL(ast.dct[k], env)
return MalHashMap(new_dct)
else:
elif not types._list_Q(ast):
return ast # primitive value, return unchanged

def EVAL(ast, env):
#print("EVAL %s" % printer._pr_str(ast))
if not types._list_Q(ast):
return eval_ast(ast, env)

else:
# apply list
if len(ast) == 0: return ast
a0 = ast[0]
if not isinstance(a0, MalSym):
if isinstance(a0, MalSym):
a0sym = a0.value
else:
raise Exception("attempt to apply on non-symbol")

if u"def!" == a0.value:
if u"def!" == a0sym:
a1, a2 = ast[1], ast[2]
res = EVAL(a2, env)
return env.set(a1, res)
elif u"let*" == a0.value:
elif u"let*" == a0sym:
a1, a2 = ast[1], ast[2]
let_env = Env(env)
for i in range(0, len(a1), 2):
let_env.set(a1[i], EVAL(a1[i+1], let_env))
return EVAL(a2, let_env)
else:
el = eval_ast(ast, env)
f = el.values[0]
f = EVAL(a0, env)
args = []
for i in range(1, len(ast)):
args.append(EVAL(ast[i], env))
if isinstance(f, MalFunc):
return f.apply(el.values[1:])
return f.apply(args)
else:
raise Exception("%s is not callable" % f)

Expand Down
38 changes: 17 additions & 21 deletions impls/rpython/step4_if_fn_do.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import mal_readline
import mal_types as types
from mal_types import (MalSym, MalInt, MalStr,
nil, true, false, _symbol, _keywordu,
nil, true, false, _symbol, _keywordu, throw_str,
MalList, _list, MalVector, MalHashMap, MalFunc)
import reader, printer
from env import Env
Expand All @@ -13,15 +13,11 @@ def READ(str):
return reader.read_str(str)

# eval
def eval_ast(ast, env):
def EVAL(ast, env):
if env.get(u"DEBUG-EVAL") not in (None, nil, false):
print(u"EVAL " + printer._pr_str(ast))
if types._symbol_Q(ast):
assert isinstance(ast, MalSym)
return env.get(ast)
elif types._list_Q(ast):
res = []
for a in ast.values:
res.append(EVAL(a, env))
return MalList(res)
return env.get(ast.value) or throw_str("'" + ast.value + "' not found")
elif types._vector_Q(ast):
res = []
for a in ast.values:
Expand All @@ -32,14 +28,9 @@ def eval_ast(ast, env):
for k in ast.dct.keys():
new_dct[k] = EVAL(ast.dct[k], env)
return MalHashMap(new_dct)
else:
elif not types._list_Q(ast):
return ast # primitive value, return unchanged

def EVAL(ast, env):
#print("EVAL %s" % printer._pr_str(ast))
if not types._list_Q(ast):
return eval_ast(ast, env)

else:
# apply list
if len(ast) == 0: return ast
a0 = ast[0]
Expand All @@ -59,8 +50,11 @@ def EVAL(ast, env):
let_env.set(a1[i], EVAL(a1[i+1], let_env))
return EVAL(a2, let_env)
elif u"do" == a0sym:
el = eval_ast(ast.rest(), env)
return el.values[-1]
if len(ast) == 0:
return nil
for i in range(1, len(ast) - 1):
EVAL(ast[i], env)
return EVAL(ast[-1], env)
elif u"if" == a0sym:
a1, a2 = ast[1], ast[2]
cond = EVAL(a1, env)
Expand All @@ -73,10 +67,12 @@ def EVAL(ast, env):
a1, a2 = ast[1], ast[2]
return MalFunc(None, a2, env, a1, EVAL)
else:
el = eval_ast(ast, env)
f = el.values[0]
f = EVAL(a0, env)
args = []
for i in range(1, len(ast)):
args.append(EVAL(ast[i], env))
if isinstance(f, MalFunc):
return f.apply(el.rest())
return f.apply(args)
else:
raise Exception("%s is not callable" % f)

Expand Down
39 changes: 16 additions & 23 deletions impls/rpython/step5_tco.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import mal_readline
import mal_types as types
from mal_types import (MalSym, MalInt, MalStr,
nil, true, false, _symbol, _keywordu,
nil, true, false, _symbol, _keywordu, throw_str,
MalList, _list, MalVector, MalHashMap, MalFunc)
import reader, printer
from env import Env
Expand All @@ -13,15 +13,12 @@ def READ(str):
return reader.read_str(str)

# eval
def eval_ast(ast, env):
def EVAL(ast, env):
while True:
if env.get(u"DEBUG-EVAL") not in (None, nil, false):
print(u"EVAL " + printer._pr_str(ast))
if types._symbol_Q(ast):
assert isinstance(ast, MalSym)
return env.get(ast)
elif types._list_Q(ast):
res = []
for a in ast.values:
res.append(EVAL(a, env))
return MalList(res)
return env.get(ast.value) or throw_str("'" + ast.value + "' not found")
elif types._vector_Q(ast):
res = []
for a in ast.values:
Expand All @@ -32,15 +29,9 @@ def eval_ast(ast, env):
for k in ast.dct.keys():
new_dct[k] = EVAL(ast.dct[k], env)
return MalHashMap(new_dct)
else:
elif not types._list_Q(ast):
return ast # primitive value, return unchanged

def EVAL(ast, env):
while True:
#print("EVAL %s" % printer._pr_str(ast))
if not types._list_Q(ast):
return eval_ast(ast, env)

else:
# apply list
if len(ast) == 0: return ast
a0 = ast[0]
Expand All @@ -63,8 +54,8 @@ def EVAL(ast, env):
elif u"do" == a0sym:
if len(ast) == 0:
return nil
elif len(ast) > 1:
eval_ast(ast.slice2(1, len(ast)-1), env)
for i in range(1, len(ast) - 1):
EVAL(ast[i], env)
ast = ast[-1] # Continue loop (TCO)
elif u"if" == a0sym:
a1, a2 = ast[1], ast[2]
Expand All @@ -78,14 +69,16 @@ def EVAL(ast, env):
a1, a2 = ast[1], ast[2]
return MalFunc(None, a2, env, a1, EVAL)
else:
el = eval_ast(ast, env)
f = el.values[0]
f = EVAL(a0, env)
args = []
for i in range(1, len(ast)):
args.append(EVAL(ast[i], env))
if isinstance(f, MalFunc):
if f.ast:
ast = f.ast
env = f.gen_env(el.rest()) # Continue loop (TCO)
env = f.gen_env(args) # Continue loop (TCO)
else:
return f.apply(el.rest())
return f.apply(args)
else:
raise Exception("%s is not callable" % f)

Expand Down
Loading

0 comments on commit aca6cbe

Please sign in to comment.