[pypy-svn] r23764 - in pypy/dist/pypy: interpreter/astcompiler interpreter/pyparser interpreter/pyparser/data interpreter/pyparser/test interpreter/stablecompiler interpreter/test tool

stuart at codespeak.net stuart at codespeak.net
Tue Feb 28 18:30:06 CET 2006


Author: stuart
Date: Tue Feb 28 18:30:05 2006
New Revision: 23764

Added:
   pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a
   pypy/dist/pypy/interpreter/pyparser/data/README
Removed:
   pypy/dist/pypy/interpreter/astcompiler/transformer.py
Modified:
   pypy/dist/pypy/interpreter/astcompiler/ast.py
   pypy/dist/pypy/interpreter/astcompiler/ast.txt
   pypy/dist/pypy/interpreter/astcompiler/pycodegen.py
   pypy/dist/pypy/interpreter/pyparser/astbuilder.py
   pypy/dist/pypy/interpreter/pyparser/ebnfparse.py
   pypy/dist/pypy/interpreter/pyparser/pysymbol.py
   pypy/dist/pypy/interpreter/pyparser/pythonparse.py
   pypy/dist/pypy/interpreter/pyparser/symbol.py
   pypy/dist/pypy/interpreter/pyparser/test/test_astbuilder.py
   pypy/dist/pypy/interpreter/stablecompiler/transformer.py
   pypy/dist/pypy/interpreter/test/test_syntax.py
   pypy/dist/pypy/tool/option.py
Log:
(Martin Blais, Arre, Stuart Williams)
Implemented conditional expressions.
Added new Grammar2.5a file for 2.5 grammar changes.
Added code to pysymbol.py to manually regenerate symbol.py from the 
grammar file.
Changed stable compiler to not crash with new grammar.


Modified: pypy/dist/pypy/interpreter/astcompiler/ast.py
==============================================================================
--- pypy/dist/pypy/interpreter/astcompiler/ast.py	(original)
+++ pypy/dist/pypy/interpreter/astcompiler/ast.py	Tue Feb 28 18:30:05 2006
@@ -1232,6 +1232,63 @@
                     ops=GetSetProperty(Compare.fget_ops, Compare.fset_ops ),
                     )
 
+class CondExpr(Node):
+    def __init__(self, test, true_expr, false_expr, lineno=-1):
+        Node.__init__(self, lineno)
+        self.test = test
+        self.true_expr = true_expr
+        self.false_expr = false_expr
+
+    def getChildren(self):
+        "NOT_RPYTHON"
+        return self.test, self.true_expr, self.false_expr
+
+    def getChildNodes(self):
+        return [self.test, self.true_expr, self.false_expr]
+
+    def __repr__(self):
+        return "CondExpr(%s, %s, %s)" % (self.test.__repr__(), self.true_expr.__repr__(), self.false_expr.__repr__())
+
+    def accept(self, visitor):
+        return visitor.visitCondExpr(self)
+
+    def fget_test( space, self):
+        return space.wrap(self.test)
+    def fset_test( space, self, w_arg):
+        self.test = space.interp_w(Node, w_arg, can_be_None=False)
+    def fget_true_expr( space, self):
+        return space.wrap(self.true_expr)
+    def fset_true_expr( space, self, w_arg):
+        self.true_expr = space.interp_w(Node, w_arg, can_be_None=False)
+    def fget_false_expr( space, self):
+        return space.wrap(self.false_expr)
+    def fset_false_expr( space, self, w_arg):
+        self.false_expr = space.interp_w(Node, w_arg, can_be_None=False)
+
+def descr_CondExpr_new(space, w_subtype, w_test, w_true_expr, w_false_expr, lineno=-1):
+    self = space.allocate_instance(CondExpr, w_subtype)
+    test = space.interp_w(Node, w_test, can_be_None=False)
+    self.test = test
+    true_expr = space.interp_w(Node, w_true_expr, can_be_None=False)
+    self.true_expr = true_expr
+    false_expr = space.interp_w(Node, w_false_expr, can_be_None=False)
+    self.false_expr = false_expr
+    self.lineno = lineno
+    return space.wrap(self)
+
+def descr_CondExpr_accept( space, w_self, w_visitor):
+    w_callable = space.getattr(w_visitor, space.wrap('visitCondExpr'))
+    args = Arguments(space, [ w_self ])
+    return space.call_args(w_callable, args)
+
+CondExpr.typedef = TypeDef('CondExpr', Node.typedef, 
+                     __new__ = interp2app(descr_CondExpr_new, unwrap_spec=[ObjSpace, W_Root, W_Root, W_Root, W_Root, int]),
+                     accept=interp2app(descr_CondExpr_accept, unwrap_spec=[ObjSpace, W_Root, W_Root] ),
+                    test=GetSetProperty(CondExpr.fget_test, CondExpr.fset_test ),
+                    true_expr=GetSetProperty(CondExpr.fget_true_expr, CondExpr.fset_true_expr ),
+                    false_expr=GetSetProperty(CondExpr.fget_false_expr, CondExpr.fset_false_expr ),
+                    )
+
 class Const(Node):
     def __init__(self, value, lineno=-1):
         Node.__init__(self, lineno)
