fix an ambiguity in the grammar from the implementation of extended unpacking

(one which was strangely "resolved" by pgen)

This also kills the unused testlist1 rule and fixes parse tree validation of
extended unpacking.
This commit is contained in:
Benjamin Peterson 2009-09-27 02:43:28 +00:00
parent 10430ad7aa
commit 4905e80c3d
8 changed files with 1119 additions and 1085 deletions

View File

@ -37,8 +37,9 @@ stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt | small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt |
import_stmt | global_stmt | nonlocal_stmt | assert_stmt) import_stmt | global_stmt | nonlocal_stmt | assert_stmt)
expr_stmt: testlist (augassign (yield_expr|testlist) | expr_stmt: testlist_star_expr (augassign (yield_expr|testlist) |
('=' (yield_expr|testlist))*) ('=' (yield_expr|testlist_star_expr))*)
testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [',']
augassign: ('+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | augassign: ('+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' |
'<<=' | '>>=' | '**=' | '//=') '<<=' | '>>=' | '**=' | '//=')
# For normal assignments, additional restrictions enforced by the interpreter # For normal assignments, additional restrictions enforced by the interpreter
@ -86,9 +87,9 @@ lambdef_nocond: 'lambda' [varargslist] ':' test_nocond
or_test: and_test ('or' and_test)* or_test: and_test ('or' and_test)*
and_test: not_test ('and' not_test)* and_test: not_test ('and' not_test)*
not_test: 'not' not_test | comparison not_test: 'not' not_test | comparison
comparison: star_expr (comp_op star_expr)* comparison: expr (comp_op expr)*
comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not' comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'
star_expr: ['*'] expr star_expr: '*' expr
expr: xor_expr ('|' xor_expr)* expr: xor_expr ('|' xor_expr)*
xor_expr: and_expr ('^' and_expr)* xor_expr: and_expr ('^' and_expr)*
and_expr: shift_expr ('&' shift_expr)* and_expr: shift_expr ('&' shift_expr)*
@ -101,12 +102,12 @@ atom: ('(' [yield_expr|testlist_comp] ')' |
'[' [testlist_comp] ']' | '[' [testlist_comp] ']' |
'{' [dictorsetmaker] '}' | '{' [dictorsetmaker] '}' |
NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False') NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False')
testlist_comp: test ( comp_for | (',' test)* [','] ) testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
subscriptlist: subscript (',' subscript)* [','] subscriptlist: subscript (',' subscript)* [',']
subscript: test | [test] ':' [test] [sliceop] subscript: test | [test] ':' [test] [sliceop]
sliceop: ':' [test] sliceop: ':' [test]
exprlist: star_expr (',' star_expr)* [','] exprlist: (expr|star_expr) (',' (expr|star_expr))* [',']
testlist: test (',' test)* [','] testlist: test (',' test)* [',']
dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) | dictorsetmaker: ( (test ':' test (comp_for | (',' test ':' test)* [','])) |
(test (comp_for | (',' test)* [','])) ) (test (comp_for | (',' test)* [','])) )
@ -123,8 +124,6 @@ comp_iter: comp_for | comp_if
comp_for: 'for' exprlist 'in' or_test [comp_iter] comp_for: 'for' exprlist 'in' or_test [comp_iter]
comp_if: 'if' test_nocond [comp_iter] comp_if: 'if' test_nocond [comp_iter]
testlist1: test (',' test)*
# not used in grammar, but may appear in "node" passed from Parser to Compiler # not used in grammar, but may appear in "node" passed from Parser to Compiler
encoding_decl: NAME encoding_decl: NAME

View File

