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)
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