def _mal(d): if isinstance(d, bool) and d == True: return _MalData("TRUE") elif isinstance(d, bool) and d == False: return _MalData("FALSE") elif isinstance(d, int): return _MalData("INT", d)
def EVAL(ast, env): while True: if ast.type != "LIST": return eval_ast(ast, env) if len(ast.val) == 0: return ast ast0 = ast.val[0] # def! if ast0.val == "def!": key = ast.val[1].val v = EVAL(ast.val[2], env) env.set(key, v) return v # let* elif ast0.val == "let*": a1, a2 = ast.val[1], ast.val[2] let_env = Env(env) for i in range(0, len(a1), 2): let_env.set(a1[i], EVAL(a1[i + 1], let_env)) ast = a2 env = let_env # do elif ast0.val == "do": eval_ast(_MalData("LIST", ast.val[1:-1]), env) ast = ast.val[-1] # if elif ast0.val == "if": b = EVAL(ast.val[1], env) if b.type != "NIL" and b.type != "FALSE": ast = ast.val[2] else: if len(ast.val) <= 3: ast = None ast = ast.val[3] # fn* elif ast0.val == "fn*": params = [p.val for p in ast.val[1].val] expr_ast = ast.val[2] def fn(*args): pass #new_env = Env(env, params, args) #return EVAL(expr_ast, new_env) fn.__ast__ = expr_ast fn.__gen_env__ = lambda args: Env(env, params, args) return _MalData("FUNCTION", fn) # apply else: new_ast = eval_ast(ast, env) l = new_ast.val f, args = l[0].val, l[1:] if hasattr(f, '__ast__'): ast = f.__ast__ env = f.__gen_env__(args) else: return f(*args)
def EVAL(ast, env): if ast.type != "LIST": return eval_ast(ast, env) elif len(ast.val) == 0: return ast ast0 = ast.val[0] # def! if ast0.val == "def!": key = ast.val[1].val v = EVAL(ast.val[2], env) env.set(key, v) return v # let* elif ast0.val == "let*": let_env = Env(env) bidings = ast.val[1] for a, b in zip(bidings.val[0::2], bidings.val[1::2]): key = a.val v = EVAL(b, let_env) let_env.set(key, v) return EVAL(ast.val[2], let_env) # do elif ast0.val == "do": new_ast = eval_ast(_MalData("LIST", ast.val[1:]), env) return new_ast.val[-1] # if elif ast0.val == "if": b = EVAL(ast.val[1], env) if b.type != "NIL" and b.type != "FALSE": return EVAL(ast.val[2], env) else: if len(ast.val) <= 3: return _MalData("NIL") return EVAL(ast.val[3], env) # fn* elif ast0.val == "fn*": params = [p.val for p in ast.val[1].val] expr_ast = ast.val[2] def fn(*args): new_env = Env(env, params, args) return EVAL(expr_ast, new_env) return _MalData("FUNCTION", fn) # apply else: new_ast = eval_ast(ast, env) l = new_ast.val f, args = l[0].val, l[1:] return f(*args)
def println(*args): ret = [] for ast in args: ret.append(printer.pr_str(ast, False)) txt = " ".join(ret) print(txt) return _MalData("NIL")
def EVAL(ast, env): if ast.type == "LIST": l = ast.val if len(l) == 0: return ast else: ast0 = ast.val[0] if ast0.type == "SYMBOL" and ast0.val == "def!": key = ast.val[1].val v = EVAL(ast.val[2], env) env.set(key, v) return v elif ast0.type == "SYMBOL" and ast0.val == "let*": let_env = Env(env) bidings = ast.val[1] assert bidings.type == "LIST" for a, b in zip(bidings.val[0::2], bidings.val[1::2]): key = a.val v = EVAL(b, let_env) let_env.set(key, v) return EVAL(ast.val[2], let_env) else: new_ast = eval_ast(ast, env) l = new_ast.val f, args = l[0], l[1:] res = f(*[x.val for x in args]) # apply return _MalData("INT", res) else: return eval_ast(ast, env)
def __init__(self, outer=None, binds=None, exprs=None): self.data = {} self.outer = outer if binds: for i in range(len(binds)): if binds[i] == "&": self.data[binds[i + 1]] = _MalData("LIST", exprs[i:]) break else: self.data[binds[i]] = exprs[i]
def eval_ast(ast, env): if ast.type == "SYMBOL": key = ast.val if env.find(key) is None: raise Exception('no key for env:', key) f = env.get(key) return f elif ast.type == "LIST": data = tuple([EVAL(x, env) for x in ast.val]) return _MalData("LIST", data) else: return ast
def eval_ast(ast, env): if ast.type == "SYMBOL": key = ast.val if not key in env: raise Exception('no key for env:', key) f = env[key] print('fff', f) return f elif ast.type == "LIST": data = tuple([EVAL(x, env) for x in ast.val]) return _MalData("LIST", data) else: return ast
def quasiquote(ast): if not is_pair(ast): _v = (_MalData("SYMBOLE", "quote"), ast) return _MalData("LIST", _v) elif ast.val[0].val == 'unquote': return ast.val[1] elif is_pair(ast.val[0]) and ast.val[0].val[0].val == 'splice-unquote': _v = (_MalData("SYMBOL", "concat"), ast.val[0].val[1], quasiquote(_MalData("LIST", ast.val[1:]))) return _MalData("LIST", _v) else: _v = (_MalData("SYMBOL", "cons"), quasiquote(ast.val[0]), quasiquote(_MalData("LIST", ast.val[1:]))) return _MalData("LIST", _v)
def EVAL(ast, env): if ast.type != "LIST": return eval_ast(ast, env) elif len(ast.val) == 0: return ast type0 = ast.val[0].type if type0 == "def!": pass else: new_ast = eval_ast(ast, env) l = new_ast.val f, args = l[0], l[1:] res = f(*[x.val for x in args]) # apply return _MalData("INT", res)
def _atom(atom): return _MalData("ATOM", atom)
def first(lst): if lst.val == None or len(lst.val) == 0 or lst.val[0].type == "NIL": return _MalData("NIL") return lst.val[0]
def _list(*args): return _MalData("LIST", args)
def _is_atom(atom): if atom.type == "ATOM": return _MalData("TRUE") return _MalData("FALSE")
def _slurp(node): path = node.val with open(path) as f: s = f.read() return _MalData("STRING", s)
def _concat(*args): ret = [] for a in args: for _a in a.val: ret.append(_a) return _MalData("LIST", tuple(ret))
def is_nil(arg): if arg.type == "NIL": return _MalData("TRUE")
def rest(lst): if lst.val is None: return _MalData("LIST", ()) return _MalData("LIST", lst.val[1:])
def EVAL(ast, env): while True: if ast.type != "LIST": return eval_ast(ast, env) ast = macroexpand(ast, env) if ast.type != "LIST": return eval_ast(ast, env) if len(ast.val) == 0: return ast ast0 = ast.val[0] # def! if ast0.val == "def!": key = ast.val[1].val v = EVAL(ast.val[2], env) env.set(key, v) return v # macro elif ast0.val == "defmacro!": key = ast.val[1].val new_ast = ast.val[2] v = EVAL(new_ast, env) v.is_macro = True env.set(key, v) return v elif ast0.val == "macroexpand": return macroexpand(ast.val[1], env) elif ast0.val == "try*": if len(ast.val) < 3: return EVAL(ast[1], env) a1, a2 = ast.val[1], ast.val[2] if a2.val[0].val == "catch*": err = None try: return EVAL(a1, env) except MalException as exc: err = exc.object except Exception as exc: #msg = "'" + exc.args[1] + "'" + " not found" err = _MalData("STRING", exc.args[0]) catch_env = Env(env, [a2.val[1].val], [err]) return EVAL(a2.val[2], catch_env) else: return EVAL(a1, env) # let* elif ast0.val == "let*": a1, a2 = ast.val[1], ast.val[2] let_env = Env(env) for i in range(0, len(a1.val), 2): let_env.set(a1.val[i].val, EVAL(a1.val[i + 1], let_env)) ast = a2 env = let_env # do elif ast0.val == "do": eval_ast(_MalData("LIST", ast.val[1:-1]), env) ast = ast.val[-1] # if elif ast0.val == "if": b = EVAL(ast.val[1], env) if b.type != "NIL" and b.type != "FALSE": ast = ast.val[2] else: if len(ast.val) <= 3: ast = None ast = ast.val[3] # fn* elif ast0.val == "fn*": params = [p.val for p in ast.val[1].val] expr_ast = ast.val[2] def fn(*args): new_env = Env(env, params, args) return EVAL(expr_ast, new_env) fn.__ast__ = expr_ast fn.__gen_env__ = lambda args: Env(env, params, args) return _MalData("FUNCTION", fn) # quote elif ast0.val == "quote": return ast.val[1] elif ast0.val == "quasiquote": ast = quasiquote(ast.val[1]) # apply else: new_ast = eval_ast(ast, env) l = new_ast.val f, args = l[0].val, l[1:] if hasattr(f, '__ast__'): ast = f.__ast__ env = f.__gen_env__(args) else: return f(*args)
def is_symbol(arg): if arg.type == "SYMBOL": return _MalData("TRUE")
def is_false(arg): if arg.type == "FALSE": return _MalData("TRUE")
def is_true(arg): if arg.type == "TRUE": return _MalData("TRUE")
repl_env.set(key, val) repl_env.set('eval', core._F(lambda ast: EVAL(ast, repl_env))) rep("(def! not (fn* (a) (if a false true)))", out_print=False) rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))", out_print=False) #macro 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)))))))", out_print=False) rep("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))", out_print=False) if __name__ == '__main__': _args = sys.argv[2:] repl_env.set('*ARGV*', _MalData('LIST', list(_args))) #rep("(def! not (fn* (a) (if a false true)))") if len(sys.argv) >= 2: path = sys.argv[1] rep('(load-file "' + path + '")') sys.exit(0) while True: try: x = input('user> ') rep(x, repl_env) except Exception as e: print("".join(traceback.format_exception(*sys.exc_info()))) except KeyboardInterrupt:
def _str(*args): ret = [] for ast in args: ret.append(printer.pr_str(ast, False)) return _MalData("STRING", "".join(ret))
def _P(f): def g(*args): return _mal(f(*[x.val for x in args])) return _MalData("FUNCTION", g)
def mapf(f, lst): ret = map(f.val, lst.val) return _MalData("LIST", ret)
def _F(f): return _MalData("FUNCTION", f)
def _cons(a1, a2): new_list = (a1, ) + a2.val return _MalData("LIST", new_list)