@ -16,68 +16,68 @@
#define simple_stmt 269 #define simple_stmt 269
#define small_stmt 270 #define small_stmt 270
#define expr_stmt 271 #define expr_stmt 271
#define augassign 272 #define testlist_star_expr 272
#define del_stmt 273 #define augassign 273
#define pass_stmt 274 #define del_stmt 274
#define flow_stmt 275 #define pass_stmt 275
#define break_stmt 276 #define flow_stmt 276
#define continue_stmt 277 #define break_stmt 277
#define return_stmt 278 #define continue_stmt 278
#define yield_stmt 279 #define return_stmt 279
#define raise_stmt 280 #define yield_stmt 280
#define import_stmt 281 #define raise_stmt 281
#define import_name 282 #define import_stmt 282
#define import_from 283 #define import_name 283
#define import_as_name 284 #define import_from 284
#define dotted_as_name 285 #define import_as_name 285
#define import_as_names 286 #define dotted_as_name 286
#define dotted_as_names 287 #define import_as_names 287
#define dotted_name 288 #define dotted_as_names 288
#define global_stmt 289 #define dotted_name 289
#define nonlocal_stmt 290 #define global_stmt 290
#define assert_stmt 291 #define nonlocal_stmt 291
#define compound_stmt 292 #define assert_stmt 292
#define if_stmt 293 #define compound_stmt 293
#define while_stmt 294 #define if_stmt 294
#define for_stmt 295 #define while_stmt 295
#define try_stmt 296 #define for_stmt 296
#define with_stmt 297 #define try_stmt 297
#define with_item 298 #define with_stmt 298
#define except_clause 299 #define with_item 299
#define suite 300 #define except_clause 300
#define test 301 #define suite 301
#define test_nocond 302 #define test 302
#define lambdef 303 #define test_nocond 303
#define lambdef_nocond 304 #define lambdef 304
#define or_test 305 #define lambdef_nocond 305
#define and_test 306 #define or_test 306
#define not_test 307 #define and_test 307
#define comparison 308 #define not_test 308
#define comp_op 309 #define comparison 309
#define star_expr 310 #define comp_op 310
#define expr 311 #define star_expr 311
#define xor_expr 312 #define expr 312
#define and_expr 313 #define xor_expr 313
#define shift_expr 314 #define and_expr 314
#define arith_expr 315 #define shift_expr 315
#define term 316 #define arith_expr 316
#define factor 317 #define term 317
#define power 318 #define factor 318
#define atom 319 #define power 319
#define testlist_comp 320 #define atom 320
#define trailer 321 #define testlist_comp 321
#define subscriptlist 322 #define trailer 322
#define subscript 323 #define subscriptlist 323
#define sliceop 324 #define subscript 324
#define exprlist 325 #define sliceop 325
#define testlist 326 #define exprlist 326
#define dictorsetmaker 327 #define testlist 327
#define classdef 328 #define dictorsetmaker 328
#define arglist 329 #define classdef 329
#define argument 330 #define arglist 330
#define comp_iter 331 #define argument 331
#define comp_for 332 #define comp_iter 332
#define comp_if 333 #define comp_for 333
#define testlist1 334 #define comp_if 334
#define encoding_decl 335 #define encoding_decl 335
#define yield_expr 336 #define yield_expr 336

View File

@ -26,69 +26,69 @@ stmt = 268
simple_stmt = 269 simple_stmt = 269
small_stmt = 270 small_stmt = 270
expr_stmt = 271 expr_stmt = 271
augassign = 272 testlist_star_expr = 272
del_stmt = 273 augassign = 273
pass_stmt = 274 del_stmt = 274
flow_stmt = 275 pass_stmt = 275
break_stmt = 276 flow_stmt = 276
continue_stmt = 277 break_stmt = 277
return_stmt = 278 continue_stmt = 278
yield_stmt = 279 return_stmt = 279
raise_stmt = 280 yield_stmt = 280
import_stmt = 281 raise_stmt = 281
import_name = 282 import_stmt = 282
import_from = 283 import_name = 283
import_as_name = 284 import_from = 284
dotted_as_name = 285 import_as_name = 285
import_as_names = 286 dotted_as_name = 286
dotted_as_names = 287 import_as_names = 287
dotted_name = 288 dotted_as_names = 288
global_stmt = 289 dotted_name = 289
nonlocal_stmt = 290 global_stmt = 290
assert_stmt = 291 nonlocal_stmt = 291
compound_stmt = 292 assert_stmt = 292
if_stmt = 293 compound_stmt = 293
while_stmt = 294 if_stmt = 294
for_stmt = 295 while_stmt = 295
try_stmt = 296 for_stmt = 296
with_stmt = 297 try_stmt = 297
with_item = 298 with_stmt = 298
except_clause = 299 with_item = 299
suite = 300 except_clause = 300
test = 301 suite = 301
test_nocond = 302 test = 302
lambdef = 303 test_nocond = 303
lambdef_nocond = 304 lambdef = 304
or_test = 305 lambdef_nocond = 305
and_test = 306 or_test = 306
not_test = 307 and_test = 307
comparison = 308 not_test = 308
comp_op = 309 comparison = 309
star_expr = 310 comp_op = 310
expr = 311 star_expr = 311
xor_expr = 312 expr = 312
and_expr = 313 xor_expr = 313
shift_expr = 314 and_expr = 314
arith_expr = 315 shift_expr = 315
term = 316 arith_expr = 316
factor = 317 term = 317
power = 318 factor = 318
atom = 319 power = 319
testlist_comp = 320 atom = 320
trailer = 321 testlist_comp = 321
subscriptlist = 322 trailer = 322
subscript = 323 subscriptlist = 323
sliceop = 324 subscript = 324
exprlist = 325 sliceop = 325
testlist = 326 exprlist = 326
dictorsetmaker = 327 testlist = 327
classdef = 328 dictorsetmaker = 328
arglist = 329 classdef = 329
argument = 330 arglist = 330
comp_iter = 331 argument = 331
comp_for = 332 comp_iter = 332
comp_if = 333 comp_for = 333
testlist1 = 334 comp_if = 334
encoding_decl = 335 encoding_decl = 335
yield_expr = 336 yield_expr = 336
#--end constants-- #--end constants--

