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

jlg at codespeak.net jlg at codespeak.net
Wed Aug 1 16:23:20 CEST 2007


Author: jlg
Date: Wed Aug  1 16:23:19 2007
New Revision: 45447

Modified:
   pypy/dist/pypy/lang/scheme/execution.py
   pypy/dist/pypy/lang/scheme/object.py
   pypy/dist/pypy/lang/scheme/ssparser.py
   pypy/dist/pypy/lang/scheme/test/test_macro.py
   pypy/dist/pypy/lang/scheme/test/test_parser.py
Log:
bug in macro expansions removed, SyntacticClosure is no more, instead we have PairClosure and SymbolClosure; parsing for ellipsis; macros with flat ellipsis works

Modified: pypy/dist/pypy/lang/scheme/execution.py
==============================================================================
--- pypy/dist/pypy/lang/scheme/execution.py	(original)
+++ pypy/dist/pypy/lang/scheme/execution.py	Wed Aug  1 16:23:19 2007
@@ -83,13 +83,11 @@
         self.closure = closure
 
     def _dispatch(self, symb):
-        if isinstance(symb, W_Symbol):
-            return (self, symb.name)
+        if isinstance(symb, SymbolClosure):
+            return (symb.closure, symb.name)
 
-        elif isinstance(symb, SyntacticClosure):
-            symbol = symb.sexpr
-            if isinstance(symbol, W_Symbol):
-                return (symb.closure, symbol.name)
+        elif isinstance(symb, W_Symbol):
+            return (self, symb.name)
 
         raise SchemeSyntaxError
 

Modified: pypy/dist/pypy/lang/scheme/object.py
==============================================================================
--- pypy/dist/pypy/lang/scheme/object.py	(original)
+++ pypy/dist/pypy/lang/scheme/object.py	Wed Aug  1 16:23:19 2007
@@ -77,6 +77,8 @@
     def eq_symbol(self, w_symb):
         return w_symb is self
 
+w_ellipsis = W_Symbol("...")
+
 def symbol(name):
     #use this to create new symbols, it stores all symbols
     #in W_Symbol.obarray dict
@@ -205,6 +207,9 @@
         #end proper list with dotted
         return car + " . " + cdr.to_string()
 
+    def __repr__(self):
+        return "<W_Pair " + self.to_string() + ">"
+
     def eval_tr(self, ctx):
         oper = self.car.eval(ctx)
         if not isinstance(oper, W_Callable):
@@ -316,7 +321,7 @@
         return "#<procedure %s>" % (self.pname,)
 
     def procedure_tr(self, ctx, lst):
-        """must be tail-recursive aware, uses eval_body"""
+        #must be tail-recursive aware, uses eval_body
         #ctx is a caller context, which is joyfully ignored
 
         local_ctx = self.closure.copy()
@@ -619,7 +624,7 @@
 
 class MacroIf(W_Macro):
     def call_tr(self, ctx, lst):
-        """if needs to be tail-recursive aware"""
+        #if needs to be tail-recursive aware
         if not isinstance(lst, W_Pair):
             raise SchemeSyntaxError
         w_condition = lst.car
@@ -667,7 +672,7 @@
 
 class LetStar(W_Macro):
     def call_tr(self, ctx, lst):
-        """let* uses eval_body, so it is tail-recursive aware"""
+        #let* uses eval_body, so it is tail-recursive aware
         if not isinstance(lst, W_Pair):
             raise SchemeSyntaxError
         local_ctx = ctx.copy()
@@ -856,6 +861,11 @@
         #closes template in syntactic enviroment at the point of definition
         return W_Transformer(syntax_lst, ctx)
 
+class Ellipsis(Exception):
+    def __init__(self, expr, level):
+        self.expr = expr
+        self.level = level
+
 class SyntaxRule(object):
     def __init__(self, pattern, template, literals):
         self.pattern = pattern
@@ -886,6 +896,13 @@
                 if w_form is not w_literal:
                     return (False, {})
 
+            w_pattcdr = w_patt.cdr
+            if isinstance(w_pattcdr, W_Pair) and w_pattcdr.car is w_ellipsis:
+                #w_pattcar should be matched 0-inf times in ellipsis
+                print w_patt, w_expr
+                match_dict[w_pattcar.to_string()] = Ellipsis(w_expr, 1)
+                return (True, match_dict)
+
             if isinstance(w_pattcar, W_Pair):
                 if not isinstance(w_exprcar, W_Pair):
                     return (False, {})
@@ -897,28 +914,60 @@
                 match_dict.update(match_nested)
 
             match_dict[w_pattcar.to_string()] = w_exprcar
+
             w_patt = w_patt.cdr
             w_expr = w_expr.cdr
 
-        if w_expr is w_nil and w_patt is w_nil:
-            return (True, match_dict)
+        if (w_expr is w_nil) and (w_patt is w_nil):
+                return (True, match_dict)
+
+        if w_patt is w_nil:
+            return (False, {})
+
+        #w_patt is symbol or primitive //as cdr of dotted list
+        match_dict[w_patt.to_string()] = w_expr
+        return (True, match_dict)
 
         return (False, {})
 
-class SyntacticClosure(W_Root):
-    def __init__(self, ctx, sexpr):
-        assert not isinstance(sexpr, SyntacticClosure)
-        assert isinstance(sexpr, W_Root)
-        self.sexpr = sexpr
+class SymbolClosure(W_Symbol):
+    def __init__(self, ctx, symbol):
+        assert isinstance(symbol, W_Symbol)
+        assert not isinstance(symbol, SymbolClosure)
+        self.symbol = symbol
+        self.name = symbol.name
         self.closure = ctx
 
     def eval_tr(self, ctx):
         #this symbol is in Syntactic Closure 
-        return self.sexpr.eval_tr(self.closure)
+        return self.symbol.eval_tr(self.closure)
+
+    def to_string(self):
+        #return "#<closure: " + self.sexpr.to_string() + ">"
+        return self.symbol.to_string()
+
+    def __repr__(self):
+        return "<sc:W_Symbol " + self.to_string() + ">"
+
+class PairClosure(W_Pair):
+    def __init__(self, ctx, pair):
+        assert isinstance(pair, W_Pair)
+        assert not isinstance(pair, PairClosure)
+        self.pair = pair
+        self.car = pair.car
+        self.cdr = pair.cdr
+        self.closure = ctx
+
+    def eval_tr(self, ctx):
+        #this pair is in Syntactic Closure 
+        return self.pair.eval_tr(self.closure)
 
     def to_string(self):
         #return "#<closure: " + self.sexpr.to_string() + ">"
-        return self.sexpr.to_string()
+        return self.pair.to_string()
+
+    def __repr__(self):
+        return "<sc:W_Pair " + self.to_string() + ">"
 
 class W_Transformer(W_Procedure):
     def __init__(self, syntax_lst, ctx, pname=""):
@@ -950,16 +999,31 @@
                 # enviroment at the point of use
 
                 #not always needed, because w_sub can have no W_Symbol inside
-                if isinstance(w_sub, W_Symbol) or isinstance(w_sub, W_Pair):
-                    return SyntacticClosure(ctx, w_sub)
+                if isinstance(w_sub, W_Symbol) and \
+                        not isinstance(w_sub, SymbolClosure):
+                    return SymbolClosure(ctx, w_sub)
+
+                if isinstance(w_sub, W_Pair) and \
+                        not isinstance(w_sub, PairClosure):
+                    return PairClosure(ctx, w_sub)
+
+                if isinstance(w_sub, Ellipsis):
+                    raise w_sub
 
                 return w_sub
 
             return sexpr
 
         elif isinstance(sexpr, W_Pair):
-            w_pair = W_Pair(self.substitute(ctx, sexpr.car, match_dict),
-                    self.substitute(ctx, sexpr.cdr, match_dict))
+            try:
+                w_pair = W_Pair(self.substitute(ctx, sexpr.car, match_dict),
+                        self.substitute(ctx, sexpr.cdr, match_dict))
+            except Ellipsis, e:
+                scdr = sexpr.cdr
+                if isinstance(scdr, W_Pair) and scdr.car is w_ellipsis:
+                    return e.expr
+                else:
+                    raise SchemeSyntaxError
 
             w_paircar = w_pair.car
             if isinstance(w_paircar, W_Symbol):
@@ -972,8 +1036,7 @@
                 except UnboundVariable:
                     pass
 
-            elif isinstance(w_paircar, SyntacticClosure) and \
-                    isinstance(w_paircar.sexpr, W_Symbol):
+            elif isinstance(w_paircar, SymbolClosure):
                 try:
                     #ops, which context?
                     w_macro = ctx.get(w_paircar.sexpr.to_string())
@@ -1043,7 +1106,6 @@
         w_formal = lst.car
         while isinstance(w_formal, W_Pair):
             w_def = w_formal.get_car_as_pair()
-            #evaluate the values in caller ctx
             w_transformer = w_def.get_cdr_as_pair().car.eval(ctx)
             if not isinstance(w_transformer, W_Transformer):
                 raise SchemeSyntaxError

Modified: pypy/dist/pypy/lang/scheme/ssparser.py
==============================================================================
--- pypy/dist/pypy/lang/scheme/ssparser.py	(original)
+++ pypy/dist/pypy/lang/scheme/ssparser.py	Wed Aug  1 16:23:19 2007
@@ -2,7 +2,8 @@
 from pypy.rlib.parsing.pypackrat import PackratParser
 from pypy.rlib.parsing.makepackrat import BacktrackException, Status
 from pypy.lang.scheme.object import W_Pair, W_Integer, W_String, symbol, \
