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

jlg at codespeak.net jlg at codespeak.net
Wed Jul 25 16:22:45 CEST 2007


Author: jlg
Date: Wed Jul 25 16:22:45 2007
New Revision: 45328

Modified:
   pypy/dist/pypy/lang/scheme/execution.py
   pypy/dist/pypy/lang/scheme/object.py
   pypy/dist/pypy/lang/scheme/test/test_macro.py
Log:
macro expansion more hygenic, expand_eval method added; ExecutionContext __init__ create new Location() for each operation

Modified: pypy/dist/pypy/lang/scheme/execution.py
==============================================================================
--- pypy/dist/pypy/lang/scheme/execution.py	(original)
+++ pypy/dist/pypy/lang/scheme/execution.py	Wed Jul 25 16:22:45 2007
@@ -57,7 +57,7 @@
 
 OPERATION_MAP = {}
 for name, cls in OMAP.items():
-    OPERATION_MAP[name] = Location(cls(name))
+    OPERATION_MAP[name] = cls(name)
 
 class ExecutionContext(object):
     """Execution context implemented as a dict.
@@ -66,7 +66,10 @@
     """
     def __init__(self, globalscope=None, scope=None, closure=False):
         if globalscope is None:
-            self.globalscope = OPERATION_MAP.copy()
+            self.globalscope = {}
+            for name, oper in OPERATION_MAP.items():
+                self.globalscope[name] = Location(oper)
+
         else:
             self.globalscope = globalscope
 

Modified: pypy/dist/pypy/lang/scheme/object.py
==============================================================================
--- pypy/dist/pypy/lang/scheme/object.py	(original)
+++ pypy/dist/pypy/lang/scheme/object.py	Wed Jul 25 16:22:45 2007
@@ -904,6 +904,19 @@
 
         return (False, {})
 
+class SyntacticClosure(W_Root):
+    def __init__(self, ctx, sexpr):
+        self.sexpr = sexpr
+        self.closure = ctx
+
+    def eval_tr(self, ctx):
+        #this symbol is in Syntactic Closure 
+        return self.sexpr.eval_tr(self.closure)
+
+    def to_string(self):
+        #return "#<closure: " + self.sexpr.to_string() + ">"
+        return self.sexpr.to_string()
+
 class W_Transformer(W_Procedure):
     def __init__(self, syntax_lst, ctx, pname=""):
         self.pname = pname
@@ -930,20 +943,29 @@
         if template is None :
             raise SchemeSyntaxError
 
-        return self.substitute(template)
+        return self.substitute(template, ctx)
 
-    def substitute(self, sexpr):
+    def substitute(self, sexpr, ctx):
         if isinstance(sexpr, W_Symbol):
             w_sub = self.match_dict.get(sexpr.to_string(), None)
             if w_sub is not None:
-                return w_sub
+                return SyntacticClosure(ctx, w_sub)
 
             return sexpr
 
         elif isinstance(sexpr, W_Pair):
-            return W_Pair(self.substitute(sexpr.car),
-                    self.substitute(sexpr.cdr))
+            return W_Pair(self.substitute(sexpr.car, ctx),
+                    self.substitute(sexpr.cdr, ctx))
 
-        else:
-            return sexpr
+        return sexpr
             
+    def expand_eval(self, sexpr, ctx):
+        #we have lexical scopes:
+        # 1. in which macro was defined - self.closure
+        # 2. in which macro is called   - ctx
+        # 3. in which macro is expanded - expand_ctx 
+
+        expand_ctx = self.closure.copy()
+        expanded = self.expand(sexpr, ctx)
+        return expanded.eval(expand_ctx)
+

Modified: pypy/dist/pypy/lang/scheme/test/test_macro.py
==============================================================================
--- pypy/dist/pypy/lang/scheme/test/test_macro.py	(original)
+++ pypy/dist/pypy/lang/scheme/test/test_macro.py	Wed Jul 25 16:22:45 2007
@@ -91,7 +91,7 @@
 
     w_expr = parse("(foo bar)")[0]
     w_expanded = w_transformer.expand(w_expr, ctx)
-    assert isinstance(w_expanded, W_Symbol)
+    #assert isinstance(w_expanded, W_Symbol)
     assert w_expanded.to_string() == "bar"
 
     w_transformer = eval_(ctx, """(syntax-rules ()
@@ -112,3 +112,67 @@
     assert isinstance(w_expanded, W_Pair)
     assert w_expanded.to_string() == "(let ((var 12)) (+ 1 var))"
 
+def test_syntax_rules_expand():
+    ctx = ExecutionContext()
+
+    w_transformer = eval_(ctx, """(syntax-rules ()
+                                       ((_ var)
+                                        (let ((temp 1)) (+ var temp))))""")
+
+    w_expr = parse("(_ 12)")[0]
+    w_expanded = w_transformer.expand(w_expr, ctx)
+    assert w_expanded.to_string() == "(let ((temp 1)) (+ 12 temp))"
+    assert w_transformer.expand_eval(w_expr, ctx).to_number() == 13
+
+    #transparency
+    eval_(ctx, "(define temp 12)")
+    w_expr = parse("(_ temp)")[0]
+    w_expanded = w_transformer.expand(w_expr, ctx)
+    assert w_expanded.to_string() == "(let ((temp 1)) (+ temp temp))"
+    assert w_transformer.expand_eval(w_expr, ctx).to_number() == 13
+
+    #define in closure, should not affect macro eval
+    closure = ctx.copy()
+    eval_(closure, "(define + -)")
+    assert w_transformer.expand_eval(w_expr, closure).to_number() == 13
+
+    #define in top level - should affect macro eval
+    eval_(ctx, "(define + -)")
+    assert w_transformer.expand_eval(w_expr, ctx).to_number() == 11
+
+def test_syntax_rules_hygenic_expansion():
+    ctx = ExecutionContext()
+
+    w_transformer = eval_(ctx, """(syntax-rules ()
+                                     ((dotimes count body)
+                                      (letrec ((loop
+                                       (lambda (counter)
+                                         (if (= counter 0)
+                                             ()
+                                             (begin
+                                                body
+                                                (loop (- counter 1)))))))
+                                        (loop count))))""")
+
+    w_expr = parse("(_ 5 (set! counter (+ counter 1)))")[0]
+    py.test.raises(UnboundVariable, w_transformer.expand_eval, w_expr, ctx)
+
+    eval_(ctx, "(define counter 0)")
+    w_expr = parse("(_ 5 (set! counter (+ counter 1)))")[0]
+    w_transformer.expand_eval(w_expr, ctx)
+    assert ctx.get("counter").to_number() == 5
+
+def test_shadow():
+    py.test.skip("in progress")
+    ctx = ExecutionContext()
+
+    w_transformer = eval_(ctx, """(syntax-rules ()
+                                     ((shadow used-arg body)
+                                      (let ((used-arg 5)) body)))""")
+
+    w_expr = parse("(shadow test test)")[0]
+    assert w_transformer.expand_eval(w_expr, ctx).to_number() == 5
+
+    eval_(ctx, "(define test 7)")
+    assert w_transformer.expand_eval(w_expr, ctx).to_number() == 5
+



More information about the Pypy-commit mailing list