Skip to content

Commit e9cde5f

Browse files
wetorsbinet
authored andcommitted
compile,py: fix closure and decorator
1 parent 7102b79 commit e9cde5f

File tree

6 files changed

+466
-55
lines changed

6 files changed

+466
-55
lines changed

compile/compile.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -213,13 +213,17 @@ func (c *compiler) compileAst(Ast ast.Ast, filename string, futureFlags int, don
213213
case *ast.Suite:
214214
panic("suite should not be possible")
215215
case *ast.Lambda:
216+
code.Argcount = int32(len(node.Args.Args))
217+
code.Kwonlyargcount = int32(len(node.Args.Kwonlyargs))
216218
// Make None the first constant as lambda can't have a docstring
217219
c.Const(py.None)
218220
code.Name = "<lambda>"
219221
c.setQualname()
220222
c.Expr(node.Body)
221223
valueOnStack = true
222224
case *ast.FunctionDef:
225+
code.Argcount = int32(len(node.Args.Args))
226+
code.Kwonlyargcount = int32(len(node.Args.Kwonlyargs))
223227
code.Name = string(node.Name)
224228
c.setQualname()
225229
c.Stmts(c.docString(node.Body, true))
@@ -299,6 +303,7 @@ func (c *compiler) compileAst(Ast ast.Ast, filename string, futureFlags int, don
299303
code.Stacksize = int32(c.OpCodes.StackDepth())
300304
code.Nlocals = int32(len(code.Varnames))
301305
code.Lnotab = string(c.OpCodes.Lnotab())
306+
code.InitCell2arg()
302307
return nil
303308
}
304309

@@ -479,7 +484,8 @@ func (c *compiler) makeClosure(code *py.Code, args uint32, child *compiler, qual
479484
if reftype == symtable.ScopeCell {
480485
arg = c.FindId(name, c.Code.Cellvars)
481486
} else { /* (reftype == FREE) */
482-
arg = c.FindId(name, c.Code.Freevars)
487+
// using CellAndFreeVars in closures requires skipping Cellvars
488+
arg = len(c.Code.Cellvars) + c.FindId(name, c.Code.Freevars)
483489
}
484490
if arg < 0 {
485491
panic(fmt.Sprintf("compile: makeClosure: lookup %q in %q %v %v\nfreevars of %q: %v\n", name, c.SymTable.Name, reftype, arg, code.Name, code.Freevars))
@@ -1363,7 +1369,12 @@ func (c *compiler) NameOp(name string, ctx ast.ExprContext) {
13631369
if op == 0 {
13641370
panic("NameOp: Op not set")
13651371
}
1366-
c.OpArg(op, c.Index(mangled, dict))
1372+
i := c.Index(mangled, dict)
1373+
// using CellAndFreeVars in closures requires skipping Cellvars
1374+
if scope == symtable.ScopeFree {
1375+
i += uint32(len(c.Code.Cellvars))
1376+
}
1377+
c.OpArg(op, i)
13671378
}
13681379

13691380
// Call a function which is already on the stack with n arguments already on the stack

py/code.go

+33-28
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,6 @@ func NewCode(argcount int32, kwonlyargcount int32,
112112
filename_ Object, name_ Object, firstlineno int32,
113113
lnotab_ Object) *Code {
114114

115-
var cell2arg []byte
116-
117115
// Type assert the objects
118116
consts := consts_.(Tuple)
119117
namesTuple := names_.(Tuple)
@@ -154,7 +152,6 @@ func NewCode(argcount int32, kwonlyargcount int32,
154152
// return nil;
155153
// }
156154

157-
n_cellvars := len(cellvars)
158155
intern_strings(namesTuple)
159156
intern_strings(varnamesTuple)
160157
intern_strings(freevarsTuple)
@@ -167,13 +164,40 @@ func NewCode(argcount int32, kwonlyargcount int32,
167164
}
168165
}
169166
}
167+
168+
co := &Code{
169+
Argcount: argcount,
170+
Kwonlyargcount: kwonlyargcount,
171+
Nlocals: nlocals,
172+
Stacksize: stacksize,
173+
Flags: flags,
174+
Code: code,
175+
Consts: consts,
176+
Names: names,
177+
Varnames: varnames,
178+
Freevars: freevars,
179+
Cellvars: cellvars,
180+
Filename: filename,
181+
Name: name,
182+
Firstlineno: firstlineno,
183+
Lnotab: lnotab,
184+
Weakreflist: nil,
185+
}
186+
co.InitCell2arg()
187+
return co
188+
}
189+
190+
// Create mapping between cells and arguments if needed.
191+
func (co *Code) InitCell2arg() {
192+
var cell2arg []byte
193+
n_cellvars := len(co.Cellvars)
170194
/* Create mapping between cells and arguments if needed. */
171195
if n_cellvars != 0 {
172-
total_args := argcount + kwonlyargcount
173-
if flags&CO_VARARGS != 0 {
196+
total_args := co.Argcount + co.Kwonlyargcount
197+
if co.Flags&CO_VARARGS != 0 {
174198
total_args++
175199
}
176-
if flags&CO_VARKEYWORDS != 0 {
200+
if co.Flags&CO_VARKEYWORDS != 0 {
177201
total_args++
178202
}
179203
used_cell2arg := false
@@ -182,9 +206,9 @@ func NewCode(argcount int32, kwonlyargcount int32,
182206
cell2arg[i] = CO_CELL_NOT_AN_ARG
183207
}
184208
// Find cells which are also arguments.
185-
for i, cell := range cellvars {
209+
for i, cell := range co.Cellvars {
186210
for j := int32(0); j < total_args; j++ {
187-
arg := varnames[j]
211+
arg := co.Varnames[j]
188212
if cell == arg {
189213
cell2arg[i] = byte(j)
190214
used_cell2arg = true
@@ -196,26 +220,7 @@ func NewCode(argcount int32, kwonlyargcount int32,
196220
cell2arg = nil
197221
}
198222
}
199-
200-
return &Code{
201-
Argcount: argcount,
202-
Kwonlyargcount: kwonlyargcount,
203-
Nlocals: nlocals,
204-
Stacksize: stacksize,
205-
Flags: flags,
206-
Code: code,
207-
Consts: consts,
208-
Names: names,
209-
Varnames: varnames,
210-
Freevars: freevars,
211-
Cellvars: cellvars,
212-
Cell2arg: cell2arg,
213-
Filename: filename,
214-
Name: name,
215-
Firstlineno: firstlineno,
216-
Lnotab: lnotab,
217-
Weakreflist: nil,
218-
}
223+
co.Cell2arg = cell2arg
219224
}
220225

221226
// Return number of free variables

vm/tests/class.py

+11-12
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,16 @@ def method1(self, x):
4747
c = x()
4848
assert c.method1(1) == 2
4949

50-
# FIXME doesn't work
51-
# doc="CLASS_DEREF2"
52-
# def classderef2(x):
53-
# class DeRefTest:
54-
# VAR = x
55-
# def method1(self, x):
56-
# "method1"
57-
# return self.VAR+x
58-
# return DeRefTest
59-
# x = classderef2(1)
60-
# c = x()
61-
# assert c.method1(1) == 2
50+
doc="CLASS_DEREF2"
51+
def classderef2(x):
52+
class DeRefTest:
53+
VAR = x
54+
def method1(self, x):
55+
"method1"
56+
return self.VAR+x
57+
return DeRefTest
58+
x = classderef2(1)
59+
c = x()
60+
assert c.method1(1) == 2
6261

6362
doc="finished"

0 commit comments

Comments
 (0)