Skip to content

Commit 3079681

Browse files
committed
compile: function definitions without body
1 parent a39de11 commit 3079681

File tree

3 files changed

+313
-2
lines changed

3 files changed

+313
-2
lines changed

compile/compile.go

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ func CompileAst(Ast ast.Ast, filename string, flags int, dont_inherit bool) *py.
128128
c.Const(py.None) // FIXME extra None for some reason in Consts
129129
c.Expr(node)
130130
valueOnStack = true
131+
case *ast.FunctionDef:
132+
c.Stmts(node.Body)
131133
default:
132134
panic(py.ExceptionNewf(py.SyntaxError, "Unknown ModuleBase: %v", Ast))
133135
}
@@ -266,7 +268,76 @@ func (c *compiler) Stmt(stmt ast.Stmt) {
266268
// Body []Stmt
267269
// DecoratorList []Expr
268270
// Returns Expr
269-
panic("FIXME compile: FunctionDef not implemented")
271+
code := CompileAst(node, c.Code.Filename, int(c.Code.Flags)|py.CO_OPTIMIZED|py.CO_NEWLOCALS, false) // FIXME pass on compile args
272+
code.Argcount = int32(len(node.Args.Args))
273+
code.Name = string(node.Name)
274+
code.Kwonlyargcount = int32(len(node.Args.Kwonlyargs))
275+
code.Nlocals = code.Kwonlyargcount + int32(len(node.Args.Args))
276+
if code.Kwonlyargcount > 0 {
277+
code.Flags |= py.CO_VARARGS
278+
}
279+
280+
// Arguments
281+
for _, arg := range node.Args.Args {
282+
code.Varnames = append(code.Varnames, string(arg.Arg))
283+
}
284+
for _, arg := range node.Args.Kwonlyargs {
285+
code.Varnames = append(code.Varnames, string(arg.Arg))
286+
}
287+
if node.Args.Vararg != nil {
288+
code.Nlocals++
289+
code.Varnames = append(code.Varnames, string(node.Args.Vararg.Arg))
290+
}
291+
if node.Args.Kwarg != nil {
292+
code.Nlocals++
293+
code.Varnames = append(code.Varnames, string(node.Args.Kwarg.Arg))
294+
code.Flags |= py.CO_VARKEYWORDS
295+
}
296+
297+
// Defaults
298+
posdefaults := uint32(len(node.Args.Defaults))
299+
for _, expr := range node.Args.Defaults {
300+
c.Expr(expr)
301+
}
302+
303+
// KwDefaults
304+
if len(node.Args.Kwonlyargs) != len(node.Args.KwDefaults) {
305+
panic("differing number of Kwonlyargs to KwDefaults")
306+
}
307+
kwdefaults := uint32(len(node.Args.KwDefaults))
308+
for i := range node.Args.KwDefaults {
309+
c.LoadConst(py.String(node.Args.Kwonlyargs[i].Arg))
310+
c.Expr(node.Args.KwDefaults[i])
311+
}
312+
313+
// Annotations
314+
annotations := py.Tuple{}
315+
addAnnotation := func(args ...*ast.Arg) {
316+
for _, arg := range args {
317+
if arg != nil && arg.Annotation != nil {
318+
c.Expr(arg.Annotation)
319+
annotations = append(annotations, py.String(arg.Arg))
320+
}
321+
}
322+
}
323+
addAnnotation(node.Args.Args...)
324+
addAnnotation(node.Args.Vararg)
325+
addAnnotation(node.Args.Kwonlyargs...)
326+
addAnnotation(node.Args.Kwarg)
327+
if node.Returns != nil {
328+
c.Expr(node.Returns)
329+
annotations = append(annotations, py.String("return"))
330+
}
331+
num_annotations := uint32(len(annotations))
332+
if num_annotations > 0 {
333+
num_annotations++ // include the tuple
334+
c.LoadConst(annotations)
335+
}
336+
337+
c.LoadConst(code)
338+
c.LoadConst(py.String(node.Name))
339+
c.OpArg(vm.MAKE_FUNCTION, posdefaults+(kwdefaults<<8)+(num_annotations<<16))
340+
c.OpArg(vm.STORE_NAME, c.Name(node.Name))
270341
case *ast.ClassDef:
271342
// Name Identifier
272343
// Bases []Expr

compile/compile_data_test.go

Lines changed: 232 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1151,7 +1151,7 @@ var compileTestData = []struct {
11511151
Name: "<module>",
11521152
Firstlineno: 1,
11531153
Lnotab: "",
1154-
}, " 1 0 LOAD_CONST 0 (<code object <lambda> at 0x7f94f9f31db0, file \"<string>\", line 1>)\n 3 LOAD_CONST 1 ('<lambda>')\n 6 MAKE_FUNCTION 0\n 9 RETURN_VALUE\n", nil, ""},
1154+
}, " 1 0 LOAD_CONST 0 (<code object <lambda> at 0x7fe734191db0, file \"<string>\", line 1>)\n 3 LOAD_CONST 1 ('<lambda>')\n 6 MAKE_FUNCTION 0\n 9 RETURN_VALUE\n", nil, ""},
11551155
{"pass", "exec", &py.Code{
11561156
Argcount: 0,
11571157
Kwonlyargcount: 0,
@@ -1919,4 +1919,235 @@ var compileTestData = []struct {
19191919
Firstlineno: 1,
19201920
Lnotab: "",
19211921
}, " 1 0 LOAD_NAME 0 (f)\n 3 LOAD_NAME 1 (a)\n 6 LOAD_CONST 0 ('d')\n 9 LOAD_NAME 2 (e)\n 12 LOAD_NAME 3 (kwargs)\n 15 CALL_FUNCTION_KW 257 (1 positional, 1 keyword pair)\n 18 RETURN_VALUE\n", nil, ""},
1922+
{"def fn(): pass", "exec", &py.Code{
1923+
Argcount: 0,
1924+
Kwonlyargcount: 0,
1925+
Nlocals: 0,
1926+
Stacksize: 2,
1927+
Flags: 64,
1928+
Code: "\x64\x00\x00\x64\x01\x00\x84\x00\x00\x5a\x00\x00\x64\x02\x00\x53",
1929+
Consts: []py.Object{&py.Code{
1930+
Argcount: 0,
1931+
Kwonlyargcount: 0,
1932+
Nlocals: 0,
1933+
Stacksize: 1,
1934+
Flags: 67,
1935+
Code: "\x64\x00\x00\x53",
1936+
Consts: []py.Object{py.None},
1937+
Names: []string{},
1938+
Varnames: []string{},
1939+
Freevars: []string{},
1940+
Cellvars: []string{},
1941+
Filename: "<string>",
1942+
Name: "fn",
1943+
Firstlineno: 1,
1944+
Lnotab: "",
1945+
}, py.String("fn"), py.None},
1946+
Names: []string{"fn"},
1947+
Varnames: []string{},
1948+
Freevars: []string{},
1949+
Cellvars: []string{},
1950+
Filename: "<string>",
1951+
Name: "<module>",
1952+
Firstlineno: 1,
1953+
Lnotab: "",
1954+
}, " 1 0 LOAD_CONST 0 (<code object fn at 0x7fe7341918a0, file \"<string>\", line 1>)\n 3 LOAD_CONST 1 ('fn')\n 6 MAKE_FUNCTION 0\n 9 STORE_NAME 0 (fn)\n 12 LOAD_CONST 2 (None)\n 15 RETURN_VALUE\n", nil, ""},
1955+
{"def fn(a): pass", "exec", &py.Code{
1956+
Argcount: 0,
1957+
Kwonlyargcount: 0,
1958+
Nlocals: 0,
1959+
Stacksize: 2,
1960+
Flags: 64,
1961+
Code: "\x64\x00\x00\x64\x01\x00\x84\x00\x00\x5a\x00\x00\x64\x02\x00\x53",
1962+
Consts: []py.Object{&py.Code{
1963+
Argcount: 1,
1964+
Kwonlyargcount: 0,
1965+
Nlocals: 1,
1966+
Stacksize: 1,
1967+
Flags: 67,
1968+
Code: "\x64\x00\x00\x53",
1969+
Consts: []py.Object{py.None},
1970+
Names: []string{},
1971+
Varnames: []string{"a"},
1972+
Freevars: []string{},
1973+
Cellvars: []string{},
1974+
Filename: "<string>",
1975+
Name: "fn",
1976+
Firstlineno: 1,
1977+
Lnotab: "",
1978+
}, py.String("fn"), py.None},
1979+
Names: []string{"fn"},
1980+
Varnames: []string{},
1981+
Freevars: []string{},
1982+
Cellvars: []string{},
1983+
Filename: "<string>",
1984+
Name: "<module>",
1985+
Firstlineno: 1,
1986+
Lnotab: "",
1987+
}, " 1 0 LOAD_CONST 0 (<code object fn at 0x7fe73567c6f0, file \"<string>\", line 1>)\n 3 LOAD_CONST 1 ('fn')\n 6 MAKE_FUNCTION 0\n 9 STORE_NAME 0 (fn)\n 12 LOAD_CONST 2 (None)\n 15 RETURN_VALUE\n", nil, ""},
1988+
{"def fn(a,b,c): pass", "exec", &py.Code{
1989+
Argcount: 0,
1990+
Kwonlyargcount: 0,
1991+
Nlocals: 0,
1992+
Stacksize: 2,
1993+
Flags: 64,
1994+
Code: "\x64\x00\x00\x64\x01\x00\x84\x00\x00\x5a\x00\x00\x64\x02\x00\x53",
1995+
Consts: []py.Object{&py.Code{
1996+
Argcount: 3,
1997+
Kwonlyargcount: 0,
1998+
Nlocals: 3,
1999+
Stacksize: 1,
2000+
Flags: 67,
2001+
Code: "\x64\x00\x00\x53",
2002+
Consts: []py.Object{py.None},
2003+
Names: []string{},
2004+
Varnames: []string{"a", "b", "c"},
2005+
Freevars: []string{},
2006+
Cellvars: []string{},
2007+
Filename: "<string>",
2008+
Name: "fn",
2009+
Firstlineno: 1,
2010+
Lnotab: "",
2011+
}, py.String("fn"), py.None},
2012+
Names: []string{"fn"},
2013+
Varnames: []string{},
2014+
Freevars: []string{},
2015+
Cellvars: []string{},
2016+
Filename: "<string>",
2017+
Name: "<module>",
2018+
Firstlineno: 1,
2019+
Lnotab: "",
2020+
}, " 1 0 LOAD_CONST 0 (<code object fn at 0x7fe734191db0, file \"<string>\", line 1>)\n 3 LOAD_CONST 1 ('fn')\n 6 MAKE_FUNCTION 0\n 9 STORE_NAME 0 (fn)\n 12 LOAD_CONST 2 (None)\n 15 RETURN_VALUE\n", nil, ""},
2021+
{"def fn(a,b=1,c=2): pass", "exec", &py.Code{
2022+
Argcount: 0,
2023+
Kwonlyargcount: 0,
2024+
Nlocals: 0,
2025+
Stacksize: 4,
2026+
Flags: 64,
2027+
Code: "\x64\x00\x00\x64\x01\x00\x64\x02\x00\x64\x03\x00\x84\x02\x00\x5a\x00\x00\x64\x04\x00\x53",
2028+
Consts: []py.Object{py.Int(1), py.Int(2), &py.Code{
2029+
Argcount: 3,
2030+
Kwonlyargcount: 0,
2031+
Nlocals: 3,
2032+
Stacksize: 1,
2033+
Flags: 67,
2034+
Code: "\x64\x00\x00\x53",
2035+
Consts: []py.Object{py.None},
2036+
Names: []string{},
2037+
Varnames: []string{"a", "b", "c"},
2038+
Freevars: []string{},
2039+
Cellvars: []string{},
2040+
Filename: "<string>",
2041+
Name: "fn",
2042+
Firstlineno: 1,
2043+
Lnotab: "",
2044+
}, py.String("fn"), py.None},
2045+
Names: []string{"fn"},
2046+
Varnames: []string{},
2047+
Freevars: []string{},
2048+
Cellvars: []string{},
2049+
Filename: "<string>",
2050+
Name: "<module>",
2051+
Firstlineno: 1,
2052+
Lnotab: "",
2053+
}, " 1 0 LOAD_CONST 0 (1)\n 3 LOAD_CONST 1 (2)\n 6 LOAD_CONST 2 (<code object fn at 0x7fe7341b68a0, file \"<string>\", line 1>)\n 9 LOAD_CONST 3 ('fn')\n 12 MAKE_FUNCTION 2\n 15 STORE_NAME 0 (fn)\n 18 LOAD_CONST 4 (None)\n 21 RETURN_VALUE\n", nil, ""},
2054+
{"def fn(a,*arg,b=1,c=2): pass", "exec", &py.Code{
2055+
Argcount: 0,
2056+
Kwonlyargcount: 0,
2057+
Nlocals: 0,
2058+
Stacksize: 6,
2059+
Flags: 64,
2060+
Code: "\x64\x00\x00\x64\x01\x00\x64\x02\x00\x64\x03\x00\x64\x04\x00\x64\x05\x00\x84\x00\x02\x5a\x00\x00\x64\x06\x00\x53",
2061+
Consts: []py.Object{py.String("b"), py.Int(1), py.String("c"), py.Int(2), &py.Code{
2062+
Argcount: 1,
2063+
Kwonlyargcount: 2,
2064+
Nlocals: 4,
2065+
Stacksize: 1,
2066+
Flags: 71,
2067+
Code: "\x64\x00\x00\x53",
2068+
Consts: []py.Object{py.None},
2069+
Names: []string{},
2070+
Varnames: []string{"a", "b", "c", "arg"},
2071+
Freevars: []string{},
2072+
Cellvars: []string{},
2073+
Filename: "<string>",
2074+
Name: "fn",
2075+
Firstlineno: 1,
2076+
Lnotab: "",
2077+
}, py.String("fn"), py.None},
2078+
Names: []string{"fn"},
2079+
Varnames: []string{},
2080+
Freevars: []string{},
2081+
Cellvars: []string{},
2082+
Filename: "<string>",
2083+
Name: "<module>",
2084+
Firstlineno: 1,
2085+
Lnotab: "",
2086+
}, " 1 0 LOAD_CONST 0 ('b')\n 3 LOAD_CONST 1 (1)\n 6 LOAD_CONST 2 ('c')\n 9 LOAD_CONST 3 (2)\n 12 LOAD_CONST 4 (<code object fn at 0x7fe7341918a0, file \"<string>\", line 1>)\n 15 LOAD_CONST 5 ('fn')\n 18 MAKE_FUNCTION 512\n 21 STORE_NAME 0 (fn)\n 24 LOAD_CONST 6 (None)\n 27 RETURN_VALUE\n", nil, ""},
2087+
{"def fn(a,*arg,b=1,c=2,**kwargs): pass", "exec", &py.Code{
2088+
Argcount: 0,
2089+
Kwonlyargcount: 0,
2090+
Nlocals: 0,
2091+
Stacksize: 6,
2092+
Flags: 64,
2093+
Code: "\x64\x00\x00\x64\x01\x00\x64\x02\x00\x64\x03\x00\x64\x04\x00\x64\x05\x00\x84\x00\x02\x5a\x00\x00\x64\x06\x00\x53",
2094+
Consts: []py.Object{py.String("b"), py.Int(1), py.String("c"), py.Int(2), &py.Code{
2095+
Argcount: 1,
2096+
Kwonlyargcount: 2,
2097+
Nlocals: 5,
2098+
Stacksize: 1,
2099+
Flags: 79,
2100+
Code: "\x64\x00\x00\x53",
2101+
Consts: []py.Object{py.None},
2102+
Names: []string{},
2103+
Varnames: []string{"a", "b", "c", "arg", "kwargs"},
2104+
Freevars: []string{},
2105+
Cellvars: []string{},
2106+
Filename: "<string>",
2107+
Name: "fn",
2108+
Firstlineno: 1,
2109+
Lnotab: "",
2110+
}, py.String("fn"), py.None},
2111+
Names: []string{"fn"},
2112+
Varnames: []string{},
2113+
Freevars: []string{},
2114+
Cellvars: []string{},
2115+
Filename: "<string>",
2116+
Name: "<module>",
2117+
Firstlineno: 1,
2118+
Lnotab: "",
2119+
}, " 1 0 LOAD_CONST 0 ('b')\n 3 LOAD_CONST 1 (1)\n 6 LOAD_CONST 2 ('c')\n 9 LOAD_CONST 3 (2)\n 12 LOAD_CONST 4 (<code object fn at 0x7fe73567c6f0, file \"<string>\", line 1>)\n 15 LOAD_CONST 5 ('fn')\n 18 MAKE_FUNCTION 512\n 21 STORE_NAME 0 (fn)\n 24 LOAD_CONST 6 (None)\n 27 RETURN_VALUE\n", nil, ""},
2120+
{"def fn(a:\"a\",*arg:\"arg\",b:\"b\"=1,c:\"c\"=2,**kwargs:\"kw\") -> \"ret\": pass", "exec", &py.Code{
2121+
Argcount: 0,
2122+
Kwonlyargcount: 0,
2123+
Nlocals: 0,
2124+
Stacksize: 13,
2125+
Flags: 64,
2126+
Code: "\x64\x00\x00\x64\x01\x00\x64\x02\x00\x64\x03\x00\x64\x04\x00\x64\x05\x00\x64\x00\x00\x64\x02\x00\x64\x06\x00\x64\x07\x00\x64\x08\x00\x64\x09\x00\x64\x0a\x00\x90\x07\x00\x84\x00\x02\x5a\x00\x00\x64\x0b\x00\x53",
2127+
Consts: []py.Object{py.String("b"), py.Int(1), py.String("c"), py.Int(2), py.String("a"), py.String("arg"), py.String("kw"), py.String("ret"), py.Tuple{py.String("a"), py.String("arg"), py.String("b"), py.String("c"), py.String("kwargs"), py.String("return")}, &py.Code{
2128+
Argcount: 1,
2129+
Kwonlyargcount: 2,
2130+
Nlocals: 5,
2131+
Stacksize: 1,
2132+
Flags: 79,
2133+
Code: "\x64\x00\x00\x53",
2134+
Consts: []py.Object{py.None},
2135+
Names: []string{},
2136+
Varnames: []string{"a", "b", "c", "arg", "kwargs"},
2137+
Freevars: []string{},
2138+
Cellvars: []string{},
2139+
Filename: "<string>",
2140+
Name: "fn",
2141+
Firstlineno: 1,
2142+
Lnotab: "",
2143+
}, py.String("fn"), py.None},
2144+
Names: []string{"fn"},
2145+
Varnames: []string{},
2146+
Freevars: []string{},
2147+
Cellvars: []string{},
2148+
Filename: "<string>",
2149+
Name: "<module>",
2150+
Firstlineno: 1,
2151+
Lnotab: "",
2152+
}, " 1 0 LOAD_CONST 0 ('b')\n 3 LOAD_CONST 1 (1)\n 6 LOAD_CONST 2 ('c')\n 9 LOAD_CONST 3 (2)\n 12 LOAD_CONST 4 ('a')\n 15 LOAD_CONST 5 ('arg')\n 18 LOAD_CONST 0 ('b')\n 21 LOAD_CONST 2 ('c')\n 24 LOAD_CONST 6 ('kw')\n 27 LOAD_CONST 7 ('ret')\n 30 LOAD_CONST 8 (('a', 'arg', 'b', 'c', 'kwargs', 'return'))\n 33 LOAD_CONST 9 (<code object fn at 0x7fe734191db0, file \"<string>\", line 1>)\n 36 LOAD_CONST 10 ('fn')\n 39 EXTENDED_ARG 7\n 42 MAKE_FUNCTION 459264\n 45 STORE_NAME 0 (fn)\n 48 LOAD_CONST 11 (None)\n 51 RETURN_VALUE\n", nil, ""},
19222153
}

compile/make_compile_test.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,15 @@
156156
('''f(a, b, *args)''', "eval"),
157157
('''f(a, b, *args, d=e, **kwargs)''', "eval"),
158158
('''f(a, d=e, **kwargs)''', "eval"),
159+
# def
160+
('''def fn(): pass''', "exec"),
161+
('''def fn(a): pass''', "exec"),
162+
('''def fn(a,b,c): pass''', "exec"),
163+
('''def fn(a,b=1,c=2): pass''', "exec"),
164+
('''def fn(a,*arg,b=1,c=2): pass''', "exec"),
165+
('''def fn(a,*arg,b=1,c=2,**kwargs): pass''', "exec"),
166+
('''def fn(a:"a",*arg:"arg",b:"b"=1,c:"c"=2,**kwargs:"kw") -> "ret": pass''', "exec"),
167+
#('''def fn(): a+b''', "exec"),
159168

160169
]
161170

0 commit comments

Comments
 (0)