Skip to content

Commit bbab811

Browse files
committed
compile, symtable, parse: get lineno, offset, file into SyntaxErrors
1 parent 4fc4f37 commit bbab811

File tree

8 files changed

+481
-307
lines changed

8 files changed

+481
-307
lines changed

Diff for: compile/compile.go

+34-18
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// compile python code
22
package compile
33

4-
// FIXME line numbers
54
// FIXME name mangling
65
// FIXME kill ast.Identifier and turn into string?
76

@@ -68,6 +67,7 @@ const (
6867
// State for the compiler
6968
type compiler struct {
7069
Code *py.Code // code being built up
70+
Filename string
7171
OpCodes Instructions
7272
loops loopstack
7373
SymTable *symtable.SymTable
@@ -104,11 +104,12 @@ func Compile(str, filename, mode string, futureFlags int, dont_inherit bool) (py
104104
return nil, err
105105
}
106106
// Make symbol table
107-
SymTable, err := symtable.NewSymTable(Ast)
107+
SymTable, err := symtable.NewSymTable(Ast, filename)
108108
if err != nil {
109109
return nil, err
110110
}
111111
c := newCompiler(nil, compilerScopeModule)
112+
c.Filename = filename
112113
err = c.compileAst(Ast, filename, futureFlags, dont_inherit, SymTable)
113114
if err != nil {
114115
return nil, err
@@ -131,10 +132,18 @@ func newCompiler(parent *compiler, scopeType compilerScopeType) *compiler {
131132
}
132133
if parent != nil {
133134
c.depth = parent.depth + 1
135+
c.Filename = parent.Filename
134136
}
135137
return c
136138
}
137139

140+
// Panics abount a syntax error on this ast node
141+
func (c *compiler) panicSyntaxErrorf(Ast ast.Ast, format string, a ...interface{}) {
142+
err := py.ExceptionNewf(py.SyntaxError, format, a...)
143+
err = py.MakeSyntaxError(err, c.Filename, Ast.GetLineno(), Ast.GetColOffset(), "")
144+
panic(err)
145+
}
146+
138147
// Create a new compiler object at Ast, using private for name mangling
139148
func (c *compiler) newCompilerScope(compilerScope compilerScopeType, Ast ast.Ast, private string) (newC *compiler) {
140149
newSymTable := c.SymTable.FindChild(Ast)
@@ -791,7 +800,7 @@ func (c *compiler) tryExcept(node *ast.Try) {
791800
c.Label(except)
792801
for i, handler := range node.Handlers {
793802
if handler.ExprType == nil && i < n-1 {
794-
panic(py.ExceptionNewf(py.SyntaxError, "default 'except:' must be last"))
803+
c.panicSyntaxErrorf(handler, "default 'except:' must be last")
795804
}
796805
// FIXME c.u.u_lineno_set = 0
797806
// c.u.u_lineno = handler.lineno
@@ -976,7 +985,7 @@ func (c *compiler) Stmt(stmt ast.Stmt) {
976985
case *ast.Return:
977986
// Value Expr
978987
if c.SymTable.Type != symtable.FunctionBlock {
979-
panic(py.ExceptionNewf(py.SyntaxError, "'return' outside function"))
988+
c.panicSyntaxErrorf(node, "'return' outside function")
980989
}
981990
if node.Value != nil {
982991
c.Expr(node.Value)
@@ -1165,15 +1174,15 @@ func (c *compiler) Stmt(stmt ast.Stmt) {
11651174
case *ast.Break:
11661175
l := c.loops.Top()
11671176
if l == nil {
1168-
panic(py.ExceptionNewf(py.SyntaxError, "'break' outside loop"))
1177+
c.panicSyntaxErrorf(node, "'break' outside loop")
11691178
}
11701179
c.Op(vm.BREAK_LOOP)
11711180
case *ast.Continue:
11721181
const loopError = "'continue' not properly in loop"
11731182
const inFinallyError = "'continue' not supported inside 'finally' clause"
11741183
l := c.loops.Top()
11751184
if l == nil {
1176-
panic(py.ExceptionNewf(py.SyntaxError, loopError))
1185+
c.panicSyntaxErrorf(node, loopError)
11771186
}
11781187
switch l.Type {
11791188
case loopLoop:
@@ -1187,15 +1196,15 @@ func (c *compiler) Stmt(stmt ast.Stmt) {
11871196
}
11881197
// Prevent continue anywhere under a finally even if hidden in a sub-try or except.
11891198
if l.Type == finallyEndLoop {
1190-
panic(py.ExceptionNewf(py.SyntaxError, inFinallyError))
1199+
c.panicSyntaxErrorf(node, inFinallyError)
11911200
}
11921201
}
11931202
if i == -1 {
1194-
panic(py.ExceptionNewf(py.SyntaxError, loopError))
1203+
c.panicSyntaxErrorf(node, loopError)
11951204
}
11961205
c.Jump(vm.CONTINUE_LOOP, l.Start)
11971206
case finallyEndLoop:
1198-
panic(py.ExceptionNewf(py.SyntaxError, inFinallyError))
1207+
c.panicSyntaxErrorf(node, inFinallyError)
11991208
default:
12001209
panic("unknown loop type")
12011210
}
@@ -1329,14 +1338,21 @@ func (c *compiler) callHelper(n int, Args []ast.Expr, Keywords []*ast.Keyword, S
13291338
}
13301339
kwargs := len(Keywords)
13311340
duplicateDetector := make(map[ast.Identifier]struct{}, len(Keywords))
1341+
var duplicate *ast.Keyword
13321342
for i := range Keywords {
13331343
kw := Keywords[i]
1334-
duplicateDetector[kw.Arg] = struct{}{}
1344+
if _, found := duplicateDetector[kw.Arg]; found {
1345+
if duplicate == nil {
1346+
duplicate = kw
1347+
}
1348+
} else {
1349+
duplicateDetector[kw.Arg] = struct{}{}
1350+
}
13351351
c.LoadConst(py.String(kw.Arg))
13361352
c.Expr(kw.Value)
13371353
}
1338-
if len(duplicateDetector) != len(Keywords) {
1339-
panic(py.ExceptionNewf(py.SyntaxError, "keyword argument repeated"))
1354+
if duplicate != nil {
1355+
c.panicSyntaxErrorf(duplicate, "keyword argument repeated")
13401356
}
13411357
op := vm.CALL_FUNCTION
13421358
if Starargs != nil {
@@ -1447,14 +1463,14 @@ func (c *compiler) tupleOrList(op vm.OpCode, ctx ast.ExprContext, elts []ast.Exp
14471463
starred, isStarred := elt.(*ast.Starred)
14481464
if isStarred && !seen_star {
14491465
if i >= (1<<8) || n-i-1 >= (INT_MAX>>8) {
1450-
panic(py.ExceptionNewf(py.SyntaxError, "too many expressions in star-unpacking assignment"))
1466+
c.panicSyntaxErrorf(elt, "too many expressions in star-unpacking assignment")
14511467
}
14521468
c.OpArg(vm.UNPACK_EX, uint32((i + ((n - i - 1) << 8))))
14531469
seen_star = true
14541470
// FIXME Overwrite the starred element
14551471
elts[i] = starred.Value
14561472
} else if isStarred {
1457-
panic(py.ExceptionNewf(py.SyntaxError, "two starred expressions in assignment"))
1473+
c.panicSyntaxErrorf(elt, "two starred expressions in assignment")
14581474
}
14591475
}
14601476
if !seen_star {
@@ -1692,7 +1708,7 @@ func (c *compiler) Expr(expr ast.Expr) {
16921708
case *ast.Yield:
16931709
// Value Expr
16941710
if c.SymTable.Type != symtable.FunctionBlock {
1695-
panic(py.ExceptionNewf(py.SyntaxError, "'yield' outside function"))
1711+
c.panicSyntaxErrorf(node, "'yield' outside function")
16961712
}
16971713
if node.Value != nil {
16981714
c.Expr(node.Value)
@@ -1703,7 +1719,7 @@ func (c *compiler) Expr(expr ast.Expr) {
17031719
case *ast.YieldFrom:
17041720
// Value Expr
17051721
if c.SymTable.Type != symtable.FunctionBlock {
1706-
panic(py.ExceptionNewf(py.SyntaxError, "'yield' outside function"))
1722+
c.panicSyntaxErrorf(node, "'yield' outside function")
17071723
}
17081724
c.Expr(node.Value)
17091725
c.Op(vm.GET_ITER)
@@ -1845,9 +1861,9 @@ func (c *compiler) Expr(expr ast.Expr) {
18451861
case ast.Store:
18461862
// In all legitimate cases, the Starred node was already replaced
18471863
// by tupleOrList: is that okay?
1848-
panic(py.ExceptionNewf(py.SyntaxError, "starred assignment target must be in a list or tuple"))
1864+
c.panicSyntaxErrorf(node, "starred assignment target must be in a list or tuple")
18491865
default:
1850-
panic(py.ExceptionNewf(py.SyntaxError, "can use starred expression only as assignment target"))
1866+
c.panicSyntaxErrorf(node, "can use starred expression only as assignment target")
18511867
}
18521868
case *ast.Name:
18531869
// Id Identifier

Diff for: compile/compile_test.go

+14
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,20 @@ func TestCompile(t *testing.T) {
140140
if msg != test.errString {
141141
t.Errorf("%s: want exception text %q got %q", test.in, test.errString, msg)
142142
}
143+
if lineno, ok := exc.Dict["lineno"]; ok {
144+
if lineno.(py.Int) == 0 {
145+
t.Errorf("%s: lineno not set in exception: %v", test.in, exc.Dict)
146+
}
147+
} else {
148+
t.Errorf("%s: lineno not found in exception: %v", test.in, exc.Dict)
149+
}
150+
if filename, ok := exc.Dict["filename"]; ok {
151+
if filename.(py.String) == py.String("") {
152+
t.Errorf("%s: filename not set in exception: %v", test.in, exc.Dict)
153+
}
154+
} else {
155+
t.Errorf("%s: filename not found in exception: %v", test.in, exc.Dict)
156+
}
143157
}
144158
} else {
145159
if test.out == nil {

Diff for: notes.txt

+13
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,22 @@ FIXME recursive types for __repr__ in list, dict, tuple
2727
>>> L
2828
[[...]]
2929

30+
Features
31+
========
32+
33+
* lexes, parses and compiles all the py3 source in the python distribution
34+
35+
find /usr/lib/python3.4 /usr/lib/python3/ -type f -name \*.py | xargs testparser
36+
Failes on /usr/lib/python3/dist-packages/mpmath/usertools.py
37+
- DOS mode problem
38+
3039
Limitations & Missing parts
3140
===========================
3241
* string keys only in dictionaries
3342
* line numbers missing in SyntaxErrors
43+
* now need to show them when printing SyntaxErrors
44+
* line numbers missing in Tracebacks
45+
* lnotab etc
3446
* \N{...} escapes not implemented
3547
* lots of builtins still to implement
3648
* FIXME eq && ne should throw an error for a type which doesn' have eq implemented
@@ -39,6 +51,7 @@ Limitations & Missing parts
3951
* FIXME how do mapping types work?
4052
* PyMapping_Check
4153
* is it just an interface?
54+
* name mangling for private attributes in classes
4255

4356
Type ideas
4457
==========

0 commit comments

Comments
 (0)