@@ -4232,6 +4289,8 @@
         return self.default( node )
     def visitCompare(self, node):
         return self.default( node )
+    def visitCondExpr(self, node):
+        return self.default( node )
     def visitConst(self, node):
         return self.default( node )
     def visitContinue(self, node):

Modified: pypy/dist/pypy/interpreter/astcompiler/ast.txt
==============================================================================
--- pypy/dist/pypy/interpreter/astcompiler/ast.txt	(original)
+++ pypy/dist/pypy/interpreter/astcompiler/ast.txt	Tue Feb 28 18:30:05 2006
@@ -78,6 +78,7 @@
 AbstractTest:
 Or(AbstractTest): nodes!
 And(AbstractTest): nodes!
+CondExpr: test, true_expr, false_expr
 BitOp:
 Bitor(BitOp): nodes!
 Bitxor(BitOp): nodes!

Modified: pypy/dist/pypy/interpreter/astcompiler/pycodegen.py
==============================================================================
--- pypy/dist/pypy/interpreter/astcompiler/pycodegen.py	(original)
+++ pypy/dist/pypy/interpreter/astcompiler/pycodegen.py	Tue Feb 28 18:30:05 2006
@@ -525,6 +525,24 @@
     def visitOr(self, node):
         self._visitTest(node, 'JUMP_IF_TRUE')
 
+    def visitCondExpr(self, node):
+        node.test.accept(self)
+
+        end = self.newBlock()
+        falseblock = self.newBlock()
+
+        self.emitop_block('JUMP_IF_FALSE', falseblock)
+
+        self.emit('POP_TOP')
+        node.true_expr.accept(self)
+        self.emitop_block('JUMP_FORWARD', end)
+
+        self.nextBlock(falseblock)
+        self.emit('POP_TOP')
+        node.false_expr.accept(self)
+
+        self.nextBlock(end)
+
     def visitCompare(self, node):
         node.expr.accept( self )
         cleanup = self.newBlock()

Modified: pypy/dist/pypy/interpreter/pyparser/astbuilder.py
==============================================================================
--- pypy/dist/pypy/interpreter/pyparser/astbuilder.py	(original)
+++ pypy/dist/pypy/interpreter/pyparser/astbuilder.py	Tue Feb 28 18:30:05 2006
@@ -1,6 +1,6 @@
 """This module provides the astbuilder class which is to be used
 by GrammarElements to directly build the AST during parsing
-without going trhough the nested tuples step
+without going through the nested tuples step
 """
 
 from grammar import BaseGrammarBuilder, AbstractContext
@@ -257,9 +257,9 @@
             ifs = []
         else:
             assert False, 'Unexpected token: expecting for in listcomp'
-        # 
+        #
         # Original implementation:
-        # 
+        #
         # if tokens[index].get_value() == 'for':
         #     index += 1 # skip 'for'
         #     ass_node = to_lvalue(tokens[index], consts.OP_ASSIGN)
@@ -320,7 +320,7 @@
 
 def get_docstring(builder,stmt):
     """parses a Stmt node.
-    
+
     If a docstring if found, the Discard node is **removed**
     from <stmt> and the docstring is returned.
 
@@ -340,7 +340,7 @@
                 del stmt.nodes[0]
                 doc = expr.value
     return doc
-    
+
 
 def to_lvalue(ast_node, flags):
     lineno = ast_node.lineno
@@ -388,7 +388,7 @@
                                  lineno, 0, '')
         else:
             raise SyntaxError("can't assign to non-lvalue",
-                             lineno, 0, '') 
+                             lineno, 0, '')
 
 def is_augassign( ast_node ):
     if ( isinstance( ast_node, ast.Name ) or
@@ -410,7 +410,7 @@
         i -= 1
     atoms.reverse()
     return atoms
-    
+
 #def eval_string(value):
 #    """temporary implementation
 #
@@ -466,7 +466,7 @@
 
 def parse_attraccess(tokens):
     """parses token list like ['a', '.', 'b', '.', 'c', ...]
-    
+
     and returns an ast node : ast.Getattr(Getattr(Name('a'), 'b'), 'c' ...)
     """
     token = tokens[0]
