Skip to content
This repository was archived by the owner on Jan 4, 2025. It is now read-only.

Commit a6de4f1

Browse files
committed
enough of an evaluator to eval ((fn (a) a) 1)
1 parent e0ef639 commit a6de4f1

File tree

2 files changed

+110
-15
lines changed

2 files changed

+110
-15
lines changed

eval.py

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,62 @@
11
# Write this in pseudo-Lark. We have to take a different strategy from
2-
# Arc because we're not on top of a Lisp or Scheme, so roots comes first instead of in arc.arc.
2+
# Arc because we're not on top of a Lisp or Scheme, so roots comes first
3+
# instead of in arc.arc.
4+
5+
# XXX: ac-dbname and ac-nameit have been elided for now because I'm not sure
6+
# how to translate them.
7+
38
from roots import *
49
from sexpr import str2sexpr
510
from symbol import *
6-
from types import *
11+
from larktypes import *
712

813
xcar = lambda x: car(x) if acons(x) else None
914

1015
# Let's not let them poke at raw Python variables without explicitly
11-
# them.
16+
# exposing them.
17+
18+
def ac_global_name(s):
19+
return Symbol('_' + str(s))
20+
1221

13-
arc_globals = {nil: nil, ac_global_name(t): t}
22+
arc_globals = dict((ac_global_name(sym), value) for sym, value in [
23+
(t, t),
24+
(Symbol('car'), car)
25+
])
26+
27+
28+
class InterpretedFunction(object):
29+
# Hacky, non-performant function class for interpreter.
30+
# When we have a bytecode compiler, life will be better.
31+
def __init__(self, TK):
32+
pass
1433

1534
# Evaluate an Arc expression, represented as an s-expression.
1635
# Env is a dictionary of lexically-bound variables (symbol->value).
36+
# Arc just has a list because Scheme actually keeps track of the variables and
37+
# values, but in Lark we keep track of them ourselves.
1738
def ac_eval(s, env):
39+
print 'DEBUG: eval %s in %s' % (s, env)
1840
if isinstance(s, String):
1941
return s
2042
elif literal(s):
2143
return s
2244
elif s is nil:
2345
return s
2446
elif isSymbol(s):
47+
print 'DEBUG: var ref'
2548
return ac_var_ref(s, env)
2649
elif xcar(s) == Symbol('quote'):
2750
return cadr(s)
2851
elif xcar(s) == Symbol('if'):
2952
return ac_if(cdr(s), env)
30-
# elif xcar(s) == Symbol('fn'):
31-
# return ac_fn(cadr(s), cddr(s), env)
53+
elif xcar(s) == Symbol('fn'):
54+
return ac_fn(cadr(s), cddr(s), env)
3255
# elif xcar(s) == Symbol('assign'):
3356
# return ac_set(cdr(s), env)
34-
# elif acons(s):
35-
# return ac_call(car(s), cdr(s), env)
57+
elif acons(s):
58+
print 'DEBUG: funcall'
59+
return ac_call(car(s), cdr(s), env)
3660
else:
3761
raise Exception('Bad object in expression %s (type %s)' % (s, type(s)))
3862

@@ -41,11 +65,11 @@ def literal(x):
4165
return isinstance(x, bool) or isinstance(x, int) or isinstance(x, float)
4266

4367

44-
def ac_global_name(s):
45-
return Symbol('_' + str(s))
46-
47-
4868
def ac_var_ref(s, env):
69+
assert isSymbol(s)
70+
print 'Referencing %s (type %s) in with keys' % (s, type(s)),
71+
for key in env:
72+
print key, type(key)
4973
if s in env:
5074
return env[s]
5175
return arc_globals[ac_global_name(s)]
@@ -66,8 +90,47 @@ def ac_if(s, env):
6690

6791
return nil
6892

93+
def ac_fn(args, body, env):
94+
if ac_complex_args(args):
95+
raise NotImplementedError()
96+
elif body is nil: # My extension to deal with empty body. No ac-body*.
97+
return lambda *args: nil
98+
else:
99+
env = env.copy() # Not sure if this is necessary. Being paranoid.
100+
print 'DEBUG: define function with argslist %s' % args
101+
assert isSymbol(xcar(args))
102+
def temp(*fargs):
103+
env.update(zip(args, fargs))
104+
return ac_body(body, env)
105+
return temp
106+
107+
108+
def ac_body(body, env):
109+
if body is nil:
110+
return nil
111+
return car(revmap(lambda x: ac_eval(x, env), body))
112+
113+
114+
def ac_complex_args(args):
115+
'''Does a fn arg list use optional params or destructuring?'''
116+
if args is nil or isSymbol(args):
117+
return False
118+
elif acons(args) and isSymbol(car(args)):
119+
return ac_complex_args(cdr(args))
120+
else:
121+
return True
122+
123+
124+
def ac_call(fn, args, env):
125+
return ac_eval(fn, env)(*topylist(args))
126+
127+
69128
def tle():
70129
while True:
71130
print 'Lark> ',
72131
expr = str2sexpr(raw_input())[0]
73132
print ac_eval(expr, {})
133+
134+
135+
if __name__ == '__main__':
136+
tle()

roots.py

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@
2929
# - numbers as in Python
3030
# - symbols
3131

32-
def _topylist(L):
32+
def topylist(L):
3333
acc = []
3434
while L is not nil:
3535
acc.append(car(L))
3636
L = cdr(L)
3737
return acc
3838

39-
def _toarclist(L):
39+
def toarclist(L):
4040
res = nil
4141
for x in reversed(L):
4242
res = cons(x, res)
@@ -47,6 +47,22 @@ def last(x):
4747
x = cdr(x)
4848
return x
4949

50+
51+
def revappend(x, y):
52+
# if x is nil:
53+
# return y
54+
# return revappend(cdr(x), cons(car(x), y))
55+
while x is not nil:
56+
x = cdr(x)
57+
y = cons(car(x), y)
58+
return y
59+
60+
def reverse(x):
61+
return revappend(x, nil)
62+
63+
def append(x, y):
64+
return revappend(reverse(x), y)
65+
5066
def nconc(x, y):
5167
if x is nil:
5268
return y
@@ -59,4 +75,20 @@ def nconc1(x, y):
5975
return nconc(x, list(y))
6076

6177
def list(*args):
62-
return _toarclist(args)
78+
return toarclist(args)
79+
80+
def revmap(func, L):
81+
# def rec(func, L, acc):
82+
# if L is nil:
83+
# return acc
84+
# return rec(func, cdr(L), cons(func(car(L)), acc))
85+
# return rec(func, L, nil)
86+
acc = nil
87+
while L is not nil:
88+
acc = cons(func(car(L)), acc)
89+
L = cdr(L)
90+
return acc
91+
92+
def map(func, L):
93+
# TODO: nreverse.
94+
return reverse(revmap(func, L))

0 commit comments

Comments
 (0)