[pypy-svn] r45067 - in pypy/dist/pypy/interpreter/pyparser: . data test

justas at codespeak.net justas at codespeak.net
Sat Jul 14 12:51:04 CEST 2007


Author: justas
Date: Sat Jul 14 12:51:04 2007
New Revision: 45067

Modified:
   pypy/dist/pypy/interpreter/pyparser/astbuilder.py
   pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a
   pypy/dist/pypy/interpreter/pyparser/test/test_astbuilder_future.py
Log:
(Arlo, Justas)

The future_import_builder supports with statements.
The AstBuilder supports rules which doesn't consume attoms:
    if the builder function returns True it assumes that the rule
    didn't consume any atoms and leaves the stack unmodified.


Modified: pypy/dist/pypy/interpreter/pyparser/astbuilder.py
==============================================================================
--- pypy/dist/pypy/interpreter/pyparser/astbuilder.py	(original)
+++ pypy/dist/pypy/interpreter/pyparser/astbuilder.py	Sat Jul 14 12:51:04 2007
@@ -765,6 +765,7 @@
         else_ = atoms[6]
     builder.push(ast.While(test, body, else_, atoms[0].lineno))
 
+
 def build_with_stmt(builder, nb):
     """with_stmt: 'with' test [ NAME expr ] ':' suite"""
 
@@ -783,6 +784,7 @@
         body = atoms[5]
     builder.push(ast.With(test, body, var, atoms[0].lineno))
 
+
 def build_import_name(builder, nb):
     """import_name: 'import' dotted_as_names
 
@@ -837,6 +839,7 @@
     import_as_name: NAME [NAME NAME]
     """
     atoms = get_atoms(builder, nb)
+
     index = 1
     incr, from_name = parse_dotted_names(atoms[index:], builder)
     index += (incr + 1) # skip 'import'
@@ -887,20 +890,33 @@
     Enables python language future imports. Called once per feature imported,
     no matter how you got to this one particular feature.
     """
+
     atoms = peek_atoms(builder, nb)
+
     feature_name = atoms[0].get_value()
     assert type(feature_name) is str
     space = builder.space
-    w_feature_code = space.appexec([space.wrap(feature_name)],
+    feature_code = space.unwrap(space.appexec([space.wrap(feature_name)],
         """(feature):
             import __future__ as f
             feature = getattr(f, feature, None)
             return feature and feature.compiler_flag or 0
-        """)
+        """))
 
     # We will call a method on the parser (the method exists only in unit
     # tests).
-    builder.parser.add_production(space.unwrap(w_feature_code))
+    if feature_code == consts.CO_FUTURE_WITH_STATEMENT:
+        rules = """
+            compound_stmt: (if_stmt | while_stmt | for_stmt | try_stmt |
+                            funcdef | classdef | with_stmt)
+            with_stmt: 'with' test [ 'as' expr ] ':' suite
+            """
+        builder.insert_grammar_rule(rules, {
+            'with_stmt': build_with_stmt})
+
+    # We need to keep the rule on the stack so we can share atoms
+    # with a later rule
+    return True
 
 
 def build_yield_stmt(builder, nb):
@@ -1074,7 +1090,6 @@
     'exprlist' : build_exprlist,
     'decorator' : build_decorator,
     'eval_input' : build_eval_input,
-    'with_stmt' : build_with_stmt,
     }
 
 
@@ -1143,9 +1158,7 @@
                 self.push(astnode)
             else:
                 builder_func = self.build_rules.get(rulename, None)
-                if builder_func:
-                    builder_func(self, 1)
-                else:
+                if not builder_func or builder_func(self, 1):
                     self.push_rule(rule.codename, 1, source)
         else:
             self.push_rule(rule.codename, 1, source)
@@ -1165,9 +1178,7 @@
                 self.push(astnode)
             else:
                 builder_func = self.build_rules.get(rulename, None)
-                if builder_func:
-                    builder_func(self, elts_number)
-                else:
+                if not builder_func or builder_func(self, elts_number):
                     self.push_rule(rule.codename, elts_number, source)
         else:
             self.push_rule(rule.codename, elts_number, source)
@@ -1218,6 +1229,13 @@
         else:
             return None
 
+    def insert_grammar_rule(self, rule, buildfuncs):
+        """Inserts new grammar rules for the builder
+        This allows to change the rules during the parsing
+        """
+        self.parser.insert_rule(rule)
+        self.build_rules.update(buildfuncs)
+
 
 def show_stack(before, after):
     """debugging helper function"""

Modified: pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a
==============================================================================
--- pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a	(original)
+++ pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a	Sat Jul 14 12:51:04 2007
@@ -69,15 +69,12 @@
 exec_stmt: 'exec' expr ['in' test [',' test]]
 assert_stmt: 'assert' test [',' test]
 
-# TODO: with_stmt should be added dynamically to compund_stmt if 
-# imported from __future__
 compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
 if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
 while_stmt: 'while' test ':' suite ['else' ':' suite]
 for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
 try_stmt: ('try' ':' suite (except_clause ':' suite)+ #diagram:break
            ['else' ':' suite] | 'try' ':' suite 'finally' ':' suite)
-with_stmt: 'with' test [ 'as' expr ] ':' suite
 # NB compile.c makes sure that the default except clause is last
 except_clause: 'except' [test [',' test]]
 suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT

Modified: pypy/dist/pypy/interpreter/pyparser/test/test_astbuilder_future.py
==============================================================================
--- pypy/dist/pypy/interpreter/pyparser/test/test_astbuilder_future.py	(original)
+++ pypy/dist/pypy/interpreter/pyparser/test/test_astbuilder_future.py	Sat Jul 14 12:51:04 2007
@@ -28,9 +28,10 @@
             return val
         return self.tokens[ tok ]
 
-    def add_production(self, rule):
+    def insert_rule(self, rule):
         self.trace.append(rule)
 
+
 class RuleStub:
     def __init__(self, name, root=False):
         self.codename = name
@@ -49,6 +50,11 @@
         feature_name = posargs_w[0]
         return self.feature_code_lookup.get(feature_name, 0)
 
+def assert_stripped_lines(text1, text2):
+    lines1 = [line.strip() for line in text1.strip().split('\n')]
+    lines2 = [line.strip() for line in text2.strip().split('\n')]
+    assert lines1 == lines2
+
 
 class TestBuilderFuture:
     def setup_class(self):
@@ -71,8 +77,24 @@
         for val in token_values:
             self.builder.push(TokenForTest(val, self.parser))
 
-        astbuilder.build_future_import_feature(self.builder, len(token_values))
+        assert 'with_stmt' not in self.builder.build_rules
+
+        result = astbuilder.build_future_import_feature(
+            self.builder, len(token_values))
+        assert result
+        
         assert ([rule.value for rule in self.builder.rule_stack] ==
                 token_values)
-        assert self.parser.trace == [32768]
+        assert_stripped_lines(self.parser.trace[0],
+            """
+            compound_stmt: (if_stmt | while_stmt | for_stmt | try_stmt |
+                            funcdef | classdef | with_stmt)
+            with_stmt: 'with' test [ 'as' expr ] ':' suite
+            """)
+        assert len(self.parser.trace) == 1
+
+        assert (self.builder.build_rules['with_stmt'] ==
+                astbuilder.build_with_stmt)
+
+
 



More information about the Pypy-commit mailing list