This repository has been archived by the owner on Jan 4, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patheval.py
172 lines (137 loc) · 4.46 KB
/
eval.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# Write this in pseudo-Lark. We have to take a different strategy from
# Arc because we're not on top of a Lisp or Scheme, so roots comes first
# instead of in arc.arc.
# XXX: ac-dbname and ac-nameit have been elided for now because I'm not sure
# how to translate them.
from roots import *
from sexpr import str2sexpr
from symbol import *
from larktypes import *
xcar = lambda x: car(x) if acons(x) else None
# Let's not let them poke at raw Python variables without explicitly
# exposing them.
def ac_global_name(s):
return Symbol('_' + str(s))
EXPOSED_FUNCTIONS = (car, cdr, caar, cadr, cdar, cddr, cons,
list, last, append, reverse, nconc, nconc1,
map)
arc_globals = dict((ac_global_name(Symbol(f.func_name)), f) for f in EXPOSED_FUNCTIONS)
arc_globals[ac_global_name(t)] = t
arc_globals[ac_global_name(Symbol('+'))] = lambda *args: sum(args)
class InterpretedFunction(object):
# Hacky, non-performant function class for interpreter.
# When we have a bytecode compiler, life will be better.
def __init__(self, TK):
pass
# Evaluate an Arc expression, represented as an s-expression.
# Env is a dictionary of lexically-bound variables (symbol->value).
# Arc just has a list because Scheme actually keeps track of the variables and
# values, but in Lark we keep track of them ourselves.
def ac_eval(s, env):
print 'DEBUG: eval %s in %s' % (s, env)
if isinstance(s, String):
return s
elif literal(s):
return s
elif s is nil:
return s
elif isSymbol(s):
print 'DEBUG: var ref'
return ac_var_ref(s, env)
elif xcar(s) == Symbol('quote'):
return cadr(s)
elif xcar(s) == Symbol('if'):
return ac_if(cdr(s), env)
elif xcar(s) == Symbol('fn'):
return ac_fn(cadr(s), cddr(s), env)
elif xcar(s) == Symbol('assign'):
return ac_set(cdr(s), env)
elif acons(s):
print 'DEBUG: funcall'
return ac_call(car(s), cdr(s), env)
else:
raise Exception('Bad object in expression %s (type %s)' % (s, type(s)))
def literal(x):
return isinstance(x, bool) or isinstance(x, int) or isinstance(x, float)
def ac_var_ref(s, env):
assert isSymbol(s)
print 'DEBUG: Referencing %s (type %s) in env with keys' % (s, type(s)),
for key in env:
print key, type(key)
if s in env:
return env[s]
glo = arc_globals[ac_global_name(s)]
print 'DEBUG: returning global %s' % glo
return glo
# Should False Python objects be false eventually?
# We're not even close to exposing Python right now, I think.
def ar_false(x):
return x is nil or x == False
def ac_if(s, env):
while s is not nil:
if cdr(s) is nil:
return ac_eval(car(s), env)
elif not ar_false(ac_eval(car(s), env)):
return ac_eval(cadr(s), env)
s = cddr(s)
return nil
def ac_fn(args, body, env):
if ac_complex_args(args):
raise NotImplementedError()
elif body is nil: # My extension to deal with empty body. No ac-body*.
return lambda *args: nil
else:
env = env.copy() # Not sure if this is necessary. Being paranoid.
print 'DEBUG: define function with argslist %s' % args
assert isSymbol(xcar(args))
def temp(*fargs):
env.update(zip(args, fargs))
return ac_body(body, env)
return temp
def ac_body(body, env):
if body is nil:
return nil
return car(revmap(lambda x: ac_eval(x, env), body))
# Elided ac_setn; it's ac_set.
def ac_set(x, env):
if x is nil:
return nil
return cons(ac_set1(ac_macex(car(x)), cadr(x), env),
ac_set(cddr(x), env))
def ac_set1(a, b1, env):
# Omitting dbname because it's done in ac_fn too.
if isSymbol(a):
b = ac_eval(b1, env)
if a is nil:
raise Exception('Can\'t rebind nil')
elif a is t:
raise Exception('Can\'t rebind t')
elif a in env:
env[a] = b
else:
arc_globals[ac_global_name(a)] = b
else:
raise Exception('First arg to set must be a symbol! (Given %s)' % a)
def ac_macex(x):
# STUB. TODO.
if isSymbol(x):
return x
else:
raise NotImplementedError()
def ac_complex_args(args):
'''Does a fn arg list use optional params or destructuring?'''
if args is nil or isSymbol(args):
return False
elif acons(args) and isSymbol(car(args)):
return ac_complex_args(cdr(args))
else:
return True
def ac_call(fn, args, env):
return ac_eval(fn, env)(*topylist(map(lambda x: ac_eval(x, env), args)))
def tle():
while True:
print 'Lark> ',
expr = str2sexpr(raw_input())[0]
print ac_eval(expr, {})
if __name__ == '__main__':
tle()