diff Modules/parsermodule.c @ 32121:302d399cfd37 legacy-trunk

SF patch #872326: Generator expression implementation (Code contributed by Jiwon Seo.) The documentation portion of the patch is being re-worked and will be checked-in soon. Likewise, PEP 289 will be updated to reflect Guido's rationale for the design decisions on binding behavior (as described in in his patch comments and in discussions on python-dev). The test file, test_genexps.py, is written in doctest format and is meant to exercise all aspects of the the patch. Further additions are welcome from everyone. Please stress test this new feature as much as possible before the alpha release.
author Raymond Hettinger <python@rcn.com>
date Wed, 19 May 2004 08:20:33 +0000
parents 86fdf8fe7f17
children c7e03cf8333e
line wrap: on
line diff
--- a/Modules/parsermodule.c	Tue May 18 18:15:03 2004 +0000
+++ b/Modules/parsermodule.c	Wed May 19 08:20:33 2004 +0000
@@ -855,7 +855,9 @@
 VALIDATER(exprlist);            VALIDATER(dictmaker);
 VALIDATER(arglist);             VALIDATER(argument);
 VALIDATER(listmaker);           VALIDATER(yield_stmt);
-VALIDATER(testlist1);
+VALIDATER(testlist1);           VALIDATER(gen_for);
+VALIDATER(gen_iter);            VALIDATER(gen_if);
+VALIDATER(testlist_gexp);
 
 #undef VALIDATER
 
@@ -1246,6 +1248,21 @@
     return res;
 }
 
+/*  gen_iter:  gen_for | gen_if
+ */
+static int
+validate_gen_iter(node *tree)
+{
+    int res = (validate_ntype(tree, gen_iter)
+               && validate_numnodes(tree, 1, "gen_iter"));
+    if (res && TYPE(CHILD(tree, 0)) == gen_for)
+        res = validate_gen_for(CHILD(tree, 0));
+    else
+        res = validate_gen_if(CHILD(tree, 0));
+
+    return res;
+}
+
 /*  list_for:  'for' exprlist 'in' testlist [list_iter]
  */
 static int
@@ -1268,6 +1285,28 @@
     return res;
 }
 
+/*  gen_for:  'for' exprlist 'in' test [gen_iter]
+ */
+static int
+validate_gen_for(node *tree)
+{
+    int nch = NCH(tree);
+    int res;
+
+    if (nch == 5)
+        res = validate_gen_iter(CHILD(tree, 4));
+    else
+        res = validate_numnodes(tree, 4, "gen_for");
+
+    if (res)
+        res = (validate_name(CHILD(tree, 0), "for")
+               && validate_exprlist(CHILD(tree, 1))
+               && validate_name(CHILD(tree, 2), "in")
+               && validate_test(CHILD(tree, 3)));
+
+    return res;
+}
+
 /*  list_if:  'if' test [list_iter]
  */
 static int
@@ -1288,6 +1327,25 @@
     return res;
 }
 
+/*  gen_if:  'if' test [gen_iter]
+ */
+static int
+validate_gen_if(node *tree)
+{
+    int nch = NCH(tree);
+    int res;
+
+    if (nch == 3)
+        res = validate_gen_iter(CHILD(tree, 2));
+    else
+        res = validate_numnodes(tree, 2, "gen_if");
+    
+    if (res)
+        res = (validate_name(CHILD(tree, 0), "if")
+               && validate_test(CHILD(tree, 1)));
+
+    return res;
+}
 
 /*  validate_fpdef()
  *
@@ -2187,7 +2245,7 @@
                    && (validate_rparen(CHILD(tree, nch - 1))));
 
             if (res && (nch == 3))
-                res = validate_testlist(CHILD(tree, 1));
+                res = validate_testlist_gexp(CHILD(tree, 1));
             break;
           case LSQB:
             if (nch == 2)
@@ -2244,7 +2302,7 @@
         ok = validate_test(CHILD(tree, 0));
 
     /*
-     *  list_iter | (',' test)* [',']
+     *  list_for | (',' test)* [',']
      */
     if (nch == 2 && TYPE(CHILD(tree, 1)) == list_for)
         ok = validate_list_for(CHILD(tree, 1));
@@ -2266,6 +2324,43 @@
     return ok;
 }
 
+/*  testlist_gexp:
+ *    test ( gen_for | (',' test)* [','] )
+ */
+static int
+validate_testlist_gexp(node *tree)
+{
+    int nch = NCH(tree);
+    int ok = nch;
+
+    if (nch == 0)
+        err_string("missing child nodes of testlist_gexp");
+    else {
+        ok = validate_test(CHILD(tree, 0));
+    }
+
+    /*
+     *  gen_for | (',' test)* [',']
+     */
+    if (nch == 2 && TYPE(CHILD(tree, 1)) == gen_for)
+        ok = validate_gen_for(CHILD(tree, 1));
+    else {
+        /*  (',' test)* [',']  */
+        int i = 1;
+        while (ok && nch - i >= 2) {
+            ok = (validate_comma(CHILD(tree, i))
+                  && validate_test(CHILD(tree, i+1)));
+            i += 2;
+        }
+        if (ok && i == nch-1)
+            ok = validate_comma(CHILD(tree, i));
+        else if (i != nch) {
+            ok = 0;
+            err_string("illegal trailing nodes for testlist_gexp");
+        }
+    }
+    return ok;
+}
 
 /*  funcdef:
  *      'def' NAME parameters ':' suite
@@ -2318,6 +2413,18 @@
         /* raise the right error from having an invalid number of children */
         return validate_numnodes(tree, nch + 1, "arglist");
 
+    if (nch > 1) {
+        for (i=0; i<nch; i++) {
+            if (TYPE(CHILD(tree, i)) == argument) {
+                node *ch = CHILD(tree, i);
+                if (NCH(ch) == 2 && TYPE(CHILD(ch, 1)) == gen_for) {
+                    err_string("need '(', ')' for generator expression");
+                    return 0;
+                }
+            }
+        }
+    }
+
     while (ok && nch-i >= 2) {
         /* skip leading (argument ',') */
         ok = (validate_argument(CHILD(tree, i))
@@ -2377,17 +2484,19 @@
 
 /*  argument:
  *
- *  [test '='] test
+ *  [test '='] test [gen_for]
  */
 static int
 validate_argument(node *tree)
 {
     int nch = NCH(tree);
     int res = (validate_ntype(tree, argument)
-               && ((nch == 1) || (nch == 3))
+               && ((nch == 1) || (nch == 2) || (nch == 3))
                && validate_test(CHILD(tree, 0)));
 
-    if (res && (nch == 3))
+    if (res && (nch == 2))
+        res = validate_gen_for(CHILD(tree, 1));
+    else if (res && (nch == 3))
         res = (validate_equal(CHILD(tree, 1))
                && validate_test(CHILD(tree, 2)));