-        w_nil, W_Boolean, W_Real, quote, qq, unquote, unquote_splicing
+        w_nil, W_Boolean, W_Real, quote, qq, unquote, unquote_splicing, \
+        w_ellipsis
 
 def str_unquote(s):
     str_lst = []
@@ -29,13 +30,18 @@
         IGNORE*
         return {symbol(c)};
 
+    ELLIPSIS:
+        c = '...'
+        IGNORE*
+        return {w_ellipsis};
+
     FIXNUM:
         c = `\-?(0|([1-9][0-9]*))`
         IGNORE*
         return {W_Integer(int(c))};
 
     FLOAT:
-        c = `\-?[0-9]*\.[0-9]*`
+        c = `\-?([0-9]*\.[0-9]+|[0-9]+\.[0-9]*)`
         IGNORE*
         return {W_Real(float(c))};
 
@@ -83,6 +89,7 @@
       | qq
       | unquote_splicing
       | unquote
+      | ELLIPSIS
       | FLOAT
       | FIXNUM
       | BOOLEAN

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 Aug  1 16:23:19 2007
@@ -236,6 +236,19 @@
     assert eval_(ctx, "(my-or #f 42)").to_number() == 42
     assert eval_(ctx, "(my-or #f #f 82)").to_number() == 82
 
+def test_macro_expand():
+    ctx = ExecutionContext()
+    eval_(ctx, """(define-syntax foo (syntax-rules ()
+                                          ((foo) #t)
+                                          ((foo arg) arg)))""")
+    eval_(ctx, """(define-syntax bar (syntax-rules ()
+                                          ((bar) (foo))
+                                          ((bar arg) (foo arg))))""")
+
+    w_expr = parse("(bar 42)")[0]
+    #should expand directly (recursively) to 42
+    assert ctx.get("bar").expand(ctx, w_expr).to_string() == "42"
+
 def test_let_syntax():
     ctx = ExecutionContext()
     w_result = \
@@ -260,3 +273,32 @@
 
     assert eval_(ctx, "a").to_number() == 0
 
+def test_reverse():
+    ctx = ExecutionContext()
+    eval_(ctx, """(define-syntax reverse-order
+                                 (syntax-rules () 
+                                   ((_ e) (reverse-order e ())) 
+                                   ((_ (e . rest) r)
+                                    (reverse-order rest (e . r))) 
+                                   ((_ () r) r)))""")
+
+    w_result = eval_(ctx, "(reverse-order (2 3 -))")
+    assert w_result.to_number() == 1
+
+def test_ellipsis_symbol():
+    ctx = ExecutionContext()
+    eval_(ctx, """(define-syntax or (syntax-rules ()
+                                      ((or) #f)
+                                      ((or e) e)
+                                      ((or e1 e2 ...)
+                                       (let ((temp e1))
+                                         (if temp
+                                             temp
+                                             (or e2 ...))))))""")
+
+    assert eval_(ctx, "(or 12)").to_number() == 12
+    assert eval_(ctx, "(or 12 42)").to_number() == 12
+    assert eval_(ctx, "(or #f 42)").to_number() == 42
+    assert eval_(ctx, "(or #f #f 82)").to_number() == 82
+    assert eval_(ctx, "(or #f #f #f 162)").to_number() == 162
+

Modified: pypy/dist/pypy/lang/scheme/test/test_parser.py
==============================================================================
--- pypy/dist/pypy/lang/scheme/test/test_parser.py	(original)
+++ pypy/dist/pypy/lang/scheme/test/test_parser.py	Wed Aug  1 16:23:19 2007
@@ -2,6 +2,7 @@
 from pypy.lang.scheme.ssparser import parse
 from pypy.lang.scheme.object import W_Boolean, W_Real, W_Integer, W_String
 from pypy.lang.scheme.object import W_Pair, W_Nil, W_Symbol, W_Symbol
+from pypy.rlib.parsing.makepackrat import BacktrackException
 
 def parse_sexpr(expr):
     return parse(expr)[0]
@@ -56,6 +57,15 @@
     assert isinstance(w_float, W_Real)
     assert unwrap(w_float) == -123456.1234
 
+    w_float = parse_sexpr('.1234')
+    assert isinstance(w_float, W_Real)
+    assert unwrap(w_float) == 0.1234
+    w_float = parse_sexpr('12.')
+    assert isinstance(w_float, W_Real)
+    assert unwrap(w_float) == 12.0
+
+    py.test.raises(BacktrackException, parse_sexpr, '.')
+
 def test_sexpr():
     w_list = parse_sexpr('( 1 )')
     assert isinstance(w_list, W_Pair)
@@ -155,3 +165,8 @@
     assert unwrap(t) == ['unquote-splicing', ['list',
                                 ['unquote-splicing', 'b'], 3]]
 
+def test_ellipsis():
+    w_float = parse_sexpr('...')
+    assert isinstance(w_float, W_Symbol)
+    assert unwrap(w_float) == "..."
+



More information about the Pypy-commit mailing list