def lisp_plus(args, env):
return plus_rec(args, env, make_int(0))
+def lisp_minus(args, env):
+ args = eval_list(args, env)
+ e1 = car(args)
+ e2 = cadr(args)
+ assert(e1.t == "int" and e2.t == "int")
+ return make_int(e1.v - e2.v)
+
+def times_rec(args, env, result):
+ if is_nil(args): return result
+ else:
+ result.v *= lisp_eval(car(args), env).v
+ return times_rec(cdr(args), env, result)
+
+def lisp_times(args, env):
+ return times_rec(args, env, make_int(1))
+
+def lisp_div(args, env):
+ args = eval_list(args, env)
+ e1 = car(args)
+ e2 = cadr(args)
+ assert(e1.t == "int" and e2.t == "int")
+ return make_int(e1.v / e2.v)
+
+def lisp_mod(args, env):
+ args = eval_list(args, env)
+ e1 = car(args)
+ e2 = cadr(args)
+ assert(e1.t == "int" and e2.t == "int")
+ return make_int(e1.v % e2.v)
def lisp_display(args, env):
args = eval_list(args, env)
global_env = Environment()
-
+# inline apply into eval, to convert last call to eval in apply into a loop
+# in order to optimize tail calls
def lisp_eval(e, env):
"""evals an expression"""
- result = e
- if is_symbol(e):
- result = env[e.v]
- elif is_pair(e):
- f = lisp_eval(car(e), env)
- args = cdr(e)
- if should_eval_arguments(f):
- args = eval_list(args, env)
- result = lisp_apply(f, args, env)
- #print "evaluating %s\nresult: %s"%(e, result)
+ ended = False
+ while not ended:
+ #print "eval: %s"%str(e)
+ if is_symbol(e):
+ result = env[e.v]
+ ended = True
+ elif is_pair(e):
+ f = lisp_eval(car(e), env)
+ args = cdr(e)
+ # inlined body of the apply function
+ if should_eval_arguments(f):
+ args = eval_list(args, env)
+ if type(f) == types.FunctionType:
+ # TEST: special case for cond, the old lisp_cond function is only used as a marker, but evaluated inline
+ if f == lisp_cond:
+ action = None
+ while not is_nil(args):
+ c = car(args)
+ assert(is_pair(c))
+ if is_true(lisp_eval(car(c), env)):
+ action = cadr(c)
+ break
+ args = cdr(args)
+ if action is not None:
+ e = action
+ else:
+ result = Value.NIL
+ ended = True
+ else:
+ result = f(args, env)
+ ended = True
+ elif f.t == "macro":
+ expansion = lisp_apply(f.v, args, env)
+ #print "macro expansion:", expansion
+ e = expansion
+ else:
+ formals, body, environment = f.v
+ new_env = Environment(environment)
+ #insert parameters into the environment
+ while not is_nil(formals):
+ name = car(formals)
+ formals = cdr(formals)
+ if not is_nil(args):
+ arg = car(args)
+ args = cdr(args)
+ else:
+ arg = Value.NIL
+
+ new_env[name.v] = arg
+
+ e = body
+ env = new_env
+ else:
+ result = e
+ ended = True
+
return result
def lisp_apply(f, args, env):
global_env["list"] = lisp_list
global_env["="] = lisp_equal
global_env["+"] = lisp_plus
+global_env["-"] = lisp_minus
+global_env["*"] = lisp_times
+global_env["/"] = lisp_div
+global_env["%"] = lisp_mod
global_env["nil"] = Value.NIL