[pypy-svn] r45160 - in pypy/dist/pypy/lang/scheme: . test

jlg at codespeak.net jlg at codespeak.net
Tue Jul 17 16:37:18 CEST 2007


Author: jlg
Date: Tue Jul 17 16:37:17 2007
New Revision: 45160

Modified:
   pypy/dist/pypy/lang/scheme/object.py
   pypy/dist/pypy/lang/scheme/test/test_eval.py
Log:
letrec is cool now

Modified: pypy/dist/pypy/lang/scheme/object.py
==============================================================================
--- pypy/dist/pypy/lang/scheme/object.py	(original)
+++ pypy/dist/pypy/lang/scheme/object.py	Tue Jul 17 16:37:17 2007
@@ -628,7 +628,29 @@
 
         return self.eval_body(local_ctx, lst.cdr)
 
-Letrec = Let
+class Letrec(W_Macro):
+    def call_tr(self, ctx, lst):
+        """let uses eval_body, so it is tail-recursive aware"""
+        if not isinstance(lst, W_Pair):
+            raise SchemeSyntaxError
+        local_ctx = ctx.copy()
+        map_name_expr = {}
+        w_formal = lst.car
+        while isinstance(w_formal, W_Pair):
+            w_def = w_formal.get_car_as_pair()
+            name = w_def.car.to_string()
+            map_name_expr[name] = w_def.get_cdr_as_pair().car
+            local_ctx.bound(name)
+            w_formal = w_formal.cdr
+
+        map_name_val = {}
+        for (name, expr) in map_name_expr.items():
+            map_name_val[name] = expr.eval(local_ctx)
+
+        for (name, w_val) in map_name_val.items():
+            local_ctx.sete(name, w_val)
+
+        return self.eval_body(local_ctx, lst.cdr)
 
 def literal(sexpr):
     return W_Pair(W_Identifier('quote'), W_Pair(sexpr, W_Nil()))
@@ -728,10 +750,14 @@
     def get(self, name):
         loc = self.scope.get(name, None)
         if loc is not None:
+            if loc.obj is None:
+                raise UnboundVariable(name)
             return loc.obj
 
         loc = self.globalscope.get(name, None)
         if loc is not None:
+            if loc.obj is None:
+                raise UnboundVariable(name)
             return loc.obj
 
         raise UnboundVariable(name)
@@ -774,6 +800,13 @@
         else:
             self.globalscope[name] = Location(obj)
 
+    def bound(self, name):
+        """create new location"""
+        if self.closure:
+            self.scope[name] = Location(None)
+        else:
+            self.globalscope[name] = Location(None)
+
     def get_location(self, name):
         """internal/test use only
         returns location bound to variable

Modified: pypy/dist/pypy/lang/scheme/test/test_eval.py
==============================================================================
--- pypy/dist/pypy/lang/scheme/test/test_eval.py	(original)
+++ pypy/dist/pypy/lang/scheme/test/test_eval.py	Tue Jul 17 16:37:17 2007
@@ -394,6 +394,12 @@
     assert w_result.to_number() == 44
     assert ctx.get("var") is w_global
 
+    w_result = eval_expr(ctx, """
+        (let ((x (lambda () 1)))
+            (let ((y (lambda () (x)))
+                  (x (lambda () 2))) (y)))""")
+    assert w_result.to_number() == 1
+
     py.test.raises(UnboundVariable, eval_noctx, "(let ((y 0) (x y)) x)")
 
 def test_letrec():
@@ -412,6 +418,12 @@
                 (even? 2000))""")
     assert w_result.to_boolean() is True
 
+    w_result = eval_expr(ctx, """
+        (let ((x (lambda () 1)))
+            (letrec ((y (lambda () (x)))
+                     (x (lambda () 2))) (y)))""")
+    assert w_result.to_number() == 2
+
     py.test.raises(UnboundVariable, eval_noctx, "(letrec ((y 0) (x y)) x)")
 
 def test_letstar():



More information about the Pypy-commit mailing list