simplified cond and the eval loop
authorJorge Gorbe <jgorbe@stcsl.es>
Mon, 13 Jan 2014 13:48:03 +0000 (14:48 +0100)
committerJorge Gorbe <jgorbe@stcsl.es>
Mon, 13 Jan 2014 13:48:03 +0000 (14:48 +0100)
lisp0.py

index edce63ab3c400511a339aff67c9d342977c2bf88..80c4760393d8e320a2a1c32442fa22c3b36889a1 100644 (file)
--- a/lisp0.py
+++ b/lisp0.py
@@ -83,12 +83,18 @@ class Environment:
 
 
 # helper lisp-list functions
+def find(pred, l):
+    while not is_nil(l):
+        x = car(l)
+        if pred(x): return x
+        l = cdr(l)
+    return Value.NIL
+
 def foldl(func, initial, l):
     result = initial
-    cur = l
-    while not is_nil(cur):
-        result = func(result, car(cur))
-        cur = cdr(cur)
+    while not is_nil(l):
+        result = func(result, car(l))
+        l = cdr(l)
     return result
 
 def foldr(func, initial, l):
@@ -126,19 +132,9 @@ def lisp_quote(args, env):
     assert(is_nil(cdr(args)))
     return car(args)
 
+# empty function used as a marker, the code is inlined into lisp_eval
 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
-
+    pass
 
 def quasiquote_expression(expr, env):
     """returns a tuple with:
@@ -250,14 +246,11 @@ global_env = Environment()
 # 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)
-        if is_symbol(e):
-            result = env[e.v]
-            ended = True
-        elif is_pair(e):
+    while True:
+        if e is None:        return Value.NIL
+        elif is_symbol(e):   return env[e.v]
+        elif not is_pair(e): return e
+        else:
             f = lisp_eval(car(e), env)
             args = cdr(e)
             # inlined body of the apply function
@@ -266,26 +259,14 @@ def lisp_eval(e, 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
+                    satisfied = find(lambda x: is_true(lisp_eval(car(x), env)), args)
+                    if not is_nil(satisfied):
+                        e = cadr(satisfied)
                 else:
-                    result = f(args, env)
-                    ended = True
+                    return f(args, env)
+                    
             elif f.t == "macro":
-                expansion = lisp_apply(f.v, args, env)
-                #print "macro expansion:", expansion
-                e = expansion
+                e = lisp_apply(f.v, args, env)
             else:
                 formals, body, environment = f.v
                 new_env = Environment(environment)
@@ -303,11 +284,6 @@ def lisp_eval(e, env):
                 
                 e = body
                 env = new_env
-        else:
-            result = e
-            ended = True
-        # print "result: %s"%result    
-    return result
 
 def lisp_apply(f, args, env):
     """applies an argument list to a function or special form"""