def first(x): # print('x.data', x.data) if isinstance(x, mal_types.MalNil): return mal_types.MalNil() elif isinstance(x, mal_types.list_types) and len(x) == 0: return mal_types.MalNil() return x[0]
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 read_atom(reader): token = reader.peek() try: val = int(token) return mal_types.MalNumber(val) except ValueError: pass if token in _quote_mapping: reader.next() return mal_types.MalList( [mal_types.MalSymbol(_quote_mapping[token]), read_form(reader)]) elif token == '^': reader.next() meta_data = read_form(reader) reader.next() lst = read_form(reader) return mal_types.MalList( [mal_types.MalSymbol("with-meta"), lst, meta_data]) elif token.startswith('"') and token.endswith('"'): return mal_types.MalString( bytes(token[1:-1], "utf-8").decode("unicode_escape")) elif token.startswith(":"): return mal_types.MalKeyword(token) elif token in ('true', 'false'): if token == 'true': return mal_types.MalBool(True) return mal_types.MalBool(False) elif token == 'nil': return mal_types.MalNil() return mal_types.MalSymbol(token) # symbol?
def EVAL(ast, env): # print('EVAL', 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 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)) return EVAL(ast[2], let_env) elif ast[0].data == 'do': return eval_ast(ast[1:], env)[-1] # fixme elif ast[0].data == 'if': if EVAL(ast[1], env): return EVAL(ast[2], env) else: if len(ast) == 4: return EVAL(ast[3], env) return mal_types.MalNil() elif ast[0].data == 'fn*': def closure(*exprs): new_env = Env(outer=env, binds=ast[1], exprs=exprs) # print(new_env.data) # print(ast[2]) return EVAL(ast[2], new_env) return closure evaluated_ast = eval_ast(ast, env) if callable(evaluated_ast[0]): return evaluated_ast[0](*evaluated_ast[1:]) # apply return evaluated_ast return mal_types.MalNil()
def seq(x): if not x.data: return mal_types.MalNil() elif isinstance(x, mal_types.MalList): return x elif isinstance(x, mal_types.MalVector): return mal_types.MalList(x.data) elif isinstance(x, mal_types.MalString): return mal_types.MalList([mal_types.MalString(i) for i in x.data])
def prn(*args): print(" ".join([pr_str(i, print_readably=True) for i in args])) return mal_types.MalNil()
def meta(x): return getattr(x, 'metadata', mal_types.MalNil())
def readline(string): try: return mal_types.MalString(input(string)) except EOFError: return mal_types.MalNil()
def get(x, key): if isinstance(x, mal_types.MalHashMap): return x.get(key) 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()