def EVAL(expr: types.LispType, env: Environment) -> types.LispType: while True: if not types.is_list(expr): return eval_ast(expr, env) if len(expr) == 0: return expr if types.is_list(expr): if expr[0] == 'def!': ele1, ele2 = expr[1], expr[2] value = env.set(types.Symbol(ele1), EVAL(ele2, env)) return value elif expr[0] == 'let*': new_env = Environment(env) ele1 = expr[1] keys = ele1[::2] values = ele1[1::2] for k, v in zip(keys, values): new_env.set(types.Symbol(k), EVAL(v, new_env)) env = new_env expr = expr[2] continue elif expr[0] == 'do': for e in expr[1:-1]: EVAL(e, env) expr = expr[-1] continue elif expr[0] == 'if': cond = EVAL(expr[1], env) if cond: expr = expr[2] elif not cond and len(expr) == 4: expr = expr[3] else: expr = None continue elif expr[0] == 'fn*': closure = types.Closure( expr[1], expr[2], env, EVAL ) return closure else: fun, *args = eval_ast(expr, env) return fun(*args)
def read_form(reader: Reader) -> types.LispType: token = reader.peek() if token == '(': return read_list(reader) elif token == '[': return read_list(reader, stop=']', seq=types.make_vector) elif token == '{': return read_list(reader, stop='}', seq=types.make_hash_map) elif token == '\'': reader.next() return types.make_list([types.Symbol('quote'), read_form(reader)]) elif token == '`': reader.next() return types.make_list([types.Symbol('quasiquote'), read_form(reader)]) elif token == '~': reader.next() return types.make_list([types.Symbol('unquote'), read_form(reader)]) elif token == '~@': reader.next() return types.make_list( [types.Symbol('splice-unquote'), read_form(reader)]) elif token == '@': reader.next() return types.make_list([types.Symbol('deref'), read_form(reader)]) elif token == '^': reader.next() meta = read_form(reader) return types.make_list( [types.Symbol('with-meta'), read_form(reader), meta]) else: return read_atom(reader)
def read_atom(reader: Reader) -> types.LispType: token = reader.next() if re.match(r'^[-+]?\d+$', token): return int(token) elif re.match(r'^"(?:[\\].|[^\\"])*"$', token): return escape(token[1:-1]) elif token[0] == '"': raise types.LispException('unbalanced \'"\'') elif token[0] == ':': return types.KeyWord(token[1:]) elif token == 'nil': return None elif token == 'true': return True elif token == 'false': return False else: return types.Symbol(token)
continue elif expr[0] == 'fn*': closure = types.Closure( expr[1], expr[2], env, EVAL ) return closure else: fun, *args = eval_ast(expr, env) return fun(*args) def PRINT(expr: types.LispType) -> str: return printer.print_string(expr) def REP(expr: str) -> str: return PRINT(EVAL(READ(expr), repl_env)) repl_env.set(types.Symbol('eval'), lambda a: EVAL(a, repl_env)) repl_env.set(types.Symbol('*ARGV*'), types.List(sys.argv[1:])) REP("(def! not (fn* (a) (if a false true)))") REP('(def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) "\nnil)")))))') #REP('(def! a (slurp "../tests/incA.mal"))') if __name__ == '__main__': while True: try: print(REP(input('user> '))) except Exception as exception: print(exception)
def cons(item, lst): return types.List([item] + lst) def concat(*lsts): n_lst = [] for lst in lsts: n_lst.extend(lst) return types.List(n_lst) repl_env = types.Environment(None) repl_env.set(types.Symbol('+'), lambda a, b: a + b) repl_env.set(types.Symbol('-'), lambda a, b: a - b) repl_env.set(types.Symbol('*'), lambda a, b: a * b) repl_env.set(types.Symbol('/'), lambda a, b: a // b) repl_env.set(types.Symbol('list'), lambda *a: types.List(a)) repl_env.set(types.Symbol('vector'), lambda *a: types.Vector(a)) repl_env.set(types.Symbol('list?'), types.is_list) repl_env.set(types.Symbol('vector?'), types.is_vector) repl_env.set(types.Symbol('empty?'), lambda a: len(a) == 0) repl_env.set(types.Symbol('count'), lambda a: len(a)) repl_env.set(types.Symbol('='), lambda a, b: a == b) repl_env.set(types.Symbol('>'), lambda a, b: a > b) repl_env.set(types.Symbol('>='), lambda a, b: a >= b) repl_env.set(types.Symbol('<'), lambda a, b: a < b) repl_env.set(types.Symbol('<='), lambda a, b: a <= b) repl_env.set(types.Symbol('pr-str'), pr_str)