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

File tree

9 files changed

+800
-685
lines changed

9 files changed

+800
-685
lines changed

compile/compile_data_test.go

Lines changed: 3 additions & 0 deletions
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

Lines changed: 1 addition & 4 deletions
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

Lines changed: 3 additions & 0 deletions
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

Lines changed: 1 addition & 6 deletions
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

Lines changed: 55 additions & 11 deletions
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

Lines changed: 16 additions & 0 deletions
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

Lines changed: 16 additions & 3 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy