def EVAL(ast, env): while True: if not isinstance(ast, mal_types.list_types): return eval_ast(ast, env) elif not ast: return ast elif isinstance(ast, mal_types.list_types): if len(ast) == 0: return ast if isinstance(ast[0], mal_types.MalSymbol): if ast[0].data == 'def!': value = EVAL(ast[2], env) env.set(ast[1].data, value) return value elif ast[0].data == 'let*': let_env = Env(outer=env) for k, v in zip(ast[1][::2], ast[1][1::2]): let_env.set(k, EVAL(v, let_env)) ast, env = ast[2], let_env continue elif ast[0].data == 'do': ast = eval_ast(ast[1:], env)[-1] return ast elif ast[0].data == 'if': if EVAL(ast[1], env): ast = ast[2] continue else: if len(ast) == 4: ast = ast[3] continue return mal_types.MalNil() elif ast[0].data == 'fn*': def fn(*exprs): new_env = Env(outer=env, binds=ast[1], exprs=exprs) return EVAL(ast[2], new_env) return mal_types.MalFn(ast=ast[2], params=ast[1], env=env, fn=fn) # apply evaluated_ast = eval_ast(ast, env) if callable(evaluated_ast[0]): f, args = evaluated_ast[0], evaluated_ast[1:] if isinstance(f, mal_types.MalFn): ast = f.ast env = Env(outer=f.env, binds=f.params, exprs=args) # print(f) continue else: return f(*args) return evaluated_ast return mal_types.MalNil()
def EVAL(ast, env): while True: # print('INLOOP', ast) if not isinstance(ast, mal_types.list_types): return eval_ast(ast, env) elif not ast: return ast elif isinstance(ast, mal_types.list_types): if len(ast) == 0: return ast ast = macroexpand(ast, env) if not isinstance(ast, mal_types.list_types): return eval_ast(ast, env) if isinstance(ast[0], mal_types.MalSymbol): if ast[0].data == 'macroexpand': return macroexpand(ast[1], env) if ast[0].data == 'def!': value = EVAL(ast[2], env) env.set(ast[1].data, value) return value elif ast[0].data == 'defmacro!': value = EVAL(ast[2], env) value.is_macro = True env.set(ast[1].data, value) return value elif ast[0].data == 'let*': let_env = Env(outer=env) for k, v in zip(ast[1][::2], ast[1][1::2]): new_value = EVAL(v, let_env) let_env.set(k, new_value) # print('let_env', k, new_value) ast, env = ast[2], let_env continue elif ast[0].data == 'do': return eval_ast(ast[1:], env)[-1] elif ast[0].data == 'if': if EVAL(ast[1], env): ast = ast[2] continue else: if len(ast) == 4: ast = ast[3] continue return mal_types.MalNil() elif ast[0].data == 'fn*': def fn(*exprs): new_env = Env(outer=env, binds=ast[1], exprs=exprs) return EVAL(ast[2], new_env) return mal_types.MalFn(ast=ast[2], params=ast[1], env=env, fn=fn) elif ast[0].data == 'quote': return ast[1] elif ast[0].data == 'quasiquote': ast = quasiquote(ast[1]) continue elif ast[0].data == 'try*': try: return EVAL(ast[1], env) except mal_types.MalException as e: new_env = Env(outer=env) new_env.set(ast[2][1], e) return EVAL(ast[2][2], new_env) # apply evaluated_ast = eval_ast(ast, env) if callable(evaluated_ast[0]): #print("function", ast) f, args = evaluated_ast[0], evaluated_ast[1:] # print('f', f) # print('args', args) if isinstance(f, mal_types.MalFn): ast = f.ast env = Env(outer=f.env, binds=f.params, exprs=args) continue else: # print('********************f', f) # print('********************args', args) # print('@result', type(x), x) return f(*args) return evaluated_ast return mal_types.MalNil()