]> granicus.if.org Git - python/commitdiff
follow-up of issue3473: update the compiler package to recognize the new syntax.
authorAmaury Forgeot d'Arc <amauryfa@gmail.com>
Wed, 20 Aug 2008 00:08:47 +0000 (00:08 +0000)
committerAmaury Forgeot d'Arc <amauryfa@gmail.com>
Wed, 20 Aug 2008 00:08:47 +0000 (00:08 +0000)
Lib/compiler/transformer.py
Lib/test/test_compiler.py

index 8c367e2129308aa8e2654cdb35778314f7d306e4..eccade3fd5b423d48a5a4ff4d804627fda2dfcb8 100644 (file)
@@ -1222,12 +1222,27 @@ class Transformer:
             return CallFunc(primaryNode, [], lineno=extractLineNo(nodelist))
         args = []
         kw = 0
+        star_node = dstar_node = None
         len_nodelist = len(nodelist)
-        for i in range(1, len_nodelist, 2):
+        i = 1
+        while i < len_nodelist:
             node = nodelist[i]
-            if node[0] == token.STAR or node[0] == token.DOUBLESTAR:
-                break
-            kw, result = self.com_argument(node, kw)
+
+            if node[0]==token.STAR:
+                if star_node is not None:
+                    raise SyntaxError, 'already have the varargs indentifier'
+                star_node = self.com_node(nodelist[i+1])
+                i = i + 3
+                continue
+            elif node[0]==token.DOUBLESTAR:
+                if dstar_node is not None:
+                    raise SyntaxError, 'already have the kwargs indentifier'
+                dstar_node = self.com_node(nodelist[i+1])
+                i = i + 3
+                continue
+
+            # positional or named parameters
+            kw, result = self.com_argument(node, kw, star_node)
 
             if len_nodelist != 2 and isinstance(result, GenExpr) \
                and len(node) == 3 and node[2][0] == symbol.gen_for:
@@ -1236,37 +1251,20 @@ class Transformer:
                 raise SyntaxError, 'generator expression needs parenthesis'
 
             args.append(result)
-        else:
-            # No broken by star arg, so skip the last one we processed.
-            i = i + 1
-        if i < len_nodelist and nodelist[i][0] == token.COMMA:
-            # need to accept an application that looks like "f(a, b,)"
-            i = i + 1
-        star_node = dstar_node = None
-        while i < len_nodelist:
-            tok = nodelist[i]
-            ch = nodelist[i+1]
-            i = i + 3
-            if tok[0]==token.STAR:
-                if star_node is not None:
-                    raise SyntaxError, 'already have the varargs indentifier'
-                star_node = self.com_node(ch)
-            elif tok[0]==token.DOUBLESTAR:
-                if dstar_node is not None:
-                    raise SyntaxError, 'already have the kwargs indentifier'
-                dstar_node = self.com_node(ch)
-            else:
-                raise SyntaxError, 'unknown node type: %s' % tok
+            i = i + 2
+
         return CallFunc(primaryNode, args, star_node, dstar_node,
                         lineno=extractLineNo(nodelist))
 
-    def com_argument(self, nodelist, kw):
+    def com_argument(self, nodelist, kw, star_node):
         if len(nodelist) == 3 and nodelist[2][0] == symbol.gen_for:
             test = self.com_node(nodelist[1])
             return 0, self.com_generator_expression(test, nodelist[2])
         if len(nodelist) == 2:
             if kw:
                 raise SyntaxError, "non-keyword arg after keyword arg"
+            if star_node:
+                raise SyntaxError, "only named arguments may follow *expression"
             return 0, self.com_node(nodelist[1])
         result = self.com_node(nodelist[3])
         n = nodelist[1]
index 390c4697ee3caacd779c60c85bfb9225ecb5d1cf..c7ec50fe51a667882d27bb906011a35810b25af3 100644 (file)
@@ -64,6 +64,15 @@ class CompilerTest(unittest.TestCase):
     def testYieldExpr(self):
         compiler.compile("def g(): yield\n\n", "<string>", "exec")
 
+    def testKeywordAfterStarargs(self):
+        def f(*args, **kwargs):
+            self.assertEqual((args, kwargs), ((2,3), {'x': 1, 'y': 4}))
+        c = compiler.compile('f(x=1, *(2, 3), y=4)', '<string>', 'exec')
+        exec c in {'f': f}
+
+        self.assertRaises(SyntaxError, compiler.parse, "foo(a=1, b)")
+        self.assertRaises(SyntaxError, compiler.parse, "foo(1, *args, 3)")
+
     def testTryExceptFinally(self):
         # Test that except and finally clauses in one try stmt are recognized
         c = compiler.compile("try:\n 1/0\nexcept:\n e = 1\nfinally:\n f = 1",