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

Lines changed: 13 additions & 2 deletions
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

Lines changed: 33 additions & 28 deletions
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

Lines changed: 11 additions & 12 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy