Skip to content

Commit 44e6f63

Browse files
committed
compile: symtable: global and nonlocal
1 parent 5d621d0 commit 44e6f63

File tree

4 files changed

+215
-40
lines changed

4 files changed

+215
-40
lines changed

compile/make_symtable_test.py

+23-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,26 @@ def fn(a:"a",*arg:"arg",b:"b"=1,c:"c"=2,**kwargs:"kw") -> "ret":
2222
def fn(A,b):
2323
e=1
2424
return a*arg*b*c*kwargs*A*e*glob''', "exec"),
25+
('''\
26+
def fn(a):
27+
global b
28+
b = a''', "exec"),
29+
('''\
30+
def fn(a):
31+
b = 6
32+
global b
33+
b = a''', "exec"),
34+
('''\
35+
def outer():
36+
x = 1
37+
def inner():
38+
nonlocal x
39+
x = 2''', "exec"),
40+
('''\
41+
def outer():
42+
def inner():
43+
nonlocal x
44+
x = 2''', "exec", SyntaxError),
2545
# FIXME need with x as y
2646
]
2747

@@ -149,14 +169,15 @@ def main():
149169
error = e.msg
150170
else:
151171
raise ValueError("Expecting exception %s" % exc)
152-
table = "nil"
172+
dumped_symtable = "nil"
153173
gostring = "nil"
154174
exc_name = "py.%s" % exc.__name__
155175
else:
156176
table = symtable(source, "<string>", mode)
157177
exc_name = "nil"
158178
error = ""
159-
out.append('{"%s", "%s", %s, %s, "%s"},' % (escape(source), mode, dump_symtable(table), exc_name, escape(error)))
179+
dumped_symtable = dump_symtable(table)
180+
out.append('{"%s", "%s", %s, %s, "%s"},' % (escape(source), mode, dumped_symtable, exc_name, escape(error)))
160181
out.append("}\n")
161182
print("Writing %s" % path)
162183
with open(path, "w") as f:

compile/symtable.go

+26-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
package compile
1111

1212
import (
13+
"log"
1314
"strings"
1415

1516
"github.com/ncw/gpython/ast"
@@ -153,10 +154,34 @@ func (st *SymTable) Parse(Ast ast.Ast) {
153154
switch node := Ast.(type) {
154155
case *ast.Nonlocal:
155156
for _, name := range node.Names {
157+
cur, ok := st.Symbols[string(name)]
158+
if ok {
159+
if (cur.Flags & defLocal) != 0 {
160+
// FIXME this should be a warning
161+
log.Printf("name '%s' is assigned to before nonlocal declaration", name)
162+
163+
}
164+
if (cur.Flags & defUse) != 0 {
165+
// FIXME this should be a warning
166+
log.Printf("name '%s' is used prior to nonlocal declaration", name)
167+
}
168+
}
156169
st.AddDef(name, defNonlocal)
157170
}
158171
case *ast.Global:
159172
for _, name := range node.Names {
173+
cur, ok := st.Symbols[string(name)]
174+
if ok {
175+
if (cur.Flags & defLocal) != 0 {
176+
// FIXME this should be a warning
177+
log.Printf("name '%s' is assigned to before global declaration", name)
178+
179+
}
180+
if (cur.Flags & defUse) != 0 {
181+
// FIXME this should be a warning
182+
log.Printf("name '%s' is used prior to global declaration", name)
183+
}
184+
}
160185
st.AddDef(name, defGlobal)
161186
}
162187
case *ast.Name:
@@ -449,7 +474,7 @@ func (st *SymTable) AnalyzeName(scopes Scopes, name string, flags DefUse, bound,
449474
if bound == nil {
450475
panic(py.ExceptionNewf(py.SyntaxError, "nonlocal declaration not allowed at module level"))
451476
}
452-
if bound.Contains(name) {
477+
if !bound.Contains(name) {
453478
panic(py.ExceptionNewf(py.SyntaxError, "no binding for nonlocal '%s' found", name))
454479
}
455480
scopes[name] = scopeFree

0 commit comments

Comments
 (0)