Skip to content

Commit 3842c62

Browse files
committed
compiler: Make names work and detect duplicate constants and names
1 parent d7653f2 commit 3842c62

File tree

4 files changed

+88
-4
lines changed

4 files changed

+88
-4
lines changed

compile/compile.go

+21-3
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,28 @@ type compiler struct {
134134
//
135135
// Returns the index into the Consts tuple
136136
func (c *compiler) Const(obj py.Object) uint32 {
137-
// FIXME find an existing one
137+
for i, c := range c.Code.Consts {
138+
if obj.Type() == c.Type() && py.Eq(obj, c) == py.True {
139+
return uint32(i)
140+
}
141+
}
138142
c.Code.Consts = append(c.Code.Consts, obj)
139143
return uint32(len(c.Code.Consts) - 1)
140144
}
141145

146+
// Compiles a python name
147+
//
148+
// Returns the index into the Name tuple
149+
func (c *compiler) Name(Id ast.Identifier) uint32 {
150+
for i, s := range c.Code.Names {
151+
if string(Id) == s {
152+
return uint32(i)
153+
}
154+
}
155+
c.Code.Names = append(c.Code.Names, string(Id))
156+
return uint32(len(c.Code.Names) - 1)
157+
}
158+
142159
// Compiles an instruction with an argument
143160
func (c *compiler) OpArg(Op byte, Arg uint32) {
144161
if !vm.HAS_ARG(Op) {
@@ -375,7 +392,7 @@ func (c *compiler) compileExpr(expr ast.Expr) {
375392
c.compileExpr(node.Body)
376393
c.Jump(vm.JUMP_FORWARD, endifBranch)
377394
c.Label(elseBranch)
378-
c.compileExpr(node.Body)
395+
c.compileExpr(node.Orelse)
379396
c.Label(endifBranch)
380397
case *ast.Dict:
381398
// Keys []Expr
@@ -450,7 +467,8 @@ func (c *compiler) compileExpr(expr ast.Expr) {
450467
case *ast.Name:
451468
// Id Identifier
452469
// Ctx ExprContext
453-
panic("FIXME not implemented")
470+
// FIXME do something with Ctx
471+
c.OpArg(vm.LOAD_NAME, c.Name(node.Id))
454472
case *ast.List:
455473
// Elts []Expr
456474
// Ctx ExprContext

compile/compile_data_test.go

+51
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,23 @@ var compileTestData = []struct {
4646
Firstlineno: 1,
4747
Lnotab: "",
4848
}, " 1 0 LOAD_CONST 0 ('hello')\n 3 RETURN_VALUE\n"},
49+
{"a", "eval", py.Code{
50+
Argcount: 0,
51+
Kwonlyargcount: 0,
52+
Nlocals: 0,
53+
Stacksize: 1,
54+
Flags: 64,
55+
Code: "\x65\x00\x00\x53",
56+
Consts: []py.Object{},
57+
Names: []string{"a"},
58+
Varnames: []string{},
59+
Freevars: []string{},
60+
Cellvars: []string{},
61+
Filename: "<string>",
62+
Name: "<module>",
63+
Firstlineno: 1,
64+
Lnotab: "",
65+
}, " 1 0 LOAD_NAME 0 (a)\n 3 RETURN_VALUE\n"},
4966
{"\"a\"+1", "eval", py.Code{
5067
Argcount: 0,
5168
Kwonlyargcount: 0,
@@ -250,6 +267,40 @@ var compileTestData = []struct {
250267
Firstlineno: 1,
251268
Lnotab: "",
252269
}, " 1 0 LOAD_CONST 0 ('a')\n 3 LOAD_CONST 1 (1)\n 6 BINARY_FLOOR_DIVIDE\n 7 RETURN_VALUE\n"},
270+
{"a+a", "eval", py.Code{
271+
Argcount: 0,
272+
Kwonlyargcount: 0,
273+
Nlocals: 0,
274+
Stacksize: 2,
275+
Flags: 64,
276+
Code: "\x65\x00\x00\x65\x00\x00\x17\x53",
277+
Consts: []py.Object{},
278+
Names: []string{"a"},
279+
Varnames: []string{},
280+
Freevars: []string{},
281+
Cellvars: []string{},
282+
Filename: "<string>",
283+
Name: "<module>",
284+
Firstlineno: 1,
285+
Lnotab: "",
286+
}, " 1 0 LOAD_NAME 0 (a)\n 3 LOAD_NAME 0 (a)\n 6 BINARY_ADD\n 7 RETURN_VALUE\n"},
287+
{"\"a\"*\"a\"", "eval", py.Code{
288+
Argcount: 0,
289+
Kwonlyargcount: 0,
290+
Nlocals: 0,
291+
Stacksize: 2,
292+
Flags: 64,
293+
Code: "\x64\x00\x00\x64\x00\x00\x14\x53",
294+
Consts: []py.Object{py.String("a")},
295+
Names: []string{},
296+
Varnames: []string{},
297+
Freevars: []string{},
298+
Cellvars: []string{},
299+
Filename: "<string>",
300+
Name: "<module>",
301+
Firstlineno: 1,
302+
Lnotab: "",
303+
}, " 1 0 LOAD_CONST 0 ('a')\n 3 LOAD_CONST 0 ('a')\n 6 BINARY_MULTIPLY\n 7 RETURN_VALUE\n"},
253304
{"~ \"a\"", "eval", py.Code{
254305
Argcount: 0,
255306
Kwonlyargcount: 0,

compile/compile_test.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ func EqStrings(t *testing.T, name string, a, b []string) {
2020
}
2121
}
2222

23+
func EqObjs(t *testing.T, name string, a, b []py.Object) {
24+
if len(a) != len(b) {
25+
t.Errorf("%s has differing length, want %v, got %v", name, a, b)
26+
return
27+
}
28+
for i := range a {
29+
if py.Eq(a[i], b[i]) != py.True {
30+
t.Errorf("%v[%d] has differs, want %#v, got %#v", name, i, a, b)
31+
}
32+
}
33+
}
34+
2335
func EqCode(t *testing.T, a, b *py.Code) {
2436
// int32
2537
if a.Argcount != b.Argcount {
@@ -56,7 +68,7 @@ func EqCode(t *testing.T, a, b *py.Code) {
5668
}
5769

5870
// Tuple
59-
// FIXME Consts
71+
EqObjs(t, "Names", a.Consts, b.Consts)
6072

6173
// []string
6274
EqStrings(t, "Names", a.Names, b.Names)

compile/make_compile_test.py

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
inp = [
1212
('''1''', "eval"),
1313
('''"hello"''', "eval"),
14+
('''a''', "eval"),
1415
# BinOps - strange operations to defeat constant optimizer!
1516
('''"a"+1''', "eval"),
1617
('''"a"-1''', "eval"),
@@ -24,6 +25,8 @@
2425
('''"a"^1''', "eval"),
2526
('''"a"&1''', "eval"),
2627
('''"a"//1''', "eval"),
28+
('''a+a''', "eval"),
29+
('''"a"*"a"''', "eval"),
2730
# UnaryOps
2831
('''~ "a"''', "eval"),
2932
('''not "a"''', "eval"),

0 commit comments

Comments
 (0)