import types
import sys
+import operator
+import inspect
from functools import reduce
class Pair:
def make_function(params, body, env): return Value("function", [params, body, env])
def make_macro(f): return Value("macro", f)
def make_symbol(s): return Value("symbol", s)
+def make_boolean(b): return Value.TRUE if b else Value.FALSE
def cons(x,y): return Value("pair", Pair(x,y))
def flipcons(x,y): return cons(y,x)
def make_list(*args): return reduce(flipcons, reversed(args), Value.NIL)
if is_nil(l): return initial
else: return func(car(l), foldr(func, initial, cdr(l)))
-def reverse_list(l): return foldl(flipcons, Value.NIL, l)
-def map_list(func, l): return foldr(lambda x,y: cons(func(x), y), Value.NIL, l)
-def do_list(func, l): return foldl(lambda x,y: func(y), None, l)
-
-def eval_list(args, env):
- return map_list(lambda x: lisp_eval(x, env), args)
-
+def reverse_list(l): return foldl(flipcons, Value.NIL, l)
+def map_list(func, l): return foldr(lambda x,y: cons(func(x), y), Value.NIL, l)
+def do_list(func, l): return foldl(lambda x,y: func(y), None, l)
+def eval_list(args, env): return map_list(lambda x: lisp_eval(x, env), args)
+def list_length(l): return foldl(lambda x,y: x+1, 0, l)
# Built-in functions and special forms
# ------------------------------------
env[name.v] = lisp_eval(value, env)
return Value.NIL
-
def lisp_list(args, env):
return eval_list(args, env)
assert(is_nil(cdr(args)))
return car(args)
+def lisp_cond(args, env):
+ while not is_nil(args):
+ c = car(args)
+ assert(is_pair(c))
+ if is_true(lisp_eval(car(c), env)):
+ actions = cdr(c)
+ while not is_nil(actions):
+ result = lisp_eval(car(actions), env)
+ actions = cdr(actions)
+ return result
+ args = cdr(args)
+ return Value.NIL
+
+
def quasiquote_expression(expr, env):
"""returns a tuple with:
- the expression with unquotes recursively expanded as needed
return expr, "normal"
def lisp_quasiquote(args, env):
- assert(is_nil(cdr(args)))
+ assert(list_length(args) == 1)
e = car(args)
return quasiquote_expression(e, env)[0]
+##############################
+# functions exported to lisp #
+##############################
+
+# a decorator which checks the number of arguments, evals them,
+# and forwards them to a python function as positional arguments
+def lisp_function(f):
+ def result(args, env):
+ argspec = inspect.getargspec(f)
+ if (argspec.varargs is None):
+ expected_args = len(argspec.args)
+ given_args = list_length(args)
+ if (given_args != expected_args):
+ raise Exception("function %s takes %d arguments (%d given)"%(f.func_name, expected_args, given_args))
+ def eval_and_append(l, x):
+ l.append(lisp_eval(x, env))
+ return l
+ python_args = foldl(eval_and_append, [], args)
+ return f(*python_args)
+ return result
-def lisp_car(args, env):
- args = eval_list(args, env)
- assert(is_nil(cdr(args)))
- return car(car(args))
+@lisp_function
+def lisp_car(l): return car(l)
-def lisp_cdr(args, env):
- args = eval_list(args, env)
- assert(is_nil(cdr(args)))
- return cdr(car(args))
+@lisp_function
+def lisp_cdr(l): return cdr(l)
-def lisp_cons(args, env):
- args = eval_list(args, env)
- assert(is_nil(cddr(args)))
- return cons(car(args), cadr(args))
+@lisp_function
+def lisp_cons(a, b): return cons(a, b)
-
-def lisp_cond(args, env):
- while not is_nil(args):
- c = car(args)
- assert(is_pair(c))
- if is_true(lisp_eval(car(c), env)):
- actions = cdr(c)
- while not is_nil(actions):
- result = lisp_eval(car(actions), env)
- actions = cdr(actions)
- return result
- args = cdr(args)
- return Value.NIL
-
# defined only for atoms
-def lisp_equal(args, env):
- args = eval_list(args, env)
- e1 = car(args)
- e2 = cadr(args)
- result = (not is_pair(e1)) and e1.t == e2.t and e1.v == e2.v
- if result:
- return Value.TRUE
- else:
- return Value.FALSE
-
-
-def plus_rec(args, env, result):
- if is_nil(args): return result
- else:
- result.v += lisp_eval(car(args), env).v
- return plus_rec(cdr(args), env, result)
-
-def lisp_plus(args, env):
- return plus_rec(args, env, make_int(0))
+@lisp_function
+def lisp_equal(e1, e2): return make_boolean((not is_pair(e1)) and e1.t == e2.t and e1.v == e2.v)
-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)
+@lisp_function
+def lisp_plus(*args): return make_int(sum((i.v for i in args)))
-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)
+@lisp_function
+def lisp_minus(e1, e2): return make_int(e1.v - e2.v)
-def lisp_times(args, env):
- return times_rec(args, env, make_int(1))
+@lisp_function
+def lisp_times(*args): return make_int(reduce(operator.mul, (i.v for i in args), 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)
+@lisp_function
+def lisp_div(e1, e2): 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)
+@lisp_function
+def lisp_mod(e1, e2): return make_int(e1.v % e2.v)
-def lisp_display(args, env):
- args = eval_list(args, env)
- do_list(lambda x: sys.stdout.write(str(x)), args)
+@lisp_function
+def lisp_display(*args):
+ for i in args:
+ sys.stdout.write(str(i))
sys.stdout.write("\n")
return Value.NIL
-
# Helper functions for the evaluator
# ----------------------------------
# in order to optimize tail calls
def lisp_eval(e, env):
"""evals an expression"""
+ result = None
ended = False
while not ended:
- #print "eval: %s"%str(e)
+ # print "eval: %s"%str(e)
if is_symbol(e):
result = env[e.v]
ended = True
else:
result = e
ended = True
-
+ # print "result: %s"%result
return result
def lisp_apply(f, args, env):