From aca6cbe3355e87881e43786810a73380c0ef5240 Mon Sep 17 00:00:00 2001 From: Nicolas Boulenguez Date: Sun, 13 Oct 2024 20:17:55 +0200 Subject: [PATCH] rpython: complete the eval_ast merge, add DEBUG-EVAL --- impls/rpython/env.py | 17 ++++----- impls/rpython/step2_eval.py | 30 ++++++--------- impls/rpython/step3_env.py | 39 +++++++++----------- impls/rpython/step4_if_fn_do.py | 38 +++++++++---------- impls/rpython/step5_tco.py | 39 ++++++++------------ impls/rpython/step6_file.py | 39 ++++++++------------ impls/rpython/step7_quote.py | 41 ++++++++------------- impls/rpython/step8_macros.py | 65 ++++++++++----------------------- impls/rpython/step9_try.py | 65 ++++++++++----------------------- impls/rpython/stepA_mal.py | 20 +++++----- 10 files changed, 148 insertions(+), 245 deletions(-) diff --git a/impls/rpython/env.py b/impls/rpython/env.py index 258874623f..f9324212a4 100644 --- a/impls/rpython/env.py +++ b/impls/rpython/env.py @@ -21,12 +21,6 @@ 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) @@ -34,7 +28,10 @@ def set(self, key, 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] diff --git a/impls/rpython/step2_eval.py b/impls/rpython/step2_eval.py index 82d71c882d..90a093e7f2 100644 --- a/impls/rpython/step2_eval.py +++ b/impls/rpython/step2_eval.py @@ -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: @@ -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) @@ -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)) diff --git a/impls/rpython/step3_env.py b/impls/rpython/step3_env.py index f196dfcecc..d6bf8feacf 100644 --- a/impls/rpython/step3_env.py +++ b/impls/rpython/step3_env.py @@ -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 @@ -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: @@ -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) diff --git a/impls/rpython/step4_if_fn_do.py b/impls/rpython/step4_if_fn_do.py index 1ce49692c9..966f444dd9 100644 --- a/impls/rpython/step4_if_fn_do.py +++ b/impls/rpython/step4_if_fn_do.py @@ -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 @@ -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: @@ -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] @@ -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) @@ -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) diff --git a/impls/rpython/step5_tco.py b/impls/rpython/step5_tco.py index 8d24555c87..fd3620c1f6 100644 --- a/impls/rpython/step5_tco.py +++ b/impls/rpython/step5_tco.py @@ -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 @@ -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: @@ -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] @@ -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] @@ -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) diff --git a/impls/rpython/step6_file.py b/impls/rpython/step6_file.py index 474392761f..9158830b6a 100644 --- a/impls/rpython/step6_file.py +++ b/impls/rpython/step6_file.py @@ -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 @@ -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: @@ -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] @@ -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] @@ -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) diff --git a/impls/rpython/step7_quote.py b/impls/rpython/step7_quote.py index cb8c063ab7..b28a5e6fd1 100644 --- a/impls/rpython/step7_quote.py +++ b/impls/rpython/step7_quote.py @@ -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 @@ -40,15 +40,12 @@ def quasiquote(ast): else: return ast -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: @@ -59,15 +56,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] @@ -89,15 +80,13 @@ def EVAL(ast, env): env = let_env # Continue loop (TCO) elif u"quote" == a0sym: return ast[1] - elif u"quasiquoteexpand" == a0sym: - return quasiquote(ast[1]) elif u"quasiquote" == a0sym: ast = quasiquote(ast[1]) # Continue loop (TCO) 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] @@ -111,14 +100,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) diff --git a/impls/rpython/step8_macros.py b/impls/rpython/step8_macros.py index 8aff32a945..fa950faf06 100644 --- a/impls/rpython/step8_macros.py +++ b/impls/rpython/step8_macros.py @@ -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 @@ -40,30 +40,12 @@ def quasiquote(ast): else: return ast -def is_macro_call(ast, env): - if types._list_Q(ast): - a0 = ast[0] - if isinstance(a0, MalSym): - if not env.find(a0) is None: - return env.get(a0).ismacro - return False - -def macroexpand(ast, env): - while is_macro_call(ast, env): - assert isinstance(ast[0], MalSym) - mac = env.get(ast[0]) - ast = macroexpand(mac.apply(ast.rest()), env) - return ast - -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: @@ -74,20 +56,10 @@ 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) - if len(ast) == 0: return ast - + else: # apply list - ast = macroexpand(ast, env) - if not types._list_Q(ast): - return eval_ast(ast, env) if len(ast) == 0: return ast a0 = ast[0] if isinstance(a0, MalSym): @@ -108,21 +80,17 @@ def EVAL(ast, env): env = let_env # Continue loop (TCO) elif u"quote" == a0sym: return ast[1] - elif u"quasiquoteexpand" == a0sym: - return quasiquote(ast[1]) elif u"quasiquote" == a0sym: ast = quasiquote(ast[1]) # Continue loop (TCO) elif u"defmacro!" == a0sym: func = EVAL(ast[2], env) func.ismacro = True return env.set(ast[1], func) - elif u"macroexpand" == a0sym: - return macroexpand(ast[1], 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] @@ -136,14 +104,19 @@ 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) + if f.ismacro: + ast = f.apply(ast.rest()) # Continue loop (TCO) + else: + 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) diff --git a/impls/rpython/step9_try.py b/impls/rpython/step9_try.py index 40989a7aab..caaca7c48f 100644 --- a/impls/rpython/step9_try.py +++ b/impls/rpython/step9_try.py @@ -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 @@ -40,30 +40,12 @@ def quasiquote(ast): else: return ast -def is_macro_call(ast, env): - if types._list_Q(ast): - a0 = ast[0] - if isinstance(a0, MalSym): - if not env.find(a0) is None: - return env.get(a0).ismacro - return False - -def macroexpand(ast, env): - while is_macro_call(ast, env): - assert isinstance(ast[0], MalSym) - mac = env.get(ast[0]) - ast = macroexpand(mac.apply(ast.rest()), env) - return ast - -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: @@ -74,20 +56,10 @@ 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) - if len(ast) == 0: return ast - + else: # apply list - ast = macroexpand(ast, env) - if not types._list_Q(ast): - return eval_ast(ast, env) if len(ast) == 0: return ast a0 = ast[0] if isinstance(a0, MalSym): @@ -108,16 +80,12 @@ def EVAL(ast, env): env = let_env # Continue loop (TCO) elif u"quote" == a0sym: return ast[1] - elif u"quasiquoteexpand" == a0sym: - return quasiquote(ast[1]) elif u"quasiquote" == a0sym: ast = quasiquote(ast[1]) # Continue loop (TCO) elif u"defmacro!" == a0sym: func = EVAL(ast[2], env) func.ismacro = True return env.set(ast[1], func) - elif u"macroexpand" == a0sym: - return macroexpand(ast[1], env) elif u"try*" == a0sym: if len(ast) < 3: return EVAL(ast[1], env); @@ -139,8 +107,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] @@ -154,14 +122,19 @@ 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) + if f.ismacro: + ast = f.apply(ast.rest()) # Continue loop (TCO) + else: + 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) diff --git a/impls/rpython/stepA_mal.py b/impls/rpython/stepA_mal.py index 9592851066..82ddca157a 100644 --- a/impls/rpython/stepA_mal.py +++ b/impls/rpython/stepA_mal.py @@ -11,7 +11,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 @@ -51,10 +51,10 @@ def quasiquote(ast): def EVAL(ast, env): while True: - #print("EVAL %s" % printer._pr_str(ast)) + 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) + return env.get(ast.value) or throw_str("'" + ast.value + "' not found") elif types._vector_Q(ast): res = [] for a in ast.values: @@ -132,20 +132,18 @@ def EVAL(ast, env): return MalFunc(None, a2, env, a1, EVAL) else: f = EVAL(a0, env) - args = ast.rest() if f.ismacro: ast = f.apply(ast.rest()) # Continue loop (TCO) else: - res = [] - for a in args.values: - res.append(EVAL(a, env)) - el = MalList(res) + 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) # Continue loop (TCO) + env = f.gen_env(args) # Continue loop (TCO) else: - return f.apply(el) + return f.apply(args) else: raise Exception("%s is not callable" % f)