@@ -579,7 +579,7 @@
         return lst[first:last]
     else:
         return []
-    
+
 
 def build_power(builder, nb):
     """power: atom trailer* ['**' factor]"""
@@ -742,7 +742,10 @@
             builder.push(TokenObject(tok.NAME, 'is not', lineno))
     else:
         assert False, "TODO" # uh ?
-        
+
+def build_or_test(builder, nb):
+    return build_binary_expr(builder, nb, ast.Or)
+
 def build_and_test(builder, nb):
     return build_binary_expr(builder, nb, ast.And)
 
@@ -756,8 +759,18 @@
         assert False, "not_test implementation incomplete in not_test"
 
 def build_test(builder, nb):
-    return build_binary_expr(builder, nb, ast.Or)
-    
+    atoms = get_atoms(builder, nb)
+    if len(atoms) == 1:
+        builder.push(atoms[0])
+    elif len(atoms) == 5:
+        builder.push(
+            ast.CondExpr(atoms[2], atoms[0], atoms[4], atoms[1].lineno))
+    else:
+        assert False, "invalid number of atoms for rule 'test'"
+
+# Note: we do not include a build_old_test() because it does not need to do
+# anything.
+
 def build_testlist(builder, nb):
     return build_binary_expr(builder, nb, ast.Tuple)
 
@@ -837,7 +850,7 @@
             stmts.extend(node.nodes)
         elif isinstance(node, TokenObject) and node.name == tok.ENDMARKER:
             # XXX Can't we just remove the last element of the list ?
-            break    
+            break
         elif isinstance(node, TokenObject) and node.name == tok.NEWLINE:
             continue
         else:
@@ -911,7 +924,6 @@
     names, defaults, flags = parse_arglist(slicecut(atoms, 1, -2))
     builder.push(ast.Lambda(names, defaults, flags, code, lineno))
 
-
 def build_trailer(builder, nb):
     """trailer: '(' ')' | '(' arglist ')' | '[' subscriptlist ']' | '.' NAME
     """
@@ -1009,7 +1021,7 @@
         else:
             builder.push(SlicelistObject('slice', sliceinfos, lineno))
 
-        
+
 def build_listmaker(builder, nb):
     """listmaker: test ( list_for | (',' test)* [','] )"""
     atoms = get_atoms(builder, nb)
@@ -1325,7 +1337,7 @@
 def build_del_stmt(builder, nb):
     atoms = get_atoms(builder, nb)
     builder.push(to_lvalue(atoms[1], consts.OP_DELETE))
-        
+
 
 def build_assert_stmt(builder, nb):
     """assert_stmt: 'assert' test [',' test]"""
@@ -1404,7 +1416,7 @@
                ['else' ':' suite] | 'try' ':' suite 'finally' ':' suite)
     # NB compile.c makes sure that the default except clause is last
     except_clause: 'except' [test [',' test]]
-   
+
     """
     atoms = get_atoms(builder, nb)
     l = len(atoms)
@@ -1446,6 +1458,7 @@
     sym['expr'] : build_expr,
     sym['comparison'] : build_comparison,
     sym['comp_op'] : build_comp_op,
+    sym['or_test'] : build_or_test,
     sym['and_test'] : build_and_test,
     sym['not_test'] : build_not_test,
     sym['test'] : build_test,
@@ -1457,6 +1470,7 @@
     sym['file_input'] : build_file_input,
     sym['testlist_gexp'] : build_testlist_gexp,
     sym['lambdef'] : build_lambdef,
+    sym['old_lambdef'] : build_lambdef,
     sym['trailer'] : build_trailer,
     sym['arglist'] : build_arglist,
     sym['subscript'] : build_subscript,
@@ -1494,8 +1508,8 @@
         self.count = count
         self.lineno = lineno # src.getline()
         self.col = 0  # src.getcol()
-        
-    
+
+
 class RuleObject(BaseRuleObject):
     """A simple object used to wrap a rule or token"""
     def __init__(self, name, count, lineno):
@@ -1511,18 +1525,18 @@
 
 class TempRuleObject(BaseRuleObject):
     """used to keep track of how many items get_atom() should pop"""
-    
+
     def __init__(self, name, count, lineno):
         BaseRuleObject.__init__(self, count, lineno)
         self.temp_rulename = name
-        
+
     def __str__(self):
         return "<Rule: %s/%d>" % (self.temp_rulename, self.count)
 
     def __repr__(self):
         return "<Rule: %s/%d>" % (self.temp_rulename, self.count)
 
-    
+
 class TokenObject(ast.Node):
     """A simple object used to wrap a rule or token"""
     def __init__(self, name, value, lineno):
@@ -1532,7 +1546,7 @@
         # self.line = 0 # src.getline()
         self.col = 0  # src.getcol()
         self.lineno = lineno
-        
+
     def get_name(self):
         return tok.tok_rpunct.get(self.name,
                                   tok.tok_name.get(self.name, str(self.name)))
@@ -1542,10 +1556,10 @@
         if value is None:
             value = ''
         return value
-    
+
     def __str__(self):
         return "<Token: (%s,%s)>" % (self.get_name(), self.value)
-    
+
     def __repr__(self):
         return "<Token: (%r,%s)>" % (self.get_name(), self.value)
 
@@ -1568,13 +1582,13 @@
 
     def __str__(self):
         return "<ArgList: (%s, %s, %s)>" % self.value
-    
+
     def __repr__(self):
         return "<ArgList: (%s, %s, %s)>" % self.value
-    
+
 class SubscriptObject(ObjectAccessor):
     """helper class to build subscript list
