Commit | Line | Data |
---|---|---|
b0a9121d JM |
1 | import sys, traceback |
2 | import mal_readline | |
3 | import mal_types as types | |
4 | from mal_types import (MalSym, MalInt, MalStr, nil, true, false, | |
5 | _symbol, _keywordu, MalList, _list, MalFunc) | |
6 | import reader, printer | |
7 | from env import Env | |
8 | import core | |
9 | ||
10 | # read | |
11 | def READ(str): | |
12 | return reader.read_str(str) | |
13 | ||
14 | # eval | |
15 | def eval_ast(ast, env): | |
16 | if types._symbol_Q(ast): | |
17 | assert isinstance(ast, MalSym) | |
18 | return env.get(ast) | |
19 | elif types._list_Q(ast): | |
20 | res = [] | |
21 | for a in ast.values: | |
22 | res.append(EVAL(a, env)) | |
23 | return MalList(res) | |
24 | ## elif types._vector_Q(ast): | |
25 | ## return types._vector(*map(lambda a: EVAL(a, env), ast)) | |
26 | ## elif types._hash_map_Q(ast): | |
27 | ## keyvals = [] | |
28 | ## for k in ast.keys(): | |
29 | ## keyvals.append(EVAL(k, env)) | |
30 | ## keyvals.append(EVAL(ast[k], env)) | |
31 | ## return types._hash_map(*keyvals) | |
32 | else: | |
33 | return ast # primitive value, return unchanged | |
34 | ||
35 | def EVAL(ast, env): | |
36 | #print("EVAL %s" % printer._pr_str(ast)) | |
37 | if not types._list_Q(ast): | |
38 | return eval_ast(ast, env) | |
39 | ||
40 | # apply list | |
41 | if len(ast) == 0: return ast | |
42 | a0 = ast[0] | |
43 | if isinstance(a0, MalSym): | |
44 | a0sym = a0.value | |
45 | else: | |
46 | a0sym = u"__<*fn*>__" | |
47 | ||
48 | if u"def!" == a0sym: | |
49 | a1, a2 = ast[1], ast[2] | |
50 | res = EVAL(a2, env) | |
51 | return env.set(a1, res) | |
52 | elif u"let*" == a0sym: | |
53 | a1, a2 = ast[1], ast[2] | |
54 | let_env = Env(env) | |
55 | for i in range(0, len(a1), 2): | |
56 | let_env.set(a1[i], EVAL(a1[i+1], let_env)) | |
57 | return EVAL(a2, let_env) | |
58 | elif u"do" == a0sym: | |
59 | el = eval_ast(ast.rest(), env) | |
60 | return el.values[-1] | |
61 | elif u"if" == a0sym: | |
62 | a1, a2 = ast[1], ast[2] | |
63 | cond = EVAL(a1, env) | |
64 | if cond is nil or cond is false: | |
65 | if len(ast) > 3: return EVAL(ast[3], env) | |
66 | else: return nil | |
67 | else: | |
68 | return EVAL(a2, env) | |
69 | elif u"fn*" == a0sym: | |
70 | a1, a2 = ast[1], ast[2] | |
71 | return MalFunc(None, a2, env, a1, EVAL) | |
72 | else: | |
73 | el = eval_ast(ast, env) | |
74 | f = el.values[0] | |
75 | if isinstance(f, MalFunc): | |
76 | return f.apply(el.rest()) | |
77 | else: | |
78 | raise Exception("%s is not callable" % f) | |
79 | ||
80 | ||
81 | def PRINT(exp): | |
82 | return printer._pr_str(exp) | |
83 | ||
84 | # repl | |
85 | def entry_point(argv): | |
86 | repl_env = Env() | |
87 | def REP(str, env): | |
88 | return PRINT(EVAL(READ(str), env)) | |
89 | ||
90 | # core.py: defined using python | |
91 | for k, v in core.ns.items(): | |
92 | repl_env.set(_symbol(unicode(k)), MalFunc(v)) | |
93 | ||
94 | # core.mal: defined using the language itself | |
95 | REP("(def! not (fn* (a) (if a false true)))", repl_env) | |
96 | ||
97 | while True: | |
98 | try: | |
99 | line = mal_readline.readline("user> ") | |
100 | if line == "": continue | |
101 | print(REP(line, repl_env)) | |
102 | except EOFError as e: | |
103 | break | |
104 | except Exception as e: | |
105 | print(e) | |
106 | #print("".join(traceback.format_exception(*sys.exc_info()))) | |
107 | return 0 | |
108 | ||
109 | # _____ Define and setup target ___ | |
110 | def target(*args): | |
111 | return entry_point | |
112 | ||
113 | # Just run entry_point if not RPython compilation | |
114 | import sys | |
115 | if not sys.argv[0].endswith('rpython'): | |
116 | entry_point(sys.argv) |