Skip to content

Commit 648fc13

Browse files
committed
parser: fix error on setting someting which can't be set, eg f()=1
1 parent 927e70d commit 648fc13

9 files changed

+800
-685
lines changed

compile/compile_data_test.go

+3
Original file line numberDiff line numberDiff line change
@@ -1540,6 +1540,7 @@ var compileTestData = []struct {
15401540
Firstlineno: 1,
15411541
Lnotab: "",
15421542
}, nil, ""},
1543+
{"f() = 1", "exec", nil, py.SyntaxError, "can't assign to function call"},
15431544
{"a+=1", "exec", &py.Code{
15441545
Argcount: 0,
15451546
Kwonlyargcount: 0,
@@ -1761,6 +1762,7 @@ var compileTestData = []struct {
17611762
Firstlineno: 1,
17621763
Lnotab: "",
17631764
}, nil, ""},
1765+
{"f() += 1", "exec", nil, py.SyntaxError, "can't assign to function call"},
17641766
{"del a", "exec", &py.Code{
17651767
Argcount: 0,
17661768
Kwonlyargcount: 0,
@@ -1812,6 +1814,7 @@ var compileTestData = []struct {
18121814
Firstlineno: 1,
18131815
Lnotab: "",
18141816
}, nil, ""},
1817+
{"del f()", "exec", nil, py.SyntaxError, "can't delete function call"},
18151818
{"def fn(b):\n global a\n del a\n c = 1\n def nested(d):\n nonlocal b\n e = b+c+d+e\n f(e)\n del b,c,d,e\n", "exec", &py.Code{
18161819
Argcount: 0,
18171820
Kwonlyargcount: 0,

compile/compile_test.go

+1-4
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,7 @@ func TestCompile(t *testing.T) {
133133
t.Errorf("%s: Got non python exception %T %v", test.in, err, err)
134134
return
135135
} else if exc.Type() != test.exceptionType {
136-
t.Errorf("%s: want exception type %v got %v", test.in, test.exceptionType, exc.Type())
137-
return
138-
} else if exc.Type() != test.exceptionType {
139-
t.Errorf("%s: want exception type %v got %v", test.in, test.exceptionType, exc.Type())
136+
t.Errorf("%s: want exception type %v(%s) got %v(%v)", test.in, test.exceptionType, test.errString, exc.Type(), err)
140137
return
141138
} else {
142139
msg := string(exc.Args.(py.Tuple)[0].(py.String))

compile/make_compile_test.py

+3
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
('''a = 1''', "exec"),
118118
('''a = b = c = 1''', "exec"),
119119
('''a[1] = 1''', "exec"),
120+
('''f() = 1''', "exec", SyntaxError),
120121
# aug assign
121122
('''a+=1''', "exec"),
122123
('''a-=1''', "exec"),
@@ -131,10 +132,12 @@
131132
('''a&=1''', "exec"),
132133
('''a//=1''', "exec"),
133134
('''a[1]+=1''', "exec"),
135+
('''f() += 1''', "exec", SyntaxError),
134136
# delete
135137
('''del a''', "exec"),
136138
('''del a, b''', "exec"),
137139
('''del a[1]''', "exec"),
140+
('''del f()''', "exec", SyntaxError),
138141
('''\
139142
def fn(b):
140143
global a

notes.txt

+1-6
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,11 @@ Code Quality
77
Limitations
88
===========
99
* string keys only in dictionaries
10-
* ints only 64 bit
11-
12-
FIXME interesting crash with compiling `int("42"), sausage=11)`
13-
Compile error: SystemError: [interface conversion: *ast.Call is not ast.SetCtxer: missing method SetCtx]
14-
1510

1611
Todo
1712
====
1813

19-
FIXME move the whole of Vm into Frame! perpahs decode the extended args inline.
14+
FIXME move the whole of Vm into Frame! Perhaps decode the extended args inline.
2015

2116
Speedup
2217
* Make Object a fat interface so it defines all the M__method__ or at least all the common ones

parser/grammar.y

+55-11
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,55 @@ func applyTrailers(expr ast.Expr, trailers []ast.Expr) ast.Expr {
4242
return expr
4343
}
4444

45+
// Set the context for expr
46+
func setCtx(yylex yyLexer, expr ast.Expr, ctx ast.ExprContext) {
47+
setctxer, ok := expr.(ast.SetCtxer)
48+
if !ok {
49+
expr_name := ""
50+
switch expr.(type) {
51+
case *ast.Lambda:
52+
expr_name = "lambda"
53+
case *ast.Call:
54+
expr_name = "function call"
55+
case *ast.BoolOp, *ast.BinOp, *ast.UnaryOp:
56+
expr_name = "operator"
57+
case *ast.GeneratorExp:
58+
expr_name = "generator expression"
59+
case *ast.Yield, *ast.YieldFrom:
60+
expr_name = "yield expression"
61+
case *ast.ListComp:
62+
expr_name = "list comprehension"
63+
case *ast.SetComp:
64+
expr_name = "set comprehension"
65+
case *ast.DictComp:
66+
expr_name = "dict comprehension"
67+
case *ast.Dict, *ast.Set, *ast.Num, *ast.Str, *ast.Bytes:
68+
expr_name = "literal"
69+
case *ast.NameConstant:
70+
expr_name = "keyword"
71+
case *ast.Ellipsis:
72+
expr_name = "Ellipsis"
73+
case *ast.Compare:
74+
expr_name = "comparison"
75+
case *ast.IfExp:
76+
expr_name = "conditional expression"
77+
default:
78+
expr_name = fmt.Sprintf("unexpected %T", expr)
79+
}
80+
action := "assign to"
81+
if ctx == ast.Del {
82+
action = "delete"
83+
}
84+
yylex.(*yyLex).SyntaxErrorf("can't %s %s", action, expr_name)
85+
return
86+
}
87+
setctxer.SetCtx(ctx)
88+
}
89+
4590
// Set the context for all the items in exprs
46-
func setCtx(exprs []ast.Expr, ctx ast.ExprContext) {
91+
func setCtxs(yylex yyLexer, exprs []ast.Expr, ctx ast.ExprContext) {
4792
for i := range exprs {
48-
exprs[i].(ast.SetCtxer).SetCtx(ctx)
93+
setCtx(yylex, exprs[i], ctx)
4994
}
5095
}
5196

@@ -628,7 +673,7 @@ expr_stmt:
628673
testlist_star_expr augassign yield_expr_or_testlist
629674
{
630675
target := $1
631-
target.(ast.SetCtxer).SetCtx(ast.Store)
676+
setCtx(yylex, target, ast.Store)
632677
$$ = &ast.AugAssign{StmtBase: ast.StmtBase{$<pos>$}, Target: target, Op: $2, Value: $3}
633678
}
634679
| testlist_star_expr equals_yield_expr_or_testlist_star_expr
@@ -637,7 +682,7 @@ expr_stmt:
637682
targets = append(targets, $2...)
638683
value := targets[len(targets)-1]
639684
targets = targets[:len(targets)-1]
640-
setCtx(targets, ast.Store)
685+
setCtxs(yylex, targets, ast.Store)
641686
$$ = &ast.Assign{StmtBase: ast.StmtBase{$<pos>$}, Targets: targets, Value: value}
642687
}
643688
| testlist_star_expr
@@ -766,7 +811,7 @@ augassign:
766811
del_stmt:
767812
DEL exprlist
768813
{
769-
setCtx($2, ast.Del)
814+
setCtxs(yylex, $2, ast.Del)
770815
$$ = &ast.Delete{StmtBase: ast.StmtBase{$<pos>$}, Targets: $2}
771816
}
772817

@@ -1101,7 +1146,7 @@ for_stmt:
11011146
FOR exprlist IN testlist ':' suite optional_else
11021147
{
11031148
target := tupleOrExpr($<pos>$, $2, false)
1104-
target.(ast.SetCtxer).SetCtx(ast.Store)
1149+
setCtx(yylex, target, ast.Store)
11051150
$$ = &ast.For{StmtBase: ast.StmtBase{$<pos>$}, Target: target, Iter: $4, Body: $6, Orelse: $7}
11061151
}
11071152

@@ -1158,7 +1203,7 @@ with_item:
11581203
| test AS expr
11591204
{
11601205
v := $3
1161-
v.(ast.SetCtxer).SetCtx(ast.Store)
1206+
setCtx(yylex, v, ast.Store)
11621207
$$ = &ast.WithItem{Pos: $<pos>$, ContextExpr: $1, OptionalVars: v}
11631208
}
11641209

@@ -1334,8 +1379,7 @@ comp_op:
13341379
}
13351380
| LTGT
13361381
{
1337-
// panic("FIXME no coverage")
1338-
yylex.(*yyLex).SyntaxError("Invalid syntax")
1382+
yylex.(*yyLex).SyntaxError("invalid syntax")
13391383
}
13401384
| PLINGEQ
13411385
{
@@ -1891,7 +1935,7 @@ comp_for:
18911935
Target: tupleOrExpr($<pos>$, $2, $<comma>2),
18921936
Iter: $4,
18931937
}
1894-
c.Target.(ast.SetCtxer).SetCtx(ast.Store)
1938+
setCtx(yylex, c.Target, ast.Store)
18951939
$$ = []ast.Comprehension{c}
18961940
}
18971941
| FOR exprlist IN or_test comp_iter
@@ -1901,7 +1945,7 @@ comp_for:
19011945
Iter: $4,
19021946
Ifs: $5,
19031947
}
1904-
c.Target.(ast.SetCtxer).SetCtx(ast.Store)
1948+
setCtx(yylex, c.Target, ast.Store)
19051949
$$ = []ast.Comprehension{c}
19061950
$$ = append($$, $<comprehensions>5...)
19071951
}

parser/grammar_data_test.go

+16
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ var grammarTestData = []struct {
135135
{"a(b,c)", "eval", "Expression(body=Call(func=Name(id='a', ctx=Load()), args=[Name(id='b', ctx=Load()), Name(id='c', ctx=Load())], keywords=[], starargs=None, kwargs=None))", nil, ""},
136136
{"a(b,*c)", "eval", "Expression(body=Call(func=Name(id='a', ctx=Load()), args=[Name(id='b', ctx=Load())], keywords=[], starargs=Name(id='c', ctx=Load()), kwargs=None))", nil, ""},
137137
{"a(*b)", "eval", "Expression(body=Call(func=Name(id='a', ctx=Load()), args=[], keywords=[], starargs=Name(id='b', ctx=Load()), kwargs=None))", nil, ""},
138+
{"a(*b,c)", "eval", "", py.SyntaxError, "only named arguments may follow *expression"},
138139
{"a(b,*c,**d)", "eval", "Expression(body=Call(func=Name(id='a', ctx=Load()), args=[Name(id='b', ctx=Load())], keywords=[], starargs=Name(id='c', ctx=Load()), kwargs=Name(id='d', ctx=Load())))", nil, ""},
139140
{"a(b,**c)", "eval", "Expression(body=Call(func=Name(id='a', ctx=Load()), args=[Name(id='b', ctx=Load())], keywords=[], starargs=None, kwargs=Name(id='c', ctx=Load())))", nil, ""},
140141
{"a(a=b)", "eval", "Expression(body=Call(func=Name(id='a', ctx=Load()), args=[], keywords=[keyword(arg='a', value=Name(id='b', ctx=Load()))], starargs=None, kwargs=None))", nil, ""},
@@ -244,6 +245,7 @@ var grammarTestData = []struct {
244245
{"a **= b", "exec", "Module(body=[AugAssign(target=Name(id='a', ctx=Store()), op=Pow(), value=Name(id='b', ctx=Load()))])", nil, ""},
245246
{"a //= b", "exec", "Module(body=[AugAssign(target=Name(id='a', ctx=Store()), op=FloorDiv(), value=Name(id='b', ctx=Load()))])", nil, ""},
246247
{"a //= yield b", "exec", "Module(body=[AugAssign(target=Name(id='a', ctx=Store()), op=FloorDiv(), value=Yield(value=Name(id='b', ctx=Load())))])", nil, ""},
248+
{"a <> b", "exec", "", py.SyntaxError, "invalid syntax"},
247249
{"a.b += 1", "exec", "Module(body=[AugAssign(target=Attribute(value=Name(id='a', ctx=Load()), attr='b', ctx=Store()), op=Add(), value=Num(n=1))])", nil, ""},
248250
{"a = b", "exec", "Module(body=[Assign(targets=[Name(id='a', ctx=Store())], value=Name(id='b', ctx=Load()))])", nil, ""},
249251
{"a = 007", "exec", "", py.SyntaxError, "illegal decimal with leading zero"},
@@ -253,6 +255,19 @@ var grammarTestData = []struct {
253255
{"a, b = *a", "exec", "Module(body=[Assign(targets=[Tuple(elts=[Name(id='a', ctx=Store()), Name(id='b', ctx=Store())], ctx=Store())], value=Starred(value=Name(id='a', ctx=Load()), ctx=Load()))])", nil, ""},
254256
{"a = yield a", "exec", "Module(body=[Assign(targets=[Name(id='a', ctx=Store())], value=Yield(value=Name(id='a', ctx=Load())))])", nil, ""},
255257
{"a.b = 1", "exec", "Module(body=[Assign(targets=[Attribute(value=Name(id='a', ctx=Load()), attr='b', ctx=Store())], value=Num(n=1))])", nil, ""},
258+
{"f() = 1", "exec", "", py.SyntaxError, "can't assign to function call"},
259+
{"lambda: x = 1", "exec", "", py.SyntaxError, "can't assign to lambda"},
260+
{"(a + b) = 1", "exec", "", py.SyntaxError, "can't assign to operator"},
261+
{"(x for x in xs) = 1", "exec", "", py.SyntaxError, "can't assign to generator expression"},
262+
{"(yield x) = 1", "exec", "", py.SyntaxError, "can't assign to yield expression"},
263+
{"[x for x in xs] = 1", "exec", "", py.SyntaxError, "can't assign to list comprehension"},
264+
{"{x for x in xs} = 1", "exec", "", py.SyntaxError, "can't assign to set comprehension"},
265+
{"{x:x for x in xs} = 1", "exec", "", py.SyntaxError, "can't assign to dict comprehension"},
266+
{"{} = 1", "exec", "", py.SyntaxError, "can't assign to literal"},
267+
{"None = 1", "exec", "", py.SyntaxError, "can't assign to keyword"},
268+
{"... = 1", "exec", "", py.SyntaxError, "can't assign to Ellipsis"},
269+
{"(a < b) = 1", "exec", "", py.SyntaxError, "can't assign to comparison"},
270+
{"(a if b else c) = 1", "exec", "", py.SyntaxError, "can't assign to conditional expression"},
256271
{"lambda: a", "eval", "Expression(body=Lambda(args=arguments(args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=Name(id='a', ctx=Load())))", nil, ""},
257272
{"lambda: lambda: a", "eval", "Expression(body=Lambda(args=arguments(args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=Lambda(args=arguments(args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=Name(id='a', ctx=Load()))))", nil, ""},
258273
{"lambda a: a", "eval", "Expression(body=Lambda(args=arguments(args=[arg(arg='a', annotation=None)], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=Name(id='a', ctx=Load())))", nil, ""},
@@ -284,6 +299,7 @@ var grammarTestData = []struct {
284299
{"def fn(**kws): pass", "exec", "Module(body=[FunctionDef(name='fn', args=arguments(args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=arg(arg='kws', annotation=None), defaults=[]), body=[Pass()], decorator_list=[], returns=None)])", nil, ""},
285300
{"def fn() -> None: pass", "exec", "Module(body=[FunctionDef(name='fn', args=arguments(args=[], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=[Pass()], decorator_list=[], returns=NameConstant(value=None))])", nil, ""},
286301
{"def fn(a:'potato') -> 'sausage': pass", "exec", "Module(body=[FunctionDef(name='fn', args=arguments(args=[arg(arg='a', annotation=Str(s='potato'))], vararg=None, kwonlyargs=[], kw_defaults=[], kwarg=None, defaults=[]), body=[Pass()], decorator_list=[], returns=Str(s='sausage'))])", nil, ""},
302+
{"del f()", "exec", "", py.SyntaxError, "can't delete function call"},
287303
{"class A: pass", "exec", "Module(body=[ClassDef(name='A', bases=[], keywords=[], starargs=None, kwargs=None, body=[Pass()], decorator_list=[])])", nil, ""},
288304
{"class A(): pass", "exec", "Module(body=[ClassDef(name='A', bases=[], keywords=[], starargs=None, kwargs=None, body=[Pass()], decorator_list=[])])", nil, ""},
289305
{"class A(B): pass", "exec", "Module(body=[ClassDef(name='A', bases=[Name(id='B', ctx=Load())], keywords=[], starargs=None, kwargs=None, body=[Pass()], decorator_list=[])])", nil, ""},

parser/make_grammar_test.py

+16-3
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@
151151
("a(b,c)", "eval"),
152152
("a(b,*c)", "eval"),
153153
("a(*b)", "eval"),
154-
#("a(*b,c)", "eval"), -test error
154+
("a(*b,c)", "eval", SyntaxError),
155155
("a(b,*c,**d)", "eval"),
156156
("a(b,**c)", "eval"),
157157
("a(a=b)", "eval"),
@@ -357,7 +357,7 @@
357357
("a **= b", "exec"),
358358
("a //= b", "exec"),
359359
("a //= yield b", "exec"),
360-
# FIXME ("a <> b", "exec"),
360+
("a <> b", "exec", SyntaxError),
361361
('''a.b += 1''', "exec"),
362362

363363
# Assign
@@ -369,7 +369,19 @@
369369
("a, b = *a", "exec"),
370370
("a = yield a", "exec"),
371371
('''a.b = 1''', "exec"),
372-
372+
('''f() = 1''', "exec", SyntaxError),
373+
('''lambda: x = 1''', "exec", SyntaxError),
374+
('''(a + b) = 1''', "exec", SyntaxError),
375+
('''(x for x in xs) = 1''', "exec", SyntaxError),
376+
('''(yield x) = 1''', "exec", SyntaxError),
377+
('''[x for x in xs] = 1''', "exec", SyntaxError),
378+
('''{x for x in xs} = 1''', "exec", SyntaxError),
379+
('''{x:x for x in xs} = 1''', "exec", SyntaxError),
380+
('''{} = 1''', "exec", SyntaxError),
381+
('''None = 1''', "exec", SyntaxError),
382+
('''... = 1''', "exec", SyntaxError),
383+
('''(a < b) = 1''', "exec", SyntaxError),
384+
('''(a if b else c) = 1''', "exec", SyntaxError),
373385

374386
# lambda
375387
("lambda: a", "eval"),
@@ -405,6 +417,7 @@
405417
("def fn(**kws): pass", "exec"),
406418
("def fn() -> None: pass", "exec"),
407419
("def fn(a:'potato') -> 'sausage': pass", "exec"),
420+
("del f()", "exec", SyntaxError),
408421

409422
# class
410423
("class A: pass", "exec"),

0 commit comments

Comments
 (0)