Skip to content

Commit f1c2c69

Browse files
committed
compiler: symbol table framework, plus test machinery
1 parent 611c8dc commit f1c2c69

File tree

6 files changed

+535
-9
lines changed

6 files changed

+535
-9
lines changed

‎compile/compile_data_test.go‎

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,7 +1151,7 @@ var compileTestData = []struct{
11511151
Name: "<module>",
11521152
Firstlineno: 1,
11531153
Lnotab: "",
1154-
}, " 1 0 LOAD_CONST 0 (<code object <lambda> at 0x7fe734191db0, file \"<string>\", line 1>)\n 3 LOAD_CONST 1 ('<lambda>')\n 6 MAKE_FUNCTION 0\n 9 RETURN_VALUE\n", nil, ""},
1154+
}, " 1 0 LOAD_CONST 0 (<code object <lambda> at 0x7fd7bccdcdb0, file \"<string>\", line 1>)\n 3 LOAD_CONST 1 ('<lambda>')\n 6 MAKE_FUNCTION 0\n 9 RETURN_VALUE\n", nil, ""},
11551155
{"pass", "exec", &py.Code{
11561156
Argcount: 0,
11571157
Kwonlyargcount: 0,
@@ -1951,7 +1951,7 @@ var compileTestData = []struct{
19511951
Name: "<module>",
19521952
Firstlineno: 1,
19531953
Lnotab: "",
1954-
}, " 1 0 LOAD_CONST 0 (<code object fn at 0x7fe7341918a0, file \"<string>\", line 1>)\n 3 LOAD_CONST 1 ('fn')\n 6 MAKE_FUNCTION 0\n 9 STORE_NAME 0 (fn)\n 12 LOAD_CONST 2 (None)\n 15 RETURN_VALUE\n", nil, ""},
1954+
}, " 1 0 LOAD_CONST 0 (<code object fn at 0x7fd7bccdc8a0, file \"<string>\", line 1>)\n 3 LOAD_CONST 1 ('fn')\n 6 MAKE_FUNCTION 0\n 9 STORE_NAME 0 (fn)\n 12 LOAD_CONST 2 (None)\n 15 RETURN_VALUE\n", nil, ""},
19551955
{"def fn(a): pass", "exec", &py.Code{
19561956
Argcount: 0,
19571957
Kwonlyargcount: 0,
@@ -1984,7 +1984,7 @@ var compileTestData = []struct{
19841984
Name: "<module>",
19851985
Firstlineno: 1,
19861986
Lnotab: "",
1987-
}, " 1 0 LOAD_CONST 0 (<code object fn at 0x7fe73567c6f0, file \"<string>\", line 1>)\n 3 LOAD_CONST 1 ('fn')\n 6 MAKE_FUNCTION 0\n 9 STORE_NAME 0 (fn)\n 12 LOAD_CONST 2 (None)\n 15 RETURN_VALUE\n", nil, ""},
1987+
}, " 1 0 LOAD_CONST 0 (<code object fn at 0x7fd7be1c76f0, file \"<string>\", line 1>)\n 3 LOAD_CONST 1 ('fn')\n 6 MAKE_FUNCTION 0\n 9 STORE_NAME 0 (fn)\n 12 LOAD_CONST 2 (None)\n 15 RETURN_VALUE\n", nil, ""},
19881988
{"def fn(a,b,c): pass", "exec", &py.Code{
19891989
Argcount: 0,
19901990
Kwonlyargcount: 0,
@@ -2017,7 +2017,7 @@ var compileTestData = []struct{
20172017
Name: "<module>",
20182018
Firstlineno: 1,
20192019
Lnotab: "",
2020-
}, " 1 0 LOAD_CONST 0 (<code object fn at 0x7fe734191db0, file \"<string>\", line 1>)\n 3 LOAD_CONST 1 ('fn')\n 6 MAKE_FUNCTION 0\n 9 STORE_NAME 0 (fn)\n 12 LOAD_CONST 2 (None)\n 15 RETURN_VALUE\n", nil, ""},
2020+
}, " 1 0 LOAD_CONST 0 (<code object fn at 0x7fd7bccdcdb0, file \"<string>\", line 1>)\n 3 LOAD_CONST 1 ('fn')\n 6 MAKE_FUNCTION 0\n 9 STORE_NAME 0 (fn)\n 12 LOAD_CONST 2 (None)\n 15 RETURN_VALUE\n", nil, ""},
20212021
{"def fn(a,b=1,c=2): pass", "exec", &py.Code{
20222022
Argcount: 0,
20232023
Kwonlyargcount: 0,
@@ -2050,7 +2050,7 @@ var compileTestData = []struct{
20502050
Name: "<module>",
20512051
Firstlineno: 1,
20522052
Lnotab: "",
2053-
}, " 1 0 LOAD_CONST 0 (1)\n 3 LOAD_CONST 1 (2)\n 6 LOAD_CONST 2 (<code object fn at 0x7fe7341b68a0, file \"<string>\", line 1>)\n 9 LOAD_CONST 3 ('fn')\n 12 MAKE_FUNCTION 2\n 15 STORE_NAME 0 (fn)\n 18 LOAD_CONST 4 (None)\n 21 RETURN_VALUE\n", nil, ""},
2053+
}, " 1 0 LOAD_CONST 0 (1)\n 3 LOAD_CONST 1 (2)\n 6 LOAD_CONST 2 (<code object fn at 0x7fd7bcd028a0, file \"<string>\", line 1>)\n 9 LOAD_CONST 3 ('fn')\n 12 MAKE_FUNCTION 2\n 15 STORE_NAME 0 (fn)\n 18 LOAD_CONST 4 (None)\n 21 RETURN_VALUE\n", nil, ""},
20542054
{"def fn(a,*arg,b=1,c=2): pass", "exec", &py.Code{
20552055
Argcount: 0,
20562056
Kwonlyargcount: 0,
@@ -2083,7 +2083,7 @@ var compileTestData = []struct{
20832083
Name: "<module>",
20842084
Firstlineno: 1,
20852085
Lnotab: "",
2086-
}, " 1 0 LOAD_CONST 0 ('b')\n 3 LOAD_CONST 1 (1)\n 6 LOAD_CONST 2 ('c')\n 9 LOAD_CONST 3 (2)\n 12 LOAD_CONST 4 (<code object fn at 0x7fe7341918a0, file \"<string>\", line 1>)\n 15 LOAD_CONST 5 ('fn')\n 18 MAKE_FUNCTION 512\n 21 STORE_NAME 0 (fn)\n 24 LOAD_CONST 6 (None)\n 27 RETURN_VALUE\n", nil, ""},
2086+
}, " 1 0 LOAD_CONST 0 ('b')\n 3 LOAD_CONST 1 (1)\n 6 LOAD_CONST 2 ('c')\n 9 LOAD_CONST 3 (2)\n 12 LOAD_CONST 4 (<code object fn at 0x7fd7bccdc8a0, file \"<string>\", line 1>)\n 15 LOAD_CONST 5 ('fn')\n 18 MAKE_FUNCTION 512\n 21 STORE_NAME 0 (fn)\n 24 LOAD_CONST 6 (None)\n 27 RETURN_VALUE\n", nil, ""},
20872087
{"def fn(a,*arg,b=1,c=2,**kwargs): pass", "exec", &py.Code{
20882088
Argcount: 0,
20892089
Kwonlyargcount: 0,
@@ -2116,7 +2116,7 @@ var compileTestData = []struct{
21162116
Name: "<module>",
21172117
Firstlineno: 1,
21182118
Lnotab: "",
2119-
}, " 1 0 LOAD_CONST 0 ('b')\n 3 LOAD_CONST 1 (1)\n 6 LOAD_CONST 2 ('c')\n 9 LOAD_CONST 3 (2)\n 12 LOAD_CONST 4 (<code object fn at 0x7fe73567c6f0, file \"<string>\", line 1>)\n 15 LOAD_CONST 5 ('fn')\n 18 MAKE_FUNCTION 512\n 21 STORE_NAME 0 (fn)\n 24 LOAD_CONST 6 (None)\n 27 RETURN_VALUE\n", nil, ""},
2119+
}, " 1 0 LOAD_CONST 0 ('b')\n 3 LOAD_CONST 1 (1)\n 6 LOAD_CONST 2 ('c')\n 9 LOAD_CONST 3 (2)\n 12 LOAD_CONST 4 (<code object fn at 0x7fd7be1c76f0, file \"<string>\", line 1>)\n 15 LOAD_CONST 5 ('fn')\n 18 MAKE_FUNCTION 512\n 21 STORE_NAME 0 (fn)\n 24 LOAD_CONST 6 (None)\n 27 RETURN_VALUE\n", nil, ""},
21202120
{"def fn(a:\"a\",*arg:\"arg\",b:\"b\"=1,c:\"c\"=2,**kwargs:\"kw\") -> \"ret\": pass", "exec", &py.Code{
21212121
Argcount: 0,
21222122
Kwonlyargcount: 0,
@@ -2149,5 +2149,38 @@ var compileTestData = []struct{
21492149
Name: "<module>",
21502150
Firstlineno: 1,
21512151
Lnotab: "",
2152-
}, " 1 0 LOAD_CONST 0 ('b')\n 3 LOAD_CONST 1 (1)\n 6 LOAD_CONST 2 ('c')\n 9 LOAD_CONST 3 (2)\n 12 LOAD_CONST 4 ('a')\n 15 LOAD_CONST 5 ('arg')\n 18 LOAD_CONST 0 ('b')\n 21 LOAD_CONST 2 ('c')\n 24 LOAD_CONST 6 ('kw')\n 27 LOAD_CONST 7 ('ret')\n 30 LOAD_CONST 8 (('a', 'arg', 'b', 'c', 'kwargs', 'return'))\n 33 LOAD_CONST 9 (<code object fn at 0x7fe734191db0, file \"<string>\", line 1>)\n 36 LOAD_CONST 10 ('fn')\n 39 EXTENDED_ARG 7\n 42 MAKE_FUNCTION 459264\n 45 STORE_NAME 0 (fn)\n 48 LOAD_CONST 11 (None)\n 51 RETURN_VALUE\n", nil, ""},
2152+
}, " 1 0 LOAD_CONST 0 ('b')\n 3 LOAD_CONST 1 (1)\n 6 LOAD_CONST 2 ('c')\n 9 LOAD_CONST 3 (2)\n 12 LOAD_CONST 4 ('a')\n 15 LOAD_CONST 5 ('arg')\n 18 LOAD_CONST 0 ('b')\n 21 LOAD_CONST 2 ('c')\n 24 LOAD_CONST 6 ('kw')\n 27 LOAD_CONST 7 ('ret')\n 30 LOAD_CONST 8 (('a', 'arg', 'b', 'c', 'kwargs', 'return'))\n 33 LOAD_CONST 9 (<code object fn at 0x7fd7bccdcdb0, file \"<string>\", line 1>)\n 36 LOAD_CONST 10 ('fn')\n 39 EXTENDED_ARG 7\n 42 MAKE_FUNCTION 459264\n 45 STORE_NAME 0 (fn)\n 48 LOAD_CONST 11 (None)\n 51 RETURN_VALUE\n", nil, ""},
2153+
{"def fn(): a+b", "exec", &py.Code{
2154+
Argcount: 0,
2155+
Kwonlyargcount: 0,
2156+
Nlocals: 0,
2157+
Stacksize: 2,
2158+
Flags: 64,
2159+
Code: "\x64\x00\x00\x64\x01\x00\x84\x00\x00\x5a\x00\x00\x64\x02\x00\x53",
2160+
Consts: []py.Object{&py.Code{
2161+
Argcount: 0,
2162+
Kwonlyargcount: 0,
2163+
Nlocals: 0,
2164+
Stacksize: 2,
2165+
Flags: 67,
2166+
Code: "\x74\x00\x00\x74\x01\x00\x17\x01\x64\x00\x00\x53",
2167+
Consts: []py.Object{py.None},
2168+
Names: []string{"a", "b"},
2169+
Varnames: []string{},
2170+
Freevars: []string{},
2171+
Cellvars: []string{},
2172+
Filename: "<string>",
2173+
Name: "fn",
2174+
Firstlineno: 1,
2175+
Lnotab: "",
2176+
}, py.String("fn"), py.None},
2177+
Names: []string{"fn"},
2178+
Varnames: []string{},
2179+
Freevars: []string{},
2180+
Cellvars: []string{},
2181+
Filename: "<string>",
2182+
Name: "<module>",
2183+
Firstlineno: 1,
2184+
Lnotab: "",
2185+
}, " 1 0 LOAD_CONST 0 (<code object fn at 0x7fd7bcd028a0, file \"<string>\", line 1>)\n 3 LOAD_CONST 1 ('fn')\n 6 MAKE_FUNCTION 0\n 9 STORE_NAME 0 (fn)\n 12 LOAD_CONST 2 (None)\n 15 RETURN_VALUE\n", nil, ""},
21532186
}

