def rep(line): try: print(pr_str(eval(read_str(line), repl_env))) except Exception as e: if isinstance(e.args[0], Val): print(pr_str(Val("error", e.args[0]))) else: print(pr_str(Val("error", Val("string", str(e)))))
def eval(ast, env): if ast.type != "list": return eval_ast(ast, env) if len(ast.value) == 0: return ast symbol = ast.value[0].value if symbol == "def!": evaluated = eval(ast.value[2], env) env.set(ast.value[1].value, evaluated) return evaluated if symbol == "let*": new_env = Env(env) params = ast.value[1].value i = 0 while i < len(params): new_env.set(params[i].value, eval(params[i + 1], new_env)) i += 2 return eval(ast.value[2], new_env) if symbol == "do": evaluated = None for i in ast.value[1:]: evaluated = eval(i, env) return evaluated if symbol == "if": evaluated = None cond = eval(ast.value[1], env) if cond.type != "nil" and (cond.type != "bool" or cond.value == True): return eval(ast.value[2], env) if len(ast.value) > 3: return eval(ast.value[3], env) return Val("nil", []) if symbol == "fn*": def func(*exprs_t): new_env = Env(env) params = ast.value[1].value exprs = list(exprs_t) i = 0 while i < len(params): if params[i].value == "&": new_env.set(params[i + 1].value, Val("list", exprs[i:])) break new_env.set(params[i].value, exprs[i]) i += 1 return eval(ast.value[2], new_env) return Val("fn", func) new_ast = eval_ast(ast, env) fn = new_ast.value[0] return fn.value(*new_ast.value[1:])
def rep(line): if len(line) == 0 or line[0] == ";": return try: return pr_str(eval(read_str(line), repl_env)) except Exception as e: if isinstance(e.args[0], Val): return pr_str(Val("error", e.args[0])) else: return pr_str(Val("error", Val("string", str(e))))
def seq(col): if len(col.value) == 0: return Val("nil", []) if col.type in ('vector', 'list'): return Val("list", col.value) res = [] for i in col.value: res.append(Val("string", i)) return Val("list", res)
def eval_ast(ast, env): if ast.type == "symbol": return env.get(ast.value) if ast.type in ("list", "vector"): items = map(lambda ast: eval(ast, env), ast.value) return Val(ast.type, items) if ast.type == "hashmap": new_val = {} for key, value in ast.value.items(): new_val[key] = eval(value, env) return Val("hashmap", new_val) return ast
def conj(col, *args): if (col.type == "vector"): res = [] for i in col.value: res.append(i) for i in list(args): res.append(i) return Val("vector", res) res = [] for i in col.value: res.append(i) for i in list(args): res.insert(0, i) return Val("list", res)
def dissoc(d, *args): keys_to_remove = map(lambda a: a.value, args) res = {} for key in d.value: if key not in keys_to_remove: res[key] = d.value[key] return Val("hashmap", res)
def hashmap(*args): arg_list = list(args) i = 0 res = {} while i < len(arg_list): res[args[i].value] = args[i + 1] i += 2 return Val("hashmap", res)
def map_fn(fn, col): res = [] for i in col.value: if fn.type == 'fn': res.append(*fn.value(i)) else: res.append(fn.value["fn"](i)) return Val("list", res)
def assoc(d, *args): res = {} for key in d.value: res[key] = d.value[key] arg_list = list(args) i = 0 while i < len(arg_list): res[arg_list[i].value] = arg_list[i + 1] i += 2 return Val("hashmap", res)
def func(*exprs_t): new_env = Env(env) params = ast.value[1].value exprs = list(exprs_t) i = 0 while i < len(params): if params[i].value == "&": new_env.set(params[i + 1].value, Val("list", exprs[i:])) break new_env.set(params[i].value, exprs[i]) i += 1 return eval(ast.value[2], new_env)
def quasiquote(ast): if not is_pair(ast): return Val("list", [Val("symbol", "quote"), ast]) if ast.value[0].value == "unquote": return ast.value[1] if is_pair( ast.value[0]) and ast.value[0].value[0].value == "splice-unquote": return Val("list", [ Val("symbol", "concat"), ast.value[0].value[1], quasiquote(Val("list", ast.value[1:])) ]) return Val("list", [ Val("symbol", "cons"), quasiquote(ast.value[0]), quasiquote(Val("list", ast.value[1:])) ])
def equal_fn(a, b): if a.type in ("vector", "list") and b.type in ("vector", "list"): if len(a.value) != len(b.value): return False for i, v in enumerate(a.value): if not equal_fn(v, b.value[i]): return False return True if a.type != b.type: return False if a.type == "hashmap": if len(a.value) != len(b.value): return False for key in a.value: if not equal_fn(a.value[key], b.value[key]): return False return True return a.value == b.value return Val("list", list(args))
def concat(*arg): result = [] for l in list(arg): result += l.value return Val("list", result)
def slurp(arg): content = "" with open(arg.value, "r") as f: content = f.read() return Val("string", content)
def list_fn(*args): return Val("list", list(args))
def prn(*args): print(" ".join(map(lambda a: pr_str(a, True), list(args)))) return Val("nil", [])
def seq(col): if len(col.value) == 0: return Val("nil", []) if col.type in ('vector', 'list'): return Val("list", col.value) res = [] for i in col.value: res.append(Val("string", i)) return Val("list", res) raw_ns = { "+": lambda a, b: Val("number", a.value + b.value), "-": lambda a, b: Val("number", a.value - b.value), "*": lambda a, b: Val("number", a.value * b.value), "/": lambda a, b: Val("number", a.value / b.value), "<": lambda a, b: Val("bool", a.value < b.value), "<=": lambda a, b: Val("bool", a.value <= b.value), ">=": lambda a, b: Val("bool", a.value >= b.value), ">": lambda a, b: Val("bool", a.value > b.value), "list":
def vector(*args): return Val("vector", list(args))
def with_meta(value, meta): return Val(value.type, value.value, meta)
import sys from reader import read_str, Val from printer import pr_str from env import Env from core import ns repl_env = Env() for key in ns: repl_env.set(key, ns[key]) repl_env.set("eval", Val("fn", lambda a: eval(a, repl_env))) def eval_ast(ast, env): if ast.type == "symbol": return env.get(ast.value) if ast.type in ("list", "vector"): items = map(lambda ast: eval(ast, env), ast.value) return Val(ast.type, items) if ast.type == "hashmap": new_val = {} for key, value in ast.value.items(): new_val[key] = eval(value, env) return Val("hashmap", new_val) return ast def is_pair(ast): return ast.type in ("list", "vector") and len(ast.value) > 0 def quasiquote(ast):
#!/usr/bin/python3 # -*- coding: utf-8 -*- import sys from reader import read_str, Val from printer import pr_str from env import Env from core import ns repl_env = Env() for key in ns: repl_env.set(key, ns[key]) repl_env.set("eval", Val("fn", lambda a: eval(a, repl_env))) repl_env.set("*host-language*", Val("string", "Python")) def eval_ast(ast, env): if ast.type == "symbol": return env.get(ast.value) if ast.type in ("list", "vector"): items = map(lambda ast: eval(ast, env), ast.value) return Val(ast.type, items) if ast.type == "hashmap": new_val = {} for key, value in ast.value.items(): new_val[key] = eval(value, env) return Val("hashmap", new_val) return ast def is_pair(ast):
def str_fn(*args): return Val("string", "".join(map(lambda a: pr_str(a, False), list(args))))
def eval(ast, env): while True: if ast.type != "list": return eval_ast(ast, env) if len(ast.value) == 0: return ast symbol = ast.value[0].value if symbol == "def!": evaluated = eval(ast.value[2], env) env.set(ast.value[1].value, evaluated) return evaluated if symbol == "let*": new_env = Env(env) params = ast.value[1].value i = 0 while i < len(params): new_env.set(params[i].value, eval(params[i + 1], new_env)) i += 2 ast = ast.value[2] env = new_env continue if symbol == "do": evaluated = None for i in ast.value[1:-1]: eval(i, env) ast = ast.value[len(ast.value) -1] continue if symbol == "if": evaluated = None cond = eval(ast.value[1], env) if cond.type != "nil" and (cond.type != "bool" or cond.value == True): ast = ast.value[2] elif len(ast.value) > 3: ast = ast.value[3] else: ast = Val("nil", []) continue if symbol == "fn*": def func(*exprs_t): new_env = Env(env) params = ast.value[1].value exprs = list(exprs_t) i = 0 while i < len(params): if params[i].value == "&": new_env.set(params[i + 1].value, Val("list", exprs[i:])) break new_env.set(params[i].value, exprs[i]) i += 1 return eval(ast.value[2], new_env) return Val("custom_fn", { "fn": func, "ast": ast.value[2], "params": ast.value[1].value, "env": env }) new_ast = eval_ast(ast, env) fn = new_ast.value[0] if fn.type == 'custom_fn': exprs = new_ast.value[1:] ast = fn.value["ast"] params = fn.value["params"] i = 0 new_env = Env(fn.value["env"]) while i < len(params): if params[i].value == "&": new_env.set(params[i + 1].value, Val("list", exprs[i:])) break new_env.set(params[i].value, exprs[i]) i += 1 env = new_env continue return fn.value(*new_ast.value[1:])
def println_fn(*args): print(" ".join(map(lambda a: pr_str(a, False), list(args)))) return Val("nil", [])
def get(self, key): if key in self.data: return self.data[key] if self.outer != None: return self.outer.get(key) raise Exception(Val("string", "'" + key + "' not found"))
def eval(ast, env): while True: ast = macroexpand(ast, env) if ast.type != "list": return eval_ast(ast, env) if len(ast.value) == 0: return ast symbol = ast.value[0].value if symbol == "try*": if (len(ast.value) <= 2): return eval(ast.value[1], env) try: return eval(ast.value[1], env) except Exception as e: error = Val("string", str(e)) if isinstance(e.args[0], Val): error = e.args[0] new_env = Env(env) new_env.set(ast.value[2].value[1].value, error) return eval(ast.value[2].value[2], new_env) if symbol == "macroexpand": return macroexpand(ast.value[1], env) if symbol == "quote": return ast.value[1] if symbol == "quasiquote": ast = quasiquote(ast.value[1]) continue if symbol == "def!": evaluated = eval(ast.value[2], env) env.set(ast.value[1].value, evaluated) return evaluated if symbol == "defmacro!": evaluated = Val("macro", eval(ast.value[2], env).value) env.set(ast.value[1].value, evaluated) return evaluated if symbol == "let*": new_env = Env(env) params = ast.value[1].value i = 0 while i < len(params): new_env.set(params[i].value, eval(params[i + 1], new_env)) i += 2 ast = ast.value[2] env = new_env continue if symbol == "do": for i in ast.value[1:-1]: eval(i, env) ast = ast.value[len(ast.value) - 1] continue if symbol == "if": cond = eval(ast.value[1], env) if cond.type != "nil" and (cond.type != "bool" or cond.value == True): ast = ast.value[2] elif len(ast.value) > 3: ast = ast.value[3] else: ast = Val("nil", []) continue if symbol == "fn*": def func(*exprs_t): new_env = Env(env) params = ast.value[1].value exprs = list(exprs_t) i = 0 while i < len(params): if params[i].value == "&": new_env.set(params[i + 1].value, Val("list", exprs[i:])) break new_env.set(params[i].value, exprs[i]) i += 1 return eval(ast.value[2], new_env) return Val( "custom_fn", { "fn": func, "ast": ast.value[2], "params": ast.value[1].value, "env": env, }) new_ast = eval_ast(ast, env) fn = new_ast.value[0] if fn.type == 'custom_fn': exprs = new_ast.value[1:] ast = fn.value["ast"] params = fn.value["params"] i = 0 new_env = Env(fn.value["env"]) while i < len(params): if params[i].value == "&": new_env.set(params[i + 1].value, Val("list", exprs[i:])) break new_env.set(params[i].value, exprs[i]) i += 1 env = new_env continue return fn.value(*new_ast.value[1:])