-    
+
     self.value represents the __getitem__ argument
     """
     def __init__(self, name, value, lineno):
@@ -1584,7 +1598,7 @@
 
     def __str__(self):
         return "<SubscriptList: (%s)>" % self.value
-    
+
     def __repr__(self):
         return "<SubscriptList: (%s)>" % self.value
 
@@ -1603,10 +1617,10 @@
 
     def __str__(self):
         return "<SliceList: (%s)>" % self.value
-    
+
     def __repr__(self):
         return "<SliceList: (%s)>" % self.value
-    
+
 
 class AstBuilderContext(AbstractContext):
     """specific context management for AstBuidler"""
@@ -1622,7 +1636,7 @@
         self.rule_stack = []
         self.space = space
         self.source_encoding = None
-        
+
     def context(self):
         return AstBuilderContext(self.rule_stack)
 
@@ -1718,12 +1732,12 @@
             l = space.builtin.get('long')
             return space.call_function(l, space.wrap(value), space.wrap(base))
         if value.endswith('j') or value.endswith('J'):
-            c = space.builtin.get('complex') 
+            c = space.builtin.get('complex')
             return space.call_function(c, space.wrap(value))
         try:
             i = space.builtin.get('int')
             return space.call_function(i, space.wrap(value), space.wrap(base))
-        except: 
+        except:
             f = space.builtin.get('float')
             return space.call_function(f, space.wrap(value))
 
@@ -1760,4 +1774,4 @@
         else:
             obj2 = "-"
         print "% 3d | %30s | %30s" % (i, obj1, obj2)
-    
+

Added: pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/interpreter/pyparser/data/Grammar2.5a	Tue Feb 28 18:30:05 2006
@@ -0,0 +1,129 @@
+# Grammar for Python
+
+# Note:  Changing the grammar specified in this file will most likely
+#        require corresponding changes in the parser module
+#        (../Modules/parsermodule.c).  If you can't make the changes to
+#        that module yourself, please co-ordinate the required changes
+#        with someone who can; ask around on python-dev for help.  Fred
+#        Drake <fdrake at acm.org> will probably be listening there.
+
+# Commands for Kees Blom's railroad program
+#diagram:token NAME
+#diagram:token NUMBER
+#diagram:token STRING
+#diagram:token NEWLINE
+#diagram:token ENDMARKER
+#diagram:token INDENT
+#diagram:output\input python.bla
+#diagram:token DEDENT
+#diagram:output\textwidth 20.04cm\oddsidemargin  0.0cm\evensidemargin 0.0cm
+#diagram:rules
+
+# Start symbols for the grammar:
+#	single_input is a single interactive statement;
+#	file_input is a module or sequence of commands read from an input file;
+#	eval_input is the input for the eval() and input() functions.
+# NB: compound_stmt in single_input is followed by extra NEWLINE!
+single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE
+file_input: (NEWLINE | stmt)* ENDMARKER
+eval_input: testlist NEWLINE* ENDMARKER
+
+decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
+decorators: decorator+
+funcdef: [decorators] 'def' NAME parameters ':' suite
+parameters: '(' [varargslist] ')'
+varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [',']
+fpdef: NAME | '(' fplist ')'
+fplist: fpdef (',' fpdef)* [',']
+
+stmt: simple_stmt | compound_stmt
+simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
+small_stmt: expr_stmt | print_stmt  | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | exec_stmt | assert_stmt
+expr_stmt: testlist (augassign testlist | ('=' testlist)*)
+augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//='
+# For normal assignments, additional restrictions enforced by the interpreter
+print_stmt: 'print' ( '>>' test [ (',' test)+ [','] ] | [ test (',' test)* [','] ] )
+del_stmt: 'del' exprlist
+pass_stmt: 'pass'
+flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt
+break_stmt: 'break'
+continue_stmt: 'continue'
+return_stmt: 'return' [testlist]
+yield_stmt: 'yield' testlist
+raise_stmt: 'raise' [test [',' test [',' test]]]
+import_stmt: import_name | import_from
+import_name: 'import' dotted_as_names
+import_from: 'from' dotted_name 'import' ('*' | '(' import_as_names [','] ')' | import_as_names)
+import_as_name: NAME [NAME NAME]
+dotted_as_name: dotted_name [NAME NAME]
+import_as_names: import_as_name (',' import_as_name)*
+dotted_as_names: dotted_as_name (',' dotted_as_name)*
+dotted_name: NAME ('.' NAME)*
+global_stmt: 'global' NAME (',' NAME)*
+exec_stmt: 'exec' expr ['in' test [',' test]]
+assert_stmt: 'assert' test [',' test]
+
+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)
+# NB compile.c makes sure that the default except clause is last
+except_clause: 'except' [test [',' test]]
+suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT
+
+# Backward compatibility cruft to support:
+# [ x for x in lambda: True, lambda: False if x() ]
+# even while also allowing:
+# lambda x: 5 if x else 2
+# (But not a mix of the two)
+testlist_safe: old_test [(',' old_test)+ [',']]
+old_test: or_test | old_lambdef
+old_lambdef: 'lambda' [varargslist] ':' old_test
+
+test: or_test ['if' or_test 'else' test] | lambdef
+or_test: and_test ('or' and_test)*
+and_test: not_test ('and' not_test)*
+not_test: 'not' not_test | comparison
+comparison: expr (comp_op expr)*
+comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is' 'not'|'is'
+expr: xor_expr ('|' xor_expr)*
+xor_expr: and_expr ('^' and_expr)*
+and_expr: shift_expr ('&' shift_expr)*
+shift_expr: arith_expr (('<<'|'>>') arith_expr)*
+arith_expr: term (('+'|'-') term)*
+term: factor (('*'|'/'|'%'|'//') factor)*
+factor: ('+'|'-'|'~') factor | power
+power: atom trailer* ['**' factor]
+atom: '(' [testlist_gexp] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}' | '`' testlist1 '`' | NAME | NUMBER | STRING+
+listmaker: test ( list_for | (',' test)* [','] )
+testlist_gexp: test ( gen_for | (',' test)* [','] )
+lambdef: 'lambda' [varargslist] ':' test
+# trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
+trailer: '(' ')' | '(' arglist ')' | '[' subscriptlist ']' | '.' NAME
+subscriptlist: subscript (',' subscript)* [',']
+subscript: '.' '.' '.' | [test] ':' [test] [sliceop] | test
+sliceop: ':' [test]
+exprlist: expr (',' expr)* [',']
+testlist: test (',' test)* [',']
+dictmaker: test ':' test (',' test ':' test)* [',']
+
+classdef: 'class' NAME ['(' testlist ')'] ':' suite
+
+# arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test)
+arglist: (argument ',')* ( '*' test [',' '**' test] | '**' test | argument | [argument ','] )
+argument: [test '='] test [gen_for] # Really [keyword '='] test
+
+list_iter: list_for | list_if
+list_for: 'for' exprlist 'in' testlist_safe [list_iter]
+list_if: 'if' test [list_iter]
+
+gen_iter: gen_for | gen_if
+gen_for: 'for' exprlist 'in' or_test [gen_iter]
+gen_if: 'if' test [gen_iter]
+
+testlist1: test (',' test)*
+
+# not used in grammar, but may appear in "node" passed from Parser to Compiler
+encoding_decl: NAME

Added: pypy/dist/pypy/interpreter/pyparser/data/README
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/interpreter/pyparser/data/README	Tue Feb 28 18:30:05 2006
@@ -0,0 +1,5 @@
+If you modify the grammar, you need to regenerate interpreter/pyparser/symbol.py
+
+Note that you could delete the old grammars, because the stable compiler only
+supports the latest.
+

Modified: pypy/dist/pypy/interpreter/pyparser/ebnfparse.py
==============================================================================
--- pypy/dist/pypy/interpreter/pyparser/ebnfparse.py	(original)
+++ pypy/dist/pypy/interpreter/pyparser/ebnfparse.py	Tue Feb 28 18:30:05 2006
@@ -260,7 +260,7 @@
 
 from pprint import pprint
 if __name__ == "__main__":
-    grambuild = parse_grammar(file('data/Grammar2.3'))
+    grambuild = parse_grammar(file('data/Grammar2.5a'))
     for i,r in enumerate(grambuild.items):
         print "%  3d : %s" % (i, r)
     pprint(grambuild.terminals.keys())

Modified: pypy/dist/pypy/interpreter/pyparser/pysymbol.py
==============================================================================
--- pypy/dist/pypy/interpreter/pyparser/pysymbol.py	(original)
+++ pypy/dist/pypy/interpreter/pyparser/pysymbol.py	Tue Feb 28 18:30:05 2006
@@ -60,7 +60,7 @@
     globals()[_name] = _value
 
     
-
+# (This function does not seen to be called right now)
 def update_symbols( parser ):
     """Update the symbol module according to rules
     in PythonParser instance : parser"""
@@ -70,3 +70,42 @@
 # There is no symbol in this module until the grammar is loaded
 # once loaded the grammar parser will fill the mappings with the
 # grammar symbols
+
+def gen_symbol_file(fname):
+    """
+    Generate a compatible symbol file for symbol.py, using the grammar that has
+    been generated from the grammar in the PyPy parser.  (Note that we assume
+    that the parser generates the tokens deterministically.)
+    """
+
+    import ebnfparse
+    gram = ebnfparse.parse_grammar( file(fname) )
+
+    import os.path
+    f = open(os.path.join(os.path.dirname(__file__), 'symbol.py'), 'w')
+    print >> f, """
+#  This file is automatically generated; please don't muck it up!
+#
+#  To update the symbols in this file, call this function from python_grammar()
+#  and call PyPy.
+"""
+    for k, v in gram.symbols.sym_name.iteritems():
+        if k >= 0:
+            print >> f, '%s = %s' % (v, k)
+
+    print >> f, """
+
+# Generate sym_name
+sym_name = {}
+for _name, _value in globals().items():
+    if type(_value) is type(0):
+        sym_name[_value] = _name
+"""
+    f.close()
+    
+if __name__ == '__main__':
+    import sys
+    if len(sys.argv) != 2:
+        print 'Call pysymbol with the filename of the python grammar'
+        sys.exit(0)
+    gen_symbol_file(sys.argv[1])

Modified: pypy/dist/pypy/interpreter/pyparser/pythonparse.py
==============================================================================
--- pypy/dist/pypy/interpreter/pyparser/pythonparse.py	(original)
+++ pypy/dist/pypy/interpreter/pyparser/pythonparse.py	Tue Feb 28 18:30:05 2006
@@ -48,7 +48,7 @@
         goalnumber = pysymbol._cpython_symbols.sym_values[goal]
         target = self.rules[goalnumber]
         src = Source(lines, flags)
-    
+
         result = target.match(src, builder)
         if not result:
             line, lineno = src.debug()
@@ -56,7 +56,7 @@
             raise SyntaxError("invalid syntax", lineno, -1, line)
             # return None
         return builder
-    
+
 _recode_to_utf8 = gateway.applevel(r'''
     def _recode_to_utf8(text, encoding):
         return unicode(text, encoding).encode("utf-8")
@@ -96,7 +96,7 @@
     if eol2 < 0:
         return _check_line_for_encoding(s[eol + 1:])
     return _check_line_for_encoding(s[eol + 1:eol2])
-    
+
 def _check_line_for_encoding(line):
     """returns the declared encoding or None"""
     i = 0
@@ -112,7 +112,7 @@
     """returns the python grammar corresponding to our CPython version"""
     if version == "native":
         _ver = PYTHON_VERSION
-    elif version in ("2.3","2.4"):
+    elif version in ("2.3","2.4","2.5a"):
         _ver = version
     return os.path.join( os.path.dirname(__file__), "data", "Grammar" + _ver ), _ver
 
@@ -141,7 +141,7 @@
 def parse_file_input(pyf, gram, builder ):
     """Parse a python file"""
     return gram.parse_source( pyf.read(), "file_input", builder )
-    
+
 def parse_single_input(textsrc, gram, builder ):
     """Parse a python single statement"""
     return gram.parse_source( textsrc, "single_input", builder )
@@ -157,4 +157,4 @@
 
 def make_rule( space, w_rule ):
     rule = space.str_w( w_rule )
-    
+

Modified: pypy/dist/pypy/interpreter/pyparser/symbol.py
==============================================================================
--- pypy/dist/pypy/interpreter/pyparser/symbol.py	(original)
+++ pypy/dist/pypy/interpreter/pyparser/symbol.py	Tue Feb 28 18:30:05 2006
@@ -1,15 +1,9 @@
-#! /usr/bin/env python
-
-"""Non-terminal symbols of Python grammar (from "graminit.h")."""
 
 #  This file is automatically generated; please don't muck it up!
 #
-#  To update the symbols in this file, 'cd' to the top directory of
-#  the python source tree after building the interpreter and run:
-#
-#    python Lib/symbol.py
+#  To update the symbols in this file, call this function from python_grammar()
+#  and call PyPy.
 
-#--start constants--
 single_input = 256
 file_input = 257
 eval_input = 258
@@ -88,20 +82,14 @@
 gen_if = 331
 testlist1 = 332
 encoding_decl = 333
-#--end constants--
+old_test = 334
+or_test = 335
+old_lambdef = 336
+
 
+# Generate sym_name
 sym_name = {}
 for _name, _value in globals().items():
     if type(_value) is type(0):
         sym_name[_value] = _name
 
-
-def main():
-    import sys
-    import token
-    if len(sys.argv) == 1:
-        sys.argv = sys.argv + ["Include/graminit.h", "Lib/symbol.py"]
-    token.main()
-
-if __name__ == "__main__":
-    main()

Modified: pypy/dist/pypy/interpreter/pyparser/test/test_astbuilder.py
==============================================================================
--- pypy/dist/pypy/interpreter/pyparser/test/test_astbuilder.py	(original)
+++ pypy/dist/pypy/interpreter/pyparser/test/test_astbuilder.py	Tue Feb 28 18:30:05 2006
@@ -206,8 +206,22 @@
     "[a, (b,c), d] = e",
     "a, (b, c), d = e",
     ]
-EXPECTED["k[v,]"] = "Module(None, Stmt([Discard(Subscript(Name('k'), 2, Tuple([Name('v')])))]))"
-EXPECTED["m[a,b]"] = "Module(None, Stmt([Discard(Subscript(Name('m'), 2, Tuple([Name('a'), Name('b')])))]))"
+
+# We do not export the following tests because we would have to implement 2.5
+# features in the stable compiler (other than just building the AST).
+expressions_inbetweenversions = expressions + [
+    "1 if True else 2",
+    "1 if False else 2",
+    ]
+
+EXPECTED["k[v,]"] = ("Module(None, Stmt([Discard(Subscript(Name('k'), 2, "
+                     "Tuple([Name('v')])))]))")
+EXPECTED["m[a,b]"] = ("Module(None, Stmt([Discard(Subscript(Name('m'), 2, "
+                      "Tuple([Name('a'), Name('b')])))]))")
+EXPECTED["1 if True else 2"] = ("Module(None, Stmt([Discard(CondExpr("
+                                "Name('True'), Const(1), Const(2)))]))")
+EXPECTED["1 if False else 2"] = ("Module(None, Stmt([Discard(CondExpr("
+                                 "Name('False'), Const(1), Const(2)))]))")
 
 funccalls = [
     "l = func()",
@@ -601,7 +615,7 @@
 
 TESTS = [
     constants,
-    expressions,
+    expressions_inbetweenversions,
     augassigns,
     comparisons,
     funccalls,

Modified: pypy/dist/pypy/interpreter/stablecompiler/transformer.py
==============================================================================
--- pypy/dist/pypy/interpreter/stablecompiler/transformer.py	(original)
+++ pypy/dist/pypy/interpreter/stablecompiler/transformer.py	Tue Feb 28 18:30:05 2006
@@ -308,9 +308,12 @@
 
         return Lambda(names, defaults, flags, code, lineno=nodelist[1][2])
 
+    # (This is like lambdef but it uses the old_test instead.)
+    # old_lambdef: 'lambda' [varargslist] ':' old_test
+    old_lambdef = lambdef
+
     def classdef(self, nodelist):
         # classdef: 'class' NAME ['(' testlist ')'] ':' suite
-
         name = nodelist[1][1]
         doc = self.get_docstring(nodelist[-1])
         if nodelist[2][0] == token.COLON:
@@ -579,7 +582,7 @@
 
     def testlist(self, nodelist):
         # testlist: expr (',' expr)* [',']
-        # testlist_safe: test [(',' test)+ [',']]
+        # testlist_safe: old_test [(',' old_test)+ [',']]
         # exprlist: expr (',' expr)* [',']
         return self.com_binary(Tuple, nodelist)
 
@@ -594,15 +597,33 @@
         return self.testlist(nodelist)
 
     def test(self, nodelist):
-        # and_test ('or' and_test)* | lambdef
-        if len(nodelist) == 1 and nodelist[0][0] == symbol.lambdef:
-            return self.lambdef(nodelist[0])
-        return self.com_binary(Or, nodelist)
+        # test: or_test ['if' or_test 'else' test] | lambdef
+        if len(nodelist) == 1:
+            if nodelist[0][0] == symbol.lambdef:
+                return self.lambdef(nodelist[0])
+            else:
+                # Normal or-expression
+                return self.com_node(nodelist[0])
+        else:
+            # Here we implement conditional expressions
+            return ast.CondExpr(nodelist[2], nodelist[0], nodelist[4],
+                                nodelist[1].lineno)
 
     def and_test(self, nodelist):
         # not_test ('and' not_test)*
         return self.com_binary(And, nodelist)
 
+    def old_test(self, nodelist):
+        # old_test: or_test | old_lambdef
+        if len(nodelist) == 1 and nodelist[0][0] == symbol.lambdef:
+            return self.lambdef(nodelist[0])
+        assert len(nodelist) == 1
+        return self.com_node(nodelist[0])
+
+    def or_test(self, nodelist):
+        # or_test: and_test ('or' and_test)*
+        return self.com_binary(Or, nodelist)
+
     def not_test(self, nodelist):
         # 'not' not_test | comparison
         result = self.com_node(nodelist[-1])
@@ -1396,6 +1417,8 @@
     symbol.testlist,
     symbol.testlist_safe,
     symbol.test,
+    symbol.old_test,
+    symbol.or_test,
     symbol.and_test,
     symbol.not_test,
     symbol.comparison,
@@ -1421,54 +1444,10 @@
     token.NOTEQUAL : '!=',
     }
 
-_legal_node_types = [
-    symbol.funcdef,
-    symbol.classdef,
-    symbol.stmt,
-    symbol.small_stmt,
-    symbol.flow_stmt,
-    symbol.simple_stmt,
-    symbol.compound_stmt,
-    symbol.expr_stmt,
-    symbol.print_stmt,
-    symbol.del_stmt,
-    symbol.pass_stmt,
-    symbol.break_stmt,
-    symbol.continue_stmt,
-    symbol.return_stmt,
-    symbol.raise_stmt,
-    symbol.import_stmt,
-    symbol.global_stmt,
-    symbol.exec_stmt,
-    symbol.assert_stmt,
-    symbol.if_stmt,
-    symbol.while_stmt,
-    symbol.for_stmt,
-    symbol.try_stmt,
-    symbol.suite,
-    symbol.testlist,
-    symbol.testlist_safe,
-    symbol.test,
-    symbol.and_test,
-    symbol.not_test,
-    symbol.comparison,
-    symbol.exprlist,
-    symbol.expr,
-    symbol.xor_expr,
-    symbol.and_expr,
-    symbol.shift_expr,
-    symbol.arith_expr,
-    symbol.term,
-    symbol.factor,
-    symbol.power,
-    symbol.atom,
-    ]
-
-if hasattr(symbol, 'yield_stmt'):
-    _legal_node_types.append(symbol.yield_stmt)
-
 _assign_types = [
     symbol.test,
+    symbol.old_test,
+    symbol.or_test,
     symbol.and_test,
     symbol.not_test,
     symbol.comparison,

Modified: pypy/dist/pypy/interpreter/test/test_syntax.py
==============================================================================
--- pypy/dist/pypy/interpreter/test/test_syntax.py	(original)
+++ pypy/dist/pypy/interpreter/test/test_syntax.py	Tue Feb 28 18:30:05 2006
@@ -248,6 +248,15 @@
         raise
 
 
+class AppTestCondExpr:
+
+    def test_condexpr(self):
+        for s, expected in [("x = 1 if True else 2", 1),
+                            ("x = 1 if False else 2", 2)]:
+            exec s
+            assert x == expected
+
+        
 if __name__ == '__main__':
     # only to check on top of CPython (you need 2.4)
     from py.test import raises

Modified: pypy/dist/pypy/tool/option.py
==============================================================================
--- pypy/dist/pypy/tool/option.py	(original)
+++ pypy/dist/pypy/tool/option.py	Tue Feb 28 18:30:05 2006
@@ -16,7 +16,7 @@
          # "ast" uses interpreter/pyparser & interpreter/astcompiler.py 
          # "cpython" uses cpython parser and cpython c-level compiler 
     usemodules = []                        
-    version = "2.4" # "native" / "2.3" / "2.4"
+    version = "2.5a" # "native" / "2.3" / "2.4" / "2.5a"
 
 def run_tb_server(option, opt, value, parser):
     from pypy.tool import tb_server



More information about the Pypy-commit mailing list