def conj(args): lst, args = args[0], args.rest() new_lst = None if types._list_Q(lst): vals = args.values[:] vals.reverse() new_lst = MalList(vals + lst.values) elif types._vector_Q(lst): new_lst = MalVector(lst.values + list(args.values)) else: throw_str("conj on non-list/non-vector") new_lst.meta = lst.meta return new_lst
def eval_ast(ast: MalExpression, env: Env) -> MalExpression: if isinstance(ast, MalSymbol): return env.get(ast) if isinstance(ast, MalList): return MalList([EVAL(x, env) for x in ast.native()]) if isinstance(ast, MalVector): return MalVector([EVAL(x, env) for x in ast.native()]) if isinstance(ast, MalHash_map): new_dict = {} # type: Dict[str, MalExpression] for key in ast.native(): new_dict[key] = EVAL(ast.native()[key], env) return MalHash_map(new_dict) return ast
def entry_point(argv): repl_env = Env() def REP(str, env): return PRINT(EVAL(READ(str), env)) # core.py: defined using python for k, v in core.ns.items(): repl_env.set(_symbol(unicode(k)), MalFunc(v)) repl_env.set(types._symbol(u'eval'), MalEval(None, env=repl_env, EvalFunc=EVAL)) mal_args = [] if len(argv) >= 3: for a in argv[2:]: mal_args.append(MalStr(unicode(a))) repl_env.set(_symbol(u'*ARGV*'), MalList(mal_args)) # core.mal: defined using the language itself REP("(def! *host-language* \"rpython\")", repl_env) REP("(def! not (fn* (a) (if a false true)))", repl_env) REP( "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))", repl_env) REP( "(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))", repl_env) if len(argv) >= 2: REP('(load-file "' + argv[1] + '")', repl_env) return 0 REP("(println (str \"Mal [\" *host-language* \"]\"))", repl_env) while True: try: line = mal_readline.readline("user> ") if line == "": continue print(REP(line, repl_env)) except EOFError as e: break except reader.Blank: continue except types.MalException as e: print(u"Error: %s" % printer._pr_str(e.object, False)) except Exception as e: print("Error: %s" % e) if IS_RPYTHON: llop.debug_print_traceback(lltype.Void) else: print("".join(traceback.format_exception(*sys.exc_info()))) return 0
def test_let_multiple(self): env = Env(None) env.set( "+", mal_types.MalFunctionCompiled( lambda a: MalInt(a[0].native() + a[1].native())), ) self.assertEqual( 5, step3_env.EVAL( MalList([ MalSymbol("let*"), MalList( [MalSymbol("c"), MalInt(2), MalSymbol("d"), MalInt(3)]), MalList([MalSymbol("+"), MalSymbol("c"), MalSymbol("d")]), ]), env, ).native(), )
def main(): rep("(def! not (fn* (a) (if a false true)))") rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\\nnil)\")))))") argv_lst = MalList("(") argv_lst += ['"' + reader.read_str(x) + '"' for x in sys.argv[2:]] repl_env.set_("*ARGV*", argv_lst) if len(sys.argv) > 1: rep("(load-file \"" + sys.argv[1] + '")') return while 1: try: read_str = input("user> ") except EOFError: break print(rep(read_str))
def apply(x, *y): assert type(y[-1] == MalList) tmp = MalList("(") for i in y[:-1]: tmp.append(i) tmp.extend(y[-1]) if type(x) == dict: return x["fn"](*tmp) else: return x(*tmp)
def main(): rep("(def! not (fn* (a) (if a false true)))") rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\\nnil)\")))))") rep("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))") argv_lst = MalList("(") argv_lst += ['"' + reader.read_str(x) + '"' for x in sys.argv[2:]] repl_env.set_("*ARGV*", argv_lst) if len(sys.argv) > 1: rep("(load-file \"" + sys.argv[1] + '")') return while 1: try: read_str = input("user> ") except EOFError: break print(rep(read_str))
def __init__( self, outer: Optional["Env"], binds: Optional[List[MalExpression]] = None, exprs: Optional[List[MalExpression]] = None, ) -> None: self._outer = outer self._data: Dict[str, MalExpression] = {} if binds is not None and exprs is not None: for x in range(0, len(binds)): assert isinstance(binds[x], MalSymbol) if binds[x].native() == "&": self.set(str(binds[x + 1]), MalList(exprs[x:])) break else: self.set(str(binds[x]), exprs[x])
def dissoc(args: List[MalExpression]) -> MalExpression: if len(args) == 0: raise MalInvalidArgumentException(MalNil(), "no arguments supplied to dissoc") elif len(args) == 1: return args[0] if not isinstance(args[0], MalHash_map): raise MalInvalidArgumentException(args[0], "not a hash map") dict_a_copy: Dict[str, MalExpression] = args[0].native().copy() list_b: List[MalExpression] = MalList(args[1:]).native() for key in list_b: try: del dict_a_copy[key.unreadable_str()] except KeyError: pass return MalHash_map(dict_a_copy)
def eval_ast(ast: MalExpression, env: Dict[str, MalFunctionCompiled]) -> MalExpression: if isinstance(ast, MalSymbol): try: return env[str(ast)] except KeyError: raise MalUnknownSymbolException(str(ast)) if isinstance(ast, MalList): return MalList([EVAL(x, env) for x in ast.native()]) if isinstance(ast, MalVector): return MalVector([EVAL(x, env) for x in ast.native()]) if isinstance(ast, MalHash_map): new_dict = {} # type: Dict[str, MalExpression] for key in ast.native(): new_dict[key] = EVAL(ast.native()[key], env) return MalHash_map(new_dict) return ast
def entry_point(argv): repl_env = Env() def REP(str, env): return PRINT(EVAL(READ(str), env)) # core.py: defined using python for k, v in core.ns.items(): repl_env.set(_symbol(unicode(k)), MalFunc(v)) repl_env.set(types._symbol(u'eval'), MalEval(None, env=repl_env, EvalFunc=EVAL)) mal_args = [] if len(argv) >= 3: for a in argv[2:]: mal_args.append(MalStr(unicode(a))) repl_env.set(_symbol(u'*ARGV*'), MalList(mal_args)) # core.mal: defined using the language itself REP("(def! not (fn* (a) (if a false true)))", repl_env) REP( "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))", repl_env) if len(argv) >= 2: REP('(load-file "' + argv[1] + '")', repl_env) return 0 while True: try: line = mal_readline.readline("user> ") if line == "": continue print(REP(line, repl_env)) except EOFError as e: break except reader.Blank: continue except types.MalException as e: print(u"Error: %s" % printer._pr_str(e.object, False)) except Exception as e: print("Error: %s" % e) #print("".join(traceback.format_exception(*sys.exc_info()))) return 0
def eval_ast(ast, env): 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) elif types._vector_Q(ast): res = [] for a in ast.values: res.append(EVAL(a, env)) return MalVector(res) elif types._hash_map_Q(ast): new_dct = {} for k in ast.dct.keys(): new_dct[k] = EVAL(ast.dct[k], env) return MalHashMap(new_dct) else: return ast # primitive value, return unchanged
def assoc(x, *y): assert len(y) % 2 == 0 assert type(x) == MalList and x.opener == "{" tmp = MalList("{") tmp_dict = {} for i in range(0, len(x), 2): tmp_dict[x[i]] = x[i + 1] for i in range(0, len(y), 2): tmp_dict[y[i]] = y[i + 1] for key in tmp_dict: tmp.append(key) tmp.append(tmp_dict[key]) return tmp
def vals(args): hm = args[0] return MalList(hm.dct.values())
def keys(args): hm = args[0] keys = [] for k in hm.dct.keys(): keys.append(MalStr(k)) return MalList(keys)
def EVAL(ast: MalExpression, env: Env) -> MalExpression: while True: dbgeval = env.get("DEBUG-EVAL") if (dbgeval is not None and not isinstance(dbgeval, MalNil) and (not isinstance(dbgeval, MalBoolean) or dbgeval.native())): print("EVAL: " + str(ast)) ast_native = ast.native() if isinstance(ast, MalSymbol): key = str(ast) val = env.get(key) if val is None: raise MalUnknownSymbolException(key) return val if isinstance(ast, MalVector): return MalVector([EVAL(x, env) for x in ast_native]) if isinstance(ast, MalHash_map): new_dict = {} # type: Dict[str, MalExpression] for key in ast_native: new_dict[key] = EVAL(ast_native[key], env) return MalHash_map(new_dict) if not isinstance(ast, MalList): return ast elif len(ast_native) == 0: return ast first_str = str(ast_native[0]) if first_str == "def!": name: str = str(ast_native[1]) value: MalExpression = EVAL(ast_native[2], env) return env.set(name, value) elif first_str == "let*": assert len(ast_native) == 3 let_env = Env(env) bindings: MalExpression = ast_native[1] assert isinstance(bindings, MalList) or isinstance( bindings, MalVector) bindings_list: List[MalExpression] = bindings.native() assert len(bindings_list) % 2 == 0 for i in range(0, len(bindings_list), 2): assert isinstance(bindings_list[i], MalSymbol) assert isinstance(bindings_list[i + 1], MalExpression) let_env.set(str(bindings_list[i]), EVAL(bindings_list[i + 1], let_env)) env = let_env ast = ast_native[2] continue elif first_str == "do": for x in range(1, len(ast_native) - 1): EVAL(ast_native[x], env) ast = ast_native[len(ast_native) - 1] continue elif first_str == "if": condition = EVAL(ast_native[1], env) if isinstance(condition, MalNil) or (isinstance(condition, MalBoolean) and condition.native() is False): if len(ast_native) >= 4: ast = ast_native[3] continue else: return MalNil() else: ast = ast_native[2] continue elif first_str == "fn*": raw_ast = ast_native[2] raw_params = ast_native[1] def fn(args: List[MalExpression]) -> MalExpression: f_ast = raw_ast f_env = Env(outer=env, binds=raw_params.native(), exprs=args) return EVAL(f_ast, f_env) return MalFunctionRaw(fn=fn, ast=raw_ast, params=raw_params, env=env) elif first_str == "quote": return (MalList(ast_native[1].native()) if isinstance( ast_native[1], MalVector) else ast_native[1]) elif first_str == "quasiquote": ast = quasiquote(ast_native[1]) continue else: f, *args = (EVAL(form, env) for form in ast_native) if isinstance(f, MalFunctionRaw): ast = f.ast() env = Env( outer=f.env(), binds=f.params().native(), exprs=args, ) continue elif isinstance(f, MalFunctionCompiled): return f.call(args) else: raise MalInvalidArgumentException(f, "not a function")
def qq_foldr(xs: List[MalExpression]) -> MalList: return functools.reduce(qq_loop, reversed(xs), MalList([]))
def swap(args: List[MalExpression]) -> MalExpression: atom = args[0] assert isinstance(atom, MalAtom) func = args[1] atom.reset(EVAL(MalList([func, atom.native()] + args[2:]), repl_env)) return atom.native()
def concat(args: List[MalExpression]) -> MalExpression: result_list: List[MalExpression] = [] for x in args: assert isinstance(x, MalList) or isinstance(x, MalVector) result_list = result_list + x.native() return MalList(result_list)
def concat(*a): temp = MalList("(") for next_list in a: for next_item in next_list: temp.append(next_item) return temp
def vec(a): temp = MalList("[") temp.extend(a) return temp
def eval_(ast, env: Env): while 1: ast = macroexpand(ast, env) if type(ast) != MalList or ast.opener != "(": return eval_ast(ast, env) if len(ast) == 0: return ast if ast[0] == "def!": second_param = eval_(ast[2], env) env.set_(ast[1], second_param) return second_param if ast[0] == "let*": let_env = Env(env) bindings = ast[1] i = 0 while 1: try: let_env.set_(bindings[i], eval_(bindings[i + 1], let_env)) i += 2 except IndexError: break env = let_env ast = ast[2] continue if ast[0] == "do": do_ast = MalList("(") do_ast += ast[1:-1] eval_ast(do_ast, env) ast = ast[-1] continue if ast[0] == "if": cond = eval_(ast[1], env) if cond == 0 and type(cond) == int: cond = True # Counting number 0 as True if cond is None: cond = False if cond != False: ast = ast[2] continue if cond == False and len(ast) <= 3: return None ast = ast[3] continue if ast[0] == "fn*": def closure(binds, exprs, *args): fn_env = Env(env, binds=binds, exprs=args) return eval_(exprs, fn_env) return { "ast": ast[2], "params": ast[1], "env": env, "fn": lambda *x: closure(ast[1], ast[2], *x), } if ast[0] == "quote": return ast[1] if ast[0] == "quasiquote" or ast[0] == "quasiquoteexpand": def quasiquote(param): def in_list(param): res = MalList("(") for elt in reversed(param): if type(elt) == MalList and len(elt) > 1 and elt[0] == "splice-unquote": tmp = MalList("(") tmp.append("concat") tmp.append(elt[1]) tmp.append(res) res = tmp else: tmp = MalList("(") tmp.append("cons") tmp.append(quasiquote(elt)) tmp.append(res) res = tmp return res if type(param) == MalList and param.opener == "(" and len(param) > 0 and param[0] == "unquote": return param[1] elif type(param) == MalList and param.opener == "(": return in_list(param) elif (type(param) == MalList and param.opener == "{") or (type(param) == str): tmp = MalList("(") tmp.append("quote") tmp.append(param) return tmp elif type(param) == MalList and param.opener == "[": tmp = MalList("(") tmp.append("vec") tmp.append(in_list(param)) return tmp else: return param if ast[0] == "quasiquote": ast = quasiquote(ast[1]) continue else: return quasiquote(ast[1]) if ast[0] == "defmacro!": second_param = eval_(ast[2], env) if type(second_param) != dict: second_param.is_macro = True else: second_param["is_macro"] = True env.set_(ast[1], second_param) return second_param if ast[0] == "macroexpand": return macroexpand(ast[1], env) else: eval_list = eval_ast(ast, env) if type(eval_list[0]) == dict: f = eval_list[0] ast = f["ast"] env = Env(outer=f["env"], binds=f["params"], exprs=eval_list[1:]) continue else: return eval_list[0](*eval_list[1:])
def in_list(param): res = MalList("(") for elt in reversed(param): if type(elt) == MalList and len(elt) > 1 and elt[0] == "splice-unquote": tmp = MalList("(") tmp.append("concat") tmp.append(elt[1]) tmp.append(res) res = tmp else: tmp = MalList("(") tmp.append("cons") tmp.append(quasiquote(elt)) tmp.append(res) res = tmp return res
def rest(x): temp = MalList("(") if x is not None and len(x) > 0: temp += x[1:] return temp
MalFunctionCompiled( lambda args: MalInt(args[0].native() - args[1].native())), "*": MalFunctionCompiled( lambda args: MalInt(args[0].native() * args[1].native())), "/": MalFunctionCompiled( lambda args: MalInt(int(args[0].native() / args[1].native()))), "prn": MalFunctionCompiled(lambda args: prn(args)), "pr-str": MalFunctionCompiled(lambda args: pr_str(args)), "println": MalFunctionCompiled(lambda args: println(args)), "list": MalFunctionCompiled(lambda args: MalList(args)), "list?": MalFunctionCompiled(lambda args: list_q(args[0])), "empty?": MalFunctionCompiled(lambda args: empty_q(args[0])), "count": MalFunctionCompiled(lambda args: count(args[0])), "=": MalFunctionCompiled(lambda args: equal(args[0], args[1])), "<": MalFunctionCompiled(lambda args: less(args[0], args[1])), "<=": MalFunctionCompiled(lambda args: less_equal(args[0], args[1])), ">": MalFunctionCompiled(lambda args: less(args[1], args[0])), ">=":
def cons(args): x, seq = args[0], args[1] if not isinstance(seq, MalList): throw_str("cons called with non-list/non-vector") return MalList([x] + seq.values)
def EVAL(ast: MalExpression, env: Env) -> MalExpression: while True: ast = macroexpand(ast, env) ast_native = ast.native() if not isinstance(ast, MalList): return eval_ast(ast, env) elif len(ast_native) == 0: return ast first_str = str(ast_native[0]) if first_str == "macroexpand": return macroexpand(ast.native()[1], env) elif first_str == "def!": name: str = str(ast_native[1]) value: MalExpression = EVAL(ast_native[2], env) return env.set(name, value) if first_str == "defmacro!": name = str(ast_native[1]) value = EVAL(ast_native[2], env) assert isinstance(value, MalFunctionCompiled) or isinstance( value, MalFunctionRaw) value.make_macro() return env.set(name, value) elif first_str == "let*": assert len(ast_native) == 3 let_env = Env(env) bindings: MalExpression = ast_native[1] assert isinstance(bindings, MalList) or isinstance( bindings, MalVector) bindings_list: List[MalExpression] = bindings.native() assert len(bindings_list) % 2 == 0 for i in range(0, len(bindings_list), 2): assert isinstance(bindings_list[i], MalSymbol) assert isinstance(bindings_list[i + 1], MalExpression) let_env.set(str(bindings_list[i]), EVAL(bindings_list[i + 1], let_env)) env = let_env ast = ast_native[2] continue elif first_str == "do": for x in range(1, len(ast_native) - 1): EVAL(ast_native[x], env) ast = ast_native[len(ast_native) - 1] continue elif first_str == "if": condition = EVAL(ast_native[1], env) if isinstance(condition, MalNil) or (isinstance(condition, MalBoolean) and condition.native() is False): if len(ast_native) >= 4: ast = ast_native[3] continue else: return MalNil() else: ast = ast_native[2] continue elif first_str == "fn*": raw_ast = ast_native[2] raw_params = ast_native[1] def fn(args: List[MalExpression]) -> MalExpression: f_ast = raw_ast f_env = Env(outer=env, binds=raw_params.native(), exprs=args) return EVAL(f_ast, f_env) return MalFunctionRaw(fn=fn, ast=raw_ast, params=raw_params, env=env) elif first_str == "quote": return (MalList(ast_native[1].native()) if isinstance( ast_native[1], MalVector) else ast_native[1]) elif first_str == "quasiquote": ast = quasiquote(ast_native[1]) continue elif first_str == "try*": try: return EVAL(ast_native[1], env) except MalException as e: if len(ast_native) < 3: raise e catch_block = ast_native[2] assert (isinstance(catch_block, MalList) and isinstance(catch_block.native()[0], MalSymbol) and str(catch_block.native()[0]) == "catch*" and len(catch_block.native()) == 3) exception_symbol = catch_block.native()[1] assert isinstance(exception_symbol, MalSymbol) env = Env(env) env.set(str(exception_symbol), e.native()) ast = catch_block.native()[2] continue else: evaled_ast = eval_ast(ast, env) f = evaled_ast.native()[0] args = evaled_ast.native()[1:] if isinstance(f, MalFunctionRaw): ast = f.ast() env = Env( outer=f.env(), binds=f.params().native(), exprs=evaled_ast.native()[1:], ) continue elif isinstance(f, MalFunctionCompiled): return f.call(args) else: raise MalInvalidArgumentException(f, "not a function")
def cons(a, b): temp = MalList("(") temp.append(a) for next_item in b: temp.append(next_item) return temp
def PRINT(x: MalExpression) -> str: return str(x) def rep(x: str) -> str: return PRINT(EVAL(READ(x), repl_env)) if __name__ == "__main__": # repl loop eof: bool = False rep('(def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) "\nnil)")))))' ) mal_argv = MalList([MalString(x) for x in sys.argv[2:]]) repl_env.set("*ARGV*", mal_argv) if len(sys.argv) >= 2: file_str = sys.argv[1] rep('(load-file "' + file_str + '")') exit(0) while not eof: try: line = input("user> ") readline.add_history(line) try: print(rep(line)) except MalUnknownSymbolException as e: print("'" + e.func + "' not found")
def quasiquote(param): def in_list(param): res = MalList("(") for elt in reversed(param): if type(elt) == MalList and len(elt) > 1 and elt[0] == "splice-unquote": tmp = MalList("(") tmp.append("concat") tmp.append(elt[1]) tmp.append(res) res = tmp else: tmp = MalList("(") tmp.append("cons") tmp.append(quasiquote(elt)) tmp.append(res) res = tmp return res if type(param) == MalList and param.opener == "(" and len(param) > 0 and param[0] == "unquote": return param[1] elif type(param) == MalList and param.opener == "(": return in_list(param) elif (type(param) == MalList and param.opener == "{") or (type(param) == str): tmp = MalList("(") tmp.append("quote") tmp.append(param) return tmp elif type(param) == MalList and param.opener == "[": tmp = MalList("(") tmp.append("vec") tmp.append(in_list(param)) return tmp else: return param
def cons(first: MalExpression, rest: MalExpression) -> MalExpression: assert isinstance(rest, MalList) or isinstance(rest, MalVector) return MalList([first] + rest.native())