Skip to content

Commit 7686a57

Browse files
committed
compile: finish lambdas including closures
1 parent 5a2a35a commit 7686a57

File tree

3 files changed

+110
-86
lines changed

3 files changed

+110
-86
lines changed

compile/compile.go

Lines changed: 63 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,12 @@ func (c *compiler) compileAst(Ast ast.Ast, filename string, futureFlags int, don
143143
valueOnStack = true
144144
case *ast.Suite:
145145
c.Stmts(node.Body)
146-
case ast.Expr:
146+
case *ast.Lambda:
147147
// Make None the first constant as lambda can't have a docstring
148148
c.Const(py.None)
149149
code.Name = "<lambda>"
150150
c.setQualname() // FIXME is this in the right place!
151-
c.Expr(node)
151+
c.Expr(node.Body)
152152
valueOnStack = true
153153
case *ast.FunctionDef:
154154
code.Name = string(node.Name)
@@ -406,6 +406,65 @@ func (c *compiler) setQualname() {
406406
}
407407
}
408408

409+
// Compile a function
410+
func (c *compiler) compileFunc(Ast ast.Ast, Args *ast.Arguments, DecoratorList []ast.Expr, Returns ast.Expr) {
411+
newSymTable := c.SymTable.FindChild(Ast)
412+
if newSymTable == nil {
413+
panic("No symtable found for function")
414+
}
415+
newC := newCompiler(c, compilerScopeFunction)
416+
code, err := newC.compileAst(Ast, c.Code.Filename, 0, false, newSymTable)
417+
if err != nil {
418+
panic(err)
419+
}
420+
// FIXME need these set in code before we compile - (pass in node?)
421+
code.Argcount = int32(len(Args.Args))
422+
code.Kwonlyargcount = int32(len(Args.Kwonlyargs))
423+
424+
// Defaults
425+
for _, expr := range Args.Defaults {
426+
c.Expr(expr)
427+
}
428+
429+
// KwDefaults
430+
if len(Args.Kwonlyargs) != len(Args.KwDefaults) {
431+
panic("differing number of Kwonlyargs to KwDefaults")
432+
}
433+
for i := range Args.KwDefaults {
434+
c.LoadConst(py.String(Args.Kwonlyargs[i].Arg))
435+
c.Expr(Args.KwDefaults[i])
436+
}
437+
438+
// Annotations
439+
annotations := py.Tuple{}
440+
addAnnotation := func(args ...*ast.Arg) {
441+
for _, arg := range args {
442+
if arg != nil && arg.Annotation != nil {
443+
c.Expr(arg.Annotation)
444+
annotations = append(annotations, py.String(arg.Arg))
445+
}
446+
}
447+
}
448+
addAnnotation(Args.Args...)
449+
addAnnotation(Args.Vararg)
450+
addAnnotation(Args.Kwonlyargs...)
451+
addAnnotation(Args.Kwarg)
452+
if Returns != nil {
453+
c.Expr(Returns)
454+
annotations = append(annotations, py.String("return"))
455+
}
456+
num_annotations := uint32(len(annotations))
457+
if num_annotations > 0 {
458+
num_annotations++ // include the tuple
459+
c.LoadConst(annotations)
460+
}
461+
462+
posdefaults := uint32(len(Args.Defaults))
463+
kwdefaults := uint32(len(Args.KwDefaults))
464+
args := uint32(posdefaults + (kwdefaults << 8) + (num_annotations << 16))
465+
c.makeClosure(code, args, newC)
466+
}
467+
409468
// Compile statement
410469
func (c *compiler) Stmt(stmt ast.Stmt) {
411470
switch node := stmt.(type) {
@@ -415,62 +474,7 @@ func (c *compiler) Stmt(stmt ast.Stmt) {
415474
// Body []Stmt
416475
// DecoratorList []Expr
417476
// Returns Expr
418-
newSymTable := c.SymTable.FindChild(stmt)
419-
if newSymTable == nil {
420-
panic("No symtable found for function")
421-
}
422-
newC := newCompiler(c, compilerScopeFunction)
423-
code, err := newC.compileAst(node, c.Code.Filename, 0, false, newSymTable)
424-
if err != nil {
425-
panic(err)
426-
}
427-
// FIXME need these set in code before we compile - (pass in node?)
428-
code.Argcount = int32(len(node.Args.Args))
429-
code.Name = string(node.Name)
430-
code.Kwonlyargcount = int32(len(node.Args.Kwonlyargs))
431-
432-
// Defaults
433-
posdefaults := uint32(len(node.Args.Defaults))
434-
for _, expr := range node.Args.Defaults {
435-
c.Expr(expr)
436-
}
437-
438-
// KwDefaults
439-
if len(node.Args.Kwonlyargs) != len(node.Args.KwDefaults) {
440-
panic("differing number of Kwonlyargs to KwDefaults")
441-
}
442-
kwdefaults := uint32(len(node.Args.KwDefaults))
443-
for i := range node.Args.KwDefaults {
444-
c.LoadConst(py.String(node.Args.Kwonlyargs[i].Arg))
445-
c.Expr(node.Args.KwDefaults[i])
446-
}
447-
448-
// Annotations
449-
annotations := py.Tuple{}
450-
addAnnotation := func(args ...*ast.Arg) {
451-
for _, arg := range args {
452-
if arg != nil && arg.Annotation != nil {
453-
c.Expr(arg.Annotation)
454-
annotations = append(annotations, py.String(arg.Arg))
455-
}
456-
}
457-
}
458-
addAnnotation(node.Args.Args...)
459-
addAnnotation(node.Args.Vararg)
460-
addAnnotation(node.Args.Kwonlyargs...)
461-
addAnnotation(node.Args.Kwarg)
462-
if node.Returns != nil {
463-
c.Expr(node.Returns)
464-
annotations = append(annotations, py.String("return"))
465-
}
466-
num_annotations := uint32(len(annotations))
467-
if num_annotations > 0 {
468-
num_annotations++ // include the tuple
469-
c.LoadConst(annotations)
470-
}
471-
472-
args := uint32(posdefaults + (kwdefaults << 8) + (num_annotations << 16))
473-
c.makeClosure(code, args, newC)
477+
c.compileFunc(stmt, node.Args, node.DecoratorList, node.Returns)
474478
c.NameOp(string(node.Name), ast.Store)
475479

476480
case *ast.ClassDef:
@@ -899,19 +903,7 @@ func (c *compiler) Expr(expr ast.Expr) {
899903
// Args *Arguments
900904
// Body Expr
901905
// newC := Compiler
902-
newSymTable := c.SymTable.FindChild(expr)
903-
if newSymTable == nil {
904-
panic("No symtable found for lambda")
905-
}
906-
newC := newCompiler(c, compilerScopeLambda)
907-
code, err := newC.compileAst(node.Body, c.Code.Filename, 0, false, newSymTable)
908-
if err != nil {
909-
panic(err)
910-
}
911-
912-
code.Argcount = int32(len(node.Args.Args))
913-
// FIXME node.Args - more work on lambda needed
914-
c.makeClosure(code, 0, newC)
906+
c.compileFunc(expr, node.Args, nil, nil)
915907
case *ast.IfExp:
916908
// Test Expr
917909
// Body Expr

compile/compile_data_test.go

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,39 @@ var compileTestData = []struct {
11841184
Firstlineno: 1,
11851185
Lnotab: "",
11861186
}, nil, ""},
1187+
{"lambda a,b=42,*args,**kw: a*b*args*kw", "eval", &py.Code{
1188+
Argcount: 0,
1189+
Kwonlyargcount: 0,
1190+
Nlocals: 0,
1191+
Stacksize: 3,
1192+
Flags: 64,
1193+
Code: "\x64\x00\x00\x64\x01\x00\x64\x02\x00\x84\x01\x00\x53",
1194+
Consts: []py.Object{py.Int(42), &py.Code{
1195+
Argcount: 2,
1196+
Kwonlyargcount: 0,
1197+
Nlocals: 4,
1198+
Stacksize: 2,
1199+
Flags: 79,
1200+
Code: "\x7c\x00\x00\x7c\x01\x00\x14\x7c\x02\x00\x14\x7c\x03\x00\x14\x53",
1201+
Consts: []py.Object{py.None},
1202+
Names: []string{},
1203+
Varnames: []string{"a", "b", "args", "kw"},
1204+
Freevars: []string{},
1205+
Cellvars: []string{},
1206+
Filename: "<string>",
1207+
Name: "<lambda>",
1208+
Firstlineno: 1,
1209+
Lnotab: "",
1210+
}, py.String("<lambda>")},
1211+
Names: []string{},
1212+
Varnames: []string{},
1213+
Freevars: []string{},
1214+
Cellvars: []string{},
1215+
Filename: "<string>",
1216+
Name: "<module>",
1217+
Firstlineno: 1,
1218+
Lnotab: "",
1219+
}, nil, ""},
11871220
{"pass", "exec", &py.Code{
11881221
Argcount: 0,
11891222
Kwonlyargcount: 0,
@@ -2494,7 +2527,7 @@ var compileTestData = []struct {
24942527
Firstlineno: 1,
24952528
Lnotab: "",
24962529
}, nil, ""},
2497-
{"def outer(o):\n a = 17\n return lambda x: o+a+x", "exec", &py.Code{
2530+
{"def outer(o):\n x = 17\n return lambda a,b=42,*args,**kw: a*b*args*kw*x*o", "exec", &py.Code{
24982531
Argcount: 0,
24992532
Kwonlyargcount: 0,
25002533
Nlocals: 0,
@@ -2505,20 +2538,20 @@ var compileTestData = []struct {
25052538
Argcount: 1,
25062539
Kwonlyargcount: 0,
25072540
Nlocals: 1,
2508-
Stacksize: 3,
2541+
Stacksize: 4,
25092542
Flags: 3,
2510-
Code: "\x64\x01\x00\x89\x00\x00\x87\x00\x00\x87\x01\x00\x66\x02\x00\x64\x02\x00\x64\x03\x00\x86\x00\x00\x53",
2511-
Consts: []py.Object{py.None, py.Int(17), &py.Code{
2512-
Argcount: 1,
2543+
Code: "\x64\x01\x00\x89\x01\x00\x64\x02\x00\x87\x00\x00\x87\x01\x00\x66\x02\x00\x64\x03\x00\x64\x04\x00\x86\x01\x00\x53",
2544+
Consts: []py.Object{py.None, py.Int(17), py.Int(42), &py.Code{
2545+
Argcount: 2,
25132546
Kwonlyargcount: 0,
2514-
Nlocals: 1,
2547+
Nlocals: 4,
25152548
Stacksize: 2,
2516-
Flags: 19,
2517-
Code: "\x88\x01\x00\x88\x00\x00\x17\x7c\x00\x00\x17\x53",
2549+
Flags: 31,
2550+
Code: "\x7c\x00\x00\x7c\x01\x00\x14\x7c\x02\x00\x14\x7c\x03\x00\x14\x88\x01\x00\x14\x88\x00\x00\x14\x53",
25182551
Consts: []py.Object{py.None},
25192552
Names: []string{},
2520-
Varnames: []string{"x"},
2521-
Freevars: []string{"a", "o"},
2553+
Varnames: []string{"a", "b", "args", "kw"},
2554+
Freevars: []string{"o", "x"},
25222555
Cellvars: []string{},
25232556
Filename: "<string>",
25242557
Name: "<lambda>",
@@ -2528,7 +2561,7 @@ var compileTestData = []struct {
25282561
Names: []string{},
25292562
Varnames: []string{"o"},
25302563
Freevars: []string{},
2531-
Cellvars: []string{"a", "o"},
2564+
Cellvars: []string{"o", "x"},
25322565
Filename: "<string>",
25332566
Name: "outer",
25342567
Firstlineno: 1,

compile/make_compile_test.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
# lambda
9494
('''lambda: 0''', "eval"),
9595
('''lambda x: 2*x''', "eval"),
96-
# FIXME ('''lambda x=42: 2*x''', "eval"),
96+
('''lambda a,b=42,*args,**kw: a*b*args*kw''', "eval"),
9797
# pass statment
9898
('''pass''', "exec"),
9999
# expr statement
@@ -191,9 +191,8 @@ def inner2(s):
191191
return inner''', "exec"),
192192
('''\
193193
def outer(o):
194-
a = 17
195-
return lambda x: o+a+x''', "exec"),
196-
194+
x = 17
195+
return lambda a,b=42,*args,**kw: a*b*args*kw*x*o''', "exec"),
197196
]
198197

199198
def string(s):

0 commit comments

Comments
 (0)