Commit | Line | Data |
---|---|---|
31690700 JM |
1 | import sys, traceback |
2 | import mal_readline | |
ea81a808 JM |
3 | import mal_types as types |
4 | import reader, printer | |
5 | from env import Env | |
6 | import core | |
31690700 JM |
7 | |
8 | # read | |
9 | def READ(str): | |
ea81a808 | 10 | return reader.read_str(str) |
31690700 JM |
11 | |
12 | # eval | |
13 | def eval_ast(ast, env): | |
ea81a808 | 14 | if types._symbol_Q(ast): |
31690700 | 15 | return env.get(ast) |
ea81a808 JM |
16 | elif types._list_Q(ast): |
17 | return types._list(*map(lambda a: EVAL(a, env), ast)) | |
18 | elif types._vector_Q(ast): | |
19 | return types._vector(*map(lambda a: EVAL(a, env), ast)) | |
20 | elif types._hash_map_Q(ast): | |
31690700 JM |
21 | keyvals = [] |
22 | for k in ast.keys(): | |
23 | keyvals.append(EVAL(k, env)) | |
24 | keyvals.append(EVAL(ast[k], env)) | |
ea81a808 | 25 | return types._hash_map(*keyvals) |
31690700 JM |
26 | else: |
27 | return ast # primitive value, return unchanged | |
28 | ||
29 | def EVAL(ast, env): | |
86b689f3 | 30 | #print("EVAL %s" % printer._pr_str(ast)) |
ea81a808 JM |
31 | if not types._list_Q(ast): |
32 | return eval_ast(ast, env) | |
31690700 | 33 | |
ea81a808 JM |
34 | # apply list |
35 | if len(ast) == 0: return ast | |
36 | a0 = ast[0] | |
31690700 | 37 | |
ea81a808 JM |
38 | if "def!" == a0: |
39 | a1, a2 = ast[1], ast[2] | |
40 | res = EVAL(a2, env) | |
41 | return env.set(a1, res) | |
42 | elif "let*" == a0: | |
43 | a1, a2 = ast[1], ast[2] | |
44 | let_env = Env(env) | |
45 | for i in range(0, len(a1), 2): | |
46 | let_env.set(a1[i], EVAL(a1[i+1], let_env)) | |
47 | return EVAL(a2, let_env) | |
48 | elif "do" == a0: | |
49 | el = eval_ast(ast[1:], env) | |
50 | return el[-1] | |
51 | elif "if" == a0: | |
52 | a1, a2 = ast[1], ast[2] | |
53 | cond = EVAL(a1, env) | |
54 | if cond is None or cond is False: | |
55 | if len(ast) > 3: return EVAL(ast[3], env) | |
56 | else: return None | |
57 | else: | |
58 | return EVAL(a2, env) | |
59 | elif "fn*" == a0: | |
60 | a1, a2 = ast[1], ast[2] | |
61 | return types._function(EVAL, Env, a2, env, a1) | |
31690700 | 62 | else: |
ea81a808 JM |
63 | el = eval_ast(ast, env) |
64 | f = el[0] | |
65 | return f(*el[1:]) | |
31690700 JM |
66 | |
67 | ||
68 | def PRINT(exp): | |
ea81a808 | 69 | return printer._pr_str(exp) |
31690700 JM |
70 | |
71 | # repl | |
72 | repl_env = Env() | |
73 | def REP(str): | |
74 | return PRINT(EVAL(READ(str), repl_env)) | |
31690700 | 75 | |
8cb5cda4 | 76 | # core.py: defined using python |
b8ee29b2 | 77 | for k, v in core.ns.items(): repl_env.set(types._symbol(k), v) |
31690700 | 78 | |
8cb5cda4 | 79 | # core.mal: defined using the language itself |
31690700 JM |
80 | REP("(def! not (fn* (a) (if a false true)))") |
81 | ||
86b689f3 | 82 | # repl loop |
31690700 JM |
83 | while True: |
84 | try: | |
85 | line = mal_readline.readline("user> ") | |
86 | if line == None: break | |
87 | if line == "": continue | |
88 | print(REP(line)) | |
ea81a808 | 89 | except reader.Blank: continue |
31690700 | 90 | except Exception as e: |
a05f7822 | 91 | print("".join(traceback.format_exception(*sys.exc_info()))) |