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