parser support for generator expressions so that we can give a better error message...
authorStefan Behnel <scoder@users.berlios.de>
Thu, 6 May 2010 20:11:25 +0000 (22:11 +0200)
committerStefan Behnel <scoder@users.berlios.de>
Thu, 6 May 2010 20:11:25 +0000 (22:11 +0200)
Cython/Compiler/ExprNodes.py
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/Parsing.py

index 19bd002da9a94eac03b489afaa613bf10816d5c6..7c0edc5bd516fa927ac38dfe4c7a78bb23d6809a 100755 (executable)
@@ -3935,6 +3935,30 @@ class DictComprehensionAppendNode(ComprehensionAppendNode):
              code.error_goto_if(self.result(), self.pos)))
 
 
+class GeneratorExpressionNode(ExprNode):
+    # A generator expression, e.g.  (i for i in range(10))
+    #
+    # Result is a generator.
+    #
+    # loop   ForStatNode   the for-loop, containing a YieldExprNode
+    subexprs = []
+    child_attrs = ["loop"]
+
+    type = py_object_type
+
+    def analyse_declarations(self, env):
+        self.loop.analyse_declarations(env)
+
+    def analyse_types(self, env):
+        self.loop.analyse_expressions(env)
+
+    def may_be_none(self):
+        return False
+
+    def annotate(self, code):
+        self.loop.annotate(code)
+
+
 class SetNode(ExprNode):
     #  Set constructor.
 
@@ -4325,6 +4349,7 @@ class YieldExprNode(ExprNode):
             self.arg.analyse_types(env)
             if not self.arg.type.is_pyobject:
                 self.arg = self.arg.coerce_to_pyobject(env)
+        error(self.pos, "Generators are not supported")
 
     def generate_result_code(self, code):
         self.label_name = code.new_label('resume_from_yield')
index 3c2e74fb405d26e0e2cb1de0e4188d52bb907b38..6d9f8e69ccaef3a3a359be245291ffe069d09c68 100644 (file)
@@ -1030,6 +1030,11 @@ property NAME:
         node.analyse_declarations(self.env_stack[-1])
         return node
 
+    def visit_GeneratorExpressionNode(self, node):
+        self.visitchildren(node)
+        node.analyse_declarations(self.env_stack[-1])
+        return node
+
     # Some nodes are no longer needed after declaration
     # analysis and can be dropped. The analysis was performed
     # on these nodes in a seperate recursive process from the
index e9556efad89319b976575ee7cb38ce0797b1d87c..4fc861f3932c3c9927a9b0a5cb4a625689f2cfdc 100644 (file)
@@ -421,7 +421,10 @@ def p_call(s, function):
             break
         s.next()
 
-    if s.sy == '**':
+    if s.sy == 'for':
+        if len(positional_args) == 1 and not star_arg:
+            positional_args = [ p_genexp(s, positional_args[0]) ]
+    elif s.sy == '**':
         s.next()
         starstar_arg = p_simple_expr(s)
         if s.sy == ',':
@@ -547,7 +550,7 @@ def make_slice_node(pos, start, stop = None, step = None):
     return ExprNodes.SliceNode(pos,
         start = start, stop = stop, step = step)
 
-#atom: '(' [testlist] ')' | '[' [listmaker] ']' | '{' [dict_or_set_maker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+
+#atom: '(' [yield_expr|testlist_comp] ')' | '[' [listmaker] ']' | '{' [dict_or_set_maker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+
 
 def p_atom(s):
     pos = s.position()
@@ -559,7 +562,7 @@ def p_atom(s):
         elif s.sy == 'yield':
             result = p_yield_expression(s)
         else:
-            result = p_expr(s)
+            result = p_testlist_comp(s)
         s.expect(')')
         return result
     elif sy == '[':
@@ -922,7 +925,28 @@ def p_testlist(s):
         return ExprNodes.TupleNode(pos, args = exprs)
     else:
         return expr
-        
+
+# testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
+
+def p_testlist_comp(s):
+    pos = s.position()
+    expr = p_simple_expr(s)
+    if s.sy == ',':
+        exprs = [expr]
+        while s.sy == ',':
+            s.next()
+            exprs.append(p_test(s))
+        return ExprNodes.TupleNode(pos, args = exprs)
+    elif s.sy == 'for':
+        return p_genexp(s, expr)
+    else:
+        return expr
+
+def p_genexp(s, expr):
+    # s.sy == 'for'
+    loop = p_comp_for(s, ExprNodes.YieldExprNode(expr.pos, arg=expr))
+    return ExprNodes.GeneratorExpressionNode(expr.pos, loop=loop)
+
 expr_terminators = (')', ']', '}', ':', '=', 'NEWLINE')
 
 #-------------------------------------------------------