‎compile/make_compile_test.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@
164164
('''def fn(a,*arg,b=1,c=2): pass''', "exec"),
165165
('''def fn(a,*arg,b=1,c=2,**kwargs): pass''', "exec"),
166166
('''def fn(a:"a",*arg:"arg",b:"b"=1,c:"c"=2,**kwargs:"kw") -> "ret": pass''', "exec"),
167-
#('''def fn(): a+b''', "exec"),
167+
('''def fn(): a+b''', "exec"),
168168

169169
]
170170

‎compile/make_symtable_test.py‎

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#!/usr/bin/env python3.4
2+
"""
3+
Write symtable_data_test.go
4+
"""
5+
6+
importsys
7+
importast
8+
importsubprocess
9+
importdis
10+
fromsymtableimportsymtable
11+
12+
# FIXME test errors too
13+
14+
inp= [
15+
('''1''', "eval"),
16+
#('''a*b*c''', "eval"),
17+
#('''def fn(): pass''', "exec"),
18+
#('''def fn(a,b):\n e=1\n return a*b*c*d*e''', "exec"),
19+
#('''def fn(a,b):\n def nested(c,d):\n return a*b*c*d*e''', "exec"),
20+
# ('''def fn(a,b,c): pass''', "exec"),
21+
# ('''def fn(a,b=1,c=2): pass''', "exec"),
22+
# ('''def fn(a,*arg,b=1,c=2): pass''', "exec"),
23+
# ('''def fn(a,*arg,b=1,c=2,**kwargs): pass''', "exec"),
24+
# ('''def fn(a:"a",*arg:"arg",b:"b"=1,c:"c"=2,**kwargs:"kw") -> "ret": pass''', "exec"),
25+
# ('''def fn(): a+b''', "exec"),
26+
]
27+
28+
defdump_bool(b):
29+
return ("true"ifbelse"false")
30+
31+
defdump_strings(ss):
32+
return"[]string{"+",".join([ '"%s"'%sforsinss ])+"}"
33+
34+
# Scope numbers to names (from symtable.h)
35+
SCOPES={
36+
1: "scopeLocal",
37+
2: "scopeGlobalExplicit",
38+
3: "scopeGlobalImplicit",
39+
4: "scopeFree",
40+
5: "scopeCell",
41+
}
42+
43+
#def-use flags to names (from symtable.h)
44+
DEF_FLAGS= (
45+
("defGlobal", 1), # global stmt
46+
("defLocal", 2), # assignment in code block
47+
("defParam", 2<<1), # formal parameter
48+
("defNonlocal", 2<<2), # nonlocal stmt
49+
("defUse", 2<<3), # name is used
50+
("defFree", 2<<4), # name used but not defined in nested block
51+
("defFreeClass", 2<<5),# free variable from class's method
52+
("defImport", 2<<6), # assignment occurred via import
53+
)
54+
55+
BLOCK_TYPES={
56+
"function": "FunctionBlock",
57+
"class": "ClassBlock",
58+
"module": "ModuleBlock",
59+
}
60+
61+
defdump_symtable(st):
62+
"""Dump the symtable"""
63+
out="&SymTable{\n"
64+
out+='Type:%s,\n'%BLOCK_TYPES[st.get_type()] # Return the type of the symbol table. Possible values are 'class', 'module', and 'function'.
65+
out+='Name:"%s",\n'%st.get_name() # Return the table’s name. This is the name of the class if the table is for a class, the name of the function if the table is for a function, or 'top' if the table is global (get_type() returns 'module').
66+
67+
out+='Lineno:%s,\n'%st.get_lineno() # Return the number of the first line in the block this table represents.
68+
out+='Optimized:%s,\n'%dump_bool(st.is_optimized()) # Return True if the locals in this table can be optimized.
69+
out+='Nested:%s,\n'%dump_bool(st.is_nested()) # Return True if the block is a nested class or function.
70+
out+='Exec:%s,\n'%dump_bool(st.has_exec()) # Return True if the block uses exec.
71+
out+='ImportStar:%s,\n'%dump_bool(st.has_import_star()) # Return True if the block uses a starred from-import.
72+
out+='Symbols: Symbols{\n'
73+
fornameinst.get_identifiers():
74+
value=st.lookup(name)
75+
out+='"%s":%s,\n'% (name, dump_symbol(value))
76+
out+='},\n'
77+
# out += 'children:"%s",\n' % st.get_children() # Return a list of the nested symbol tables.
78+
out+="}"
79+
returnout
80+
81+
defdump_symbol(s):
82+
"""Dump a symbol"""
83+
#class symtable.Symbol
84+
# An entry in a SymbolTable corresponding to an identifier in the source. The constructor is not public.
85+
out="Symbol{\n"
86+
out+='Name:"%s",\n'%s.get_name() # Return the symbol’s name.
87+
flags= []
88+
flag_bits=s._Symbol__flags
89+
forname, maskinDEF_FLAGS:
90+
if (flag_bits&mask) !=0:
91+
flags.append(name)
92+
ifnotflags:
93+
flags= ["0"]
94+
out+='Flags:%s,\n'%"|".join(flags)
95+
96+
scope=SCOPES.get(s._Symbol__scope, "scopeUnknown")
97+
out+='Scope:%s,\n'%scope
98+
99+
# Return a namespace bound to this name.
100+
ns=s.get_namespaces()
101+
iflen(ns) ==0:
102+
pass
103+
eliflen(ns) ==1:
104+
out+='Namespace:%s,\n'%dump_symtable(ns[0])
105+
else:
106+
raiseAssertionError("More than one namespace")
107+
out+="}"
108+
returnout
109+
110+
defescape(x):
111+
"""Encode strings with backslashes for python/go"""
112+
returnx.replace('\\', "\\\\").replace('"', r'\"').replace("\n", r'\n').replace("\t", r'\t')
113+
114+
defmain():
115+
"""Write symtable_data_test.go"""
116+
path="symtable_data_test.go"
117+
out= ["""// Test data generated by make_symtable_test.py - do not edit
118+
119+
package compile
120+
121+
import (
122+
"github.com/ncw/gpython/py"
123+
)
124+
125+
var symtableTestData = []struct{
126+
in string
127+
mode string // exec, eval or single
128+
out *SymTable
129+
exceptionType *py.Type
130+
errString string
131+
}{"""]
132+
forxininp:
133+
source, mode=x[:2]
134+
iflen(x) >2:
135+
exc=x[2]
136+
try:
137+
table=symtable(source, "<string>", mode)
138+
exceptexcase:
139+
error=e.msg
140+
else:
141+
raiseValueError("Expecting exception %s"%exc)
142+
table="nil"
143+
gostring="nil"
144+
exc_name="py.%s"%exc.__name__
145+
else:
146+
table=symtable(source, "<string>", mode)
147+
exc_name="nil"
148+
error=""
149+
out.append('{"%s", "%s", %s, %s, "%s"},'% (escape(source), mode, dump_symtable(table), exc_name, escape(error)))
150+
out.append("}\n")
151+
print("Writing %s"%path)
152+
withopen(path, "w") asf:
153+
f.write("\n".join(out))
154+
f.write("\n")
155+
subprocess.check_call(["gofmt", "-w", path])
156+
157+
if__name__=="__main__":
158+
main()

0 commit comments

Comments
(0)