View File

@ -242,6 +242,12 @@ class RoundtripLegalSyntaxTestCase(unittest.TestCase):
(0, '', 2, -1)], (0, '', 2, -1)],
terminals) terminals)
def test_extended_unpacking(self):
self.check_suite("*a = y")
self.check_suite("x, *b, = m")
self.check_suite("[*a, *b] = y")
self.check_suite("for [*x, b] in x: pass")
# #
# Second, we take *invalid* trees and make sure we get ParserError # Second, we take *invalid* trees and make sure we get ParserError

View File

@ -12,6 +12,8 @@ What's New in Python 3.2 Alpha 1?
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #5460: Fix an ambiguity in the grammar.
- Issue #1766304: Improve performance of membership tests on range objects. - Issue #1766304: Improve performance of membership tests on range objects.
- Issue #6713: Improve performance of integer -> string conversions. - Issue #6713: Improve performance of integer -> string conversions.

View File

@ -943,7 +943,7 @@ VALIDATER(return_stmt); VALIDATER(raise_stmt);
VALIDATER(import_stmt); VALIDATER(import_stmt); VALIDATER(import_stmt); VALIDATER(import_stmt);
VALIDATER(import_name); VALIDATER(yield_stmt); VALIDATER(import_name); VALIDATER(yield_stmt);
VALIDATER(global_stmt); VALIDATER(assert_stmt); VALIDATER(global_stmt); VALIDATER(assert_stmt);
VALIDATER(compound_stmt); VALIDATER(compound_stmt); VALIDATER(test_or_star_expr);
VALIDATER(while); VALIDATER(for); VALIDATER(while); VALIDATER(for);
VALIDATER(try); VALIDATER(except_clause); VALIDATER(try); VALIDATER(except_clause);
VALIDATER(test); VALIDATER(and_test); VALIDATER(test); VALIDATER(and_test);
@ -958,10 +958,10 @@ VALIDATER(trailer); VALIDATER(subscript);
VALIDATER(subscriptlist); VALIDATER(sliceop); VALIDATER(subscriptlist); VALIDATER(sliceop);
VALIDATER(exprlist); VALIDATER(dictorsetmaker); VALIDATER(exprlist); VALIDATER(dictorsetmaker);
VALIDATER(arglist); VALIDATER(argument); VALIDATER(arglist); VALIDATER(argument);
VALIDATER(testlist1); VALIDATER(comp_for); VALIDATER(comp_for);
VALIDATER(comp_iter); VALIDATER(comp_if); VALIDATER(comp_iter); VALIDATER(comp_if);
VALIDATER(testlist_comp); VALIDATER(yield_expr); VALIDATER(testlist_comp); VALIDATER(yield_expr);
VALIDATER(yield_or_testlist); VALIDATER(or_test); VALIDATER(or_test);
VALIDATER(test_nocond); VALIDATER(lambdef_nocond); VALIDATER(test_nocond); VALIDATER(lambdef_nocond);
#undef VALIDATER #undef VALIDATER
@ -1183,12 +1183,11 @@ validate_testlist(node *tree)
validate_test, "testlist")); validate_test, "testlist"));
} }
static int static int
validate_testlist1(node *tree) validate_testlist_star_expr(node *tl)
{ {
return (validate_repeating_list(tree, testlist1, return (validate_repeating_list(tl, testlist_star_expr, validate_test_or_star_expr,
validate_test, "testlist1")); "testlist"));
} }
@ -1516,12 +1515,17 @@ validate_compound_stmt(node *tree)
} }
static int static int
validate_yield_or_testlist(node *tree) validate_yield_or_testlist(node *tree, int tse)
{ {
if (TYPE(tree) == yield_expr) if (TYPE(tree) == yield_expr) {
return validate_yield_expr(tree); return validate_yield_expr(tree);
else }
return validate_testlist(tree); else {
if (tse)
return validate_testlist_star_expr(tree);
else
return validate_testlist(tree);
}
} }
static int static int
@ -1531,12 +1535,12 @@ validate_expr_stmt(node *tree)
int nch = NCH(tree); int nch = NCH(tree);
int res = (validate_ntype(tree, expr_stmt) int res = (validate_ntype(tree, expr_stmt)
&& is_odd(nch) && is_odd(nch)
&& validate_testlist(CHILD(tree, 0))); && validate_testlist_star_expr(CHILD(tree, 0)));
if (res && nch == 3 if (res && nch == 3
&& TYPE(CHILD(tree, 1)) == augassign) { && TYPE(CHILD(tree, 1)) == augassign) {
res = validate_numnodes(CHILD(tree, 1), 1, "augassign") res = validate_numnodes(CHILD(tree, 1), 1, "augassign")
&& validate_yield_or_testlist(CHILD(tree, 2)); && validate_yield_or_testlist(CHILD(tree, 2), 0);
if (res) { if (res) {
char *s = STR(CHILD(CHILD(tree, 1), 0)); char *s = STR(CHILD(CHILD(tree, 1), 0));
@ -1560,7 +1564,7 @@ validate_expr_stmt(node *tree)
else { else {
for (j = 1; res && (j < nch); j += 2) for (j = 1; res && (j < nch); j += 2)
res = validate_equal(CHILD(tree, j)) res = validate_equal(CHILD(tree, j))
&& validate_yield_or_testlist(CHILD(tree, j + 1)); && validate_yield_or_testlist(CHILD(tree, j + 1), 1);
} }
return (res); return (res);
} }
@ -2077,11 +2081,11 @@ validate_comparison(node *tree)
int nch = NCH(tree); int nch = NCH(tree);
int res = (validate_ntype(tree, comparison) int res = (validate_ntype(tree, comparison)
&& is_odd(nch) && is_odd(nch)
&& validate_star_expr(CHILD(tree, 0))); && validate_expr(CHILD(tree, 0)));
for (pos = 1; res && (pos < nch); pos += 2) for (pos = 1; res && (pos < nch); pos += 2)
res = (validate_comp_op(CHILD(tree, pos)) res = (validate_comp_op(CHILD(tree, pos))
&& validate_star_expr(CHILD(tree, pos + 1))); && validate_expr(CHILD(tree, pos + 1)));
return (res); return (res);
} }
@ -2143,12 +2147,10 @@ validate_star_expr(node *tree)
{ {
int res = validate_ntype(tree, star_expr); int res = validate_ntype(tree, star_expr);
if (!res) return res; if (!res) return res;
if (NCH(tree) == 2) { if (!validate_numnodes(tree, 2, "star_expr"))
return validate_ntype(CHILD(tree, 0), STAR) && \ return 0;
validate_expr(CHILD(tree, 1)); return validate_ntype(CHILD(tree, 0), STAR) && \
} else { validate_expr(CHILD(tree, 1));
return validate_expr(CHILD(tree, 0));
}
} }
@ -2379,7 +2381,7 @@ validate_testlist_comp(node *tree)
if (nch == 0) if (nch == 0)
err_string("missing child nodes of testlist_comp"); err_string("missing child nodes of testlist_comp");
else { else {
ok = validate_test(CHILD(tree, 0)); ok = validate_test_or_star_expr(CHILD(tree, 0));
} }
/* /*
@ -2392,7 +2394,7 @@ validate_testlist_comp(node *tree)
int i = 1; int i = 1;
while (ok && nch - i >= 2) { while (ok && nch - i >= 2) {
ok = (validate_comma(CHILD(tree, i)) ok = (validate_comma(CHILD(tree, i))
&& validate_test(CHILD(tree, i+1))); && validate_test_or_star_expr(CHILD(tree, i+1)));
i += 2; i += 2;
} }
if (ok && i == nch-1) if (ok && i == nch-1)
@ -2785,11 +2787,28 @@ validate_sliceop(node *tree)
} }
static int
validate_test_or_star_expr(node *n)
{
if (TYPE(n) == test)
return validate_test(n);
return validate_star_expr(n);
}
static int
validate_expr_or_star_expr(node *n)
{
if (TYPE(n) == expr)
return validate_expr(n);
return validate_star_expr(n);
}
static int static int
validate_exprlist(node *tree) validate_exprlist(node *tree)
{ {
return (validate_repeating_list(tree, exprlist, return (validate_repeating_list(tree, exprlist,
validate_star_expr, "exprlist")); validate_expr_or_star_expr, "exprlist"));
} }
@ -2970,9 +2989,6 @@ validate_node(node *tree)
case yield_expr: case yield_expr:
res = validate_yield_expr(tree); res = validate_yield_expr(tree);
break; break;
case testlist1:
res = validate_testlist1(tree);
break;
case test: case test:
res = validate_test(tree); res = validate_test(tree);
break; break;

View File

@ -603,20 +603,23 @@ ast_for_comp_op(struct compiling *c, const node *n)
static asdl_seq * static asdl_seq *
seq_for_testlist(struct compiling *c, const node *n) seq_for_testlist(struct compiling *c, const node *n)
{ {
/* testlist: test (',' test)* [','] */ /* testlist: test (',' test)* [',']
testlist_star_expr: test|star_expr (',' test|star_expr)* [',']
*/
asdl_seq *seq; asdl_seq *seq;
expr_ty expression; expr_ty expression;
int i; int i;
assert(TYPE(n) == testlist || TYPE(n) == testlist_comp); assert(TYPE(n) == testlist || TYPE(n) == testlist_star_expr || TYPE(n) == testlist_comp);
seq = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); seq = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena);
if (!seq) if (!seq)
return NULL; return NULL;
for (i = 0; i < NCH(n); i += 2) { for (i = 0; i < NCH(n); i += 2) {
assert(TYPE(CHILD(n, i)) == test || TYPE(CHILD(n, i)) == test_nocond); const node *ch = CHILD(n, i);
assert(TYPE(ch) == test || TYPE(ch) == test_nocond || TYPE(ch) == star_expr);
expression = ast_for_expr(c, CHILD(n, i)); expression = ast_for_expr(c, ch);
if (!expression) if (!expression)
return NULL; return NULL;
@ -1886,10 +1889,9 @@ ast_for_expr(struct compiling *c, const node *n)
break; break;
case star_expr: case star_expr:
if (TYPE(CHILD(n, 0)) == STAR) { if (TYPE(CHILD(n, 0)) == STAR)
return ast_for_starred(c, n); return ast_for_starred(c, n);
} /* Fall through to generic case. */
/* Fallthrough */
/* The next five cases all handle BinOps. The main body of code /* The next five cases all handle BinOps. The main body of code
is the same in each case, but the switch turned inside out to is the same in each case, but the switch turned inside out to
reuse the code for each type of operator. reuse the code for each type of operator.
@ -2067,7 +2069,6 @@ ast_for_testlist(struct compiling *c, const node* n)
{ {
/* testlist_comp: test (comp_for | (',' test)* [',']) */ /* testlist_comp: test (comp_for | (',' test)* [',']) */
/* testlist: test (',' test)* [','] */ /* testlist: test (',' test)* [','] */
/* testlist1: test (',' test)* */
assert(NCH(n) > 0); assert(NCH(n) > 0);
if (TYPE(n) == testlist_comp) { if (TYPE(n) == testlist_comp) {
if (NCH(n) > 1) if (NCH(n) > 1)
@ -2075,7 +2076,7 @@ ast_for_testlist(struct compiling *c, const node* n)
} }
else { else {
assert(TYPE(n) == testlist || assert(TYPE(n) == testlist ||
TYPE(n) == testlist1); TYPE(n) == testlist_star_expr);
} }
if (NCH(n) == 1) if (NCH(n) == 1)
return ast_for_expr(c, CHILD(n, 0)); return ast_for_expr(c, CHILD(n, 0));
@ -2091,9 +2092,9 @@ static stmt_ty
ast_for_expr_stmt(struct compiling *c, const node *n) ast_for_expr_stmt(struct compiling *c, const node *n)
{ {
REQ(n, expr_stmt); REQ(n, expr_stmt);
/* expr_stmt: testlist (augassign (yield_expr|testlist) /* expr_stmt: testlist_star_expr (augassign (yield_expr|testlist)
| ('=' (yield_expr|testlist))*) | ('=' (yield_expr|testlist))*)
testlist: test (',' test)* [','] testlist_star_expr: (test|star_expr) (',' test|star_expr)* [',']
augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^='
| '<<=' | '>>=' | '**=' | '//=' | '<<=' | '>>=' | '**=' | '//='
test: ... here starts the operator precendence dance test: ... here starts the operator precendence dance
@ -2161,7 +2162,7 @@ ast_for_expr_stmt(struct compiling *c, const node *n)
asdl_seq_SET(targets, i / 2, e); asdl_seq_SET(targets, i / 2, e);
} }
value = CHILD(n, NCH(n) - 1); value = CHILD(n, NCH(n) - 1);
if (TYPE(value) == testlist) if (TYPE(value) == testlist_star_expr)
expression = ast_for_testlist(c, value); expression = ast_for_testlist(c, value);
else else
expression = ast_for_expr(c, value); expression = ast_for_expr(c, value);

File diff suppressed because it is too large Load Diff