I'm getting back to this project! I'll dump questions about Lua internals here, but I mainly need to know all about closures in Lua so I can implement them. I haven't found a good place that documents them well. There are Lua VM internals whitepapers, but they don't talk about them well enough. Anyone have a good understanding on the sorts of data stored/used and how they are implemented?
<edit>
In order to help myself understand the internals before I try writing something optimized (z80), I have been messing around with implementing a tiny Lua VM in Python (wanted to write it quickly and easily). So...
test.lua
Code: print "Hello World!"
test.luac listing
Code: Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio
main <test.lua:0,0> (4 instructions at 0x1dff3c0)
0+ params, 2 slots, 1 upvalue, 0 locals, 2 constants, 0 functions
1 [1] GETTABUP 0 0 -1 ; _ENV "print"
2 [1] LOADK 1 -2 ; "Hello World!"
3 [1] CALL 0 2 1
4 [1] RETURN 0 1
constants (2) for 0x1dff3c0:
1 "print"
2 "Hello World!"
locals (0) for 0x1dff3c0:
upvalues (1) for 0x1dff3c0:
0 _ENV 1 0
luavm output
Code: Loading a Lua 5.2 bytecode file...
Bytecode flags: (1, 4, 8, 4, 8, 0)
Reading function from line 0 to 0
Reading 4 instructions...OK!
Reading 2 constants... OK!
Reading 0 prototypes... OK!
Reading 1 upvalues... OK!
Reading 0 locals... OK!
Op: <function op_gettabup at 0x7f88cb6c25f0>
Op: <function op_loadk at 0x7f88cb6c2578>
Op: <function op_call at 0x7f88cb6c2668>
Called native print method
[type:4] Hello World!
Op: <function op_return at 0x7f88cb6c26e0>
Exited top-level function
<edit>
I understand Lua internals much better now. I added closures and fixed up my types. I can now do much more complex operations with functions. See below:
test.lua
Code: local c = 2
local b = 123
function test(a)
print(a,b)
function test2(a)
print(a,b,c)
end
test2('woo')
local p = print
local _ENV = {}
function print(a)
p("_ENV changed",a)
end
print("Test")
end
local a = 123
test(a)
print(a,a)
test.luac listing
Code: Lua 5.2.2 Copyright (C) 1994-2013 Lua.org, PUC-Rio
main <test.lua:0,0> (13 instructions at 0x21c63c0)
0+ params, 6 slots, 1 upvalue, 3 locals, 4 constants, 1 function
1 [1] LOADK 0 -1 ; 2
2 [2] LOADK 1 -2 ; 123
3 [16] CLOSURE 2 0 ; 0x21c68d0
4 [4] SETTABUP 0 -3 2 ; _ENV "test"
5 [18] LOADK 2 -2 ; 123
6 [19] GETTABUP 3 0 -3 ; _ENV "test"
7 [19] MOVE 4 2
8 [19] CALL 3 2 1
9 [20] GETTABUP 3 0 -4 ; _ENV "print"
10 [20] MOVE 4 2
11 [20] MOVE 5 2
12 [20] CALL 3 3 1
13 [20] RETURN 0 1
constants (4) for 0x21c63c0:
1 2
2 123
3 "test"
4 "print"
locals (3) for 0x21c63c0:
0 c 2 14
1 b 3 14
2 a 6 14
upvalues (1) for 0x21c63c0:
0 _ENV 1 0
function <test.lua:4,16> (17 instructions at 0x21c68d0)
1 param, 5 slots, 3 upvalues, 3 locals, 4 constants, 2 functions
1 [5] GETTABUP 1 0 -1 ; _ENV "print"
2 [5] MOVE 2 0
3 [5] GETUPVAL 3 1 ; b
4 [5] CALL 1 3 1
5 [8] CLOSURE 1 0 ; 0x21c6d20
6 [6] SETTABUP 0 -2 1 ; _ENV "test2"
7 [9] GETTABUP 1 0 -2 ; _ENV "test2"
8 [9] LOADK 2 -3 ; "woo"
9 [9] CALL 1 2 1
10 [10] GETTABUP 1 0 -1 ; _ENV "print"
11 [11] NEWTABLE 2 0 0
12 [14] CLOSURE 3 1 ; 0x21c6bd0
13 [12] SETTABLE 2 -1 3 ; "print" -
14 [15] GETTABLE 3 2 -1 ; "print"
15 [15] LOADK 4 -4 ; "Test"
16 [15] CALL 3 2 1
17 [16] RETURN 0 1
constants (4) for 0x21c68d0:
1 "print"
2 "test2"
3 "woo"
4 "Test"
locals (3) for 0x21c68d0:
0 a 1 18
1 p 11 18
2 _ENV 12 18
upvalues (3) for 0x21c68d0:
0 _ENV 0 0
1 b 1 1
2 c 1 0
function <test.lua:6,8> (6 instructions at 0x21c6d20)
1 param, 5 slots, 3 upvalues, 1 local, 1 constant, 0 functions
1 [7] GETTABUP 1 0 -1 ; _ENV "print"
2 [7] MOVE 2 0
3 [7] GETUPVAL 3 1 ; b
4 [7] GETUPVAL 4 2 ; c
5 [7] CALL 1 4 1
6 [8] RETURN 0 1
constants (1) for 0x21c6d20:
1 "print"
locals (1) for 0x21c6d20:
0 a 1 7
upvalues (3) for 0x21c6d20:
0 _ENV 0 0
1 b 0 1
2 c 0 2
function <test.lua:12,14> (5 instructions at 0x21c6bd0)
1 param, 4 slots, 1 upvalue, 1 local, 1 constant, 0 functions
1 [13] GETUPVAL 1 0 ; p
2 [13] LOADK 2 -1 ; "_ENV changed"
3 [13] MOVE 3 0
4 [13] CALL 1 3 1
5 [14] RETURN 0 1
constants (1) for 0x21c6bd0:
1 "_ENV changed"
locals (1) for 0x21c6bd0:
0 a 1 6
upvalues (1) for 0x21c6bd0:
0 p 1 1
luavm output
Code: Loading a Lua 5.2 bytecode file...
Bytecode flags: (1, 4, 8, 4, 8, 0)
Reading function from line 0 to 0
Reading 13 instructions...OK!
Reading 4 constants... OK!
Reading 1 prototypes...
Reading function from line 4 to 16
Reading 17 instructions...OK!
Reading 4 constants... OK!
Reading 2 prototypes...
Reading function from line 6 to 8
Reading 6 instructions...OK!
Reading 1 constants... OK!
Reading 0 prototypes...
Finsihed reading 0 prototypes!
Reading 3 upvalues... OK!
Reading 1 locals... OK!
Reading function from line 12 to 14
Reading 5 instructions...OK!
Reading 1 constants... OK!
Reading 0 prototypes...
Finsihed reading 0 prototypes!
Reading 1 upvalues... OK!
Reading 1 locals... OK!
Finsihed reading 2 prototypes!
Reading 3 upvalues... OK!
Reading 3 locals... OK!
Finsihed reading 1 prototypes!
Reading 1 upvalues... OK!
Reading 3 locals... OK!
Op: <function op_loadk at 0x7ff3c4031848>
Op: <function op_loadk at 0x7ff3c4031848>
Op: <function op_closure at 0x7ff3c4031c80>
Op: <function op_settabup at 0x7ff3c4031a28>
Op: <function op_loadk at 0x7ff3c4031848>
Op: <function op_gettabup at 0x7ff3c4031938>
Op: <function op_move at 0x7ff3c40317d0>
Op: <function op_call at 0x7ff3c4031b90>
Op: <function op_gettabup at 0x7ff3c40300c8>
Op: <function op_move at 0x7ff3c4031ed8>
Op: <function op_getupval at 0x7ff3c4030050>
Op: <function op_call at 0x7ff3c4030320>
Called native print method
[type:3] 123.0
[type:3] 123.0
Op: <function op_closure at 0x7ff3c4030410>
Op: <function op_settabup at 0x7ff3c40301b8>
Op: <function op_gettabup at 0x7ff3c40300c8>
Op: <function op_loadk at 0x7ff3c4031f50>
Op: <function op_call at 0x7ff3c4030320>
Op: <function op_gettabup at 0x7ff3c40307d0>
Op: <function op_move at 0x7ff3c4030668>
Op: <function op_getupval at 0x7ff3c4030758>
Op: <function op_getupval at 0x7ff3c4030758>
Op: <function op_call at 0x7ff3c4030a28>
Called native print method
[type:4] woo
[type:3] 123.0
[type:3] 2.0
Op: <function op_return at 0x7ff3c4030aa0>
Op: <function op_gettabup at 0x7ff3c40300c8>
Op: <function op_newtable at 0x7ff3c4030230>
Op: <function op_closure at 0x7ff3c4030410>
Op: <function op_settable at 0x7ff3c40302a8>
Op: <function op_gettable at 0x7ff3c4030140>
Op: <function op_loadk at 0x7ff3c4031f50>
Op: <function op_call at 0x7ff3c4030320>
Op: <function op_getupval at 0x7ff3c4030b90>
Op: <function op_loadk at 0x7ff3c40306e0>
Op: <function op_move at 0x7ff3c4030668>
Op: <function op_call at 0x7ff3c4030938>
Called native print method
[type:4] _ENV changed
[type:4] Test
Op: <function op_return at 0x7ff3c4030a28>
Op: <function op_return at 0x7ff3c4030398>
Op: <function op_gettabup at 0x7ff3c4031938>
Op: <function op_move at 0x7ff3c40317d0>
Op: <function op_move at 0x7ff3c40317d0>
Op: <function op_call at 0x7ff3c4031b90>
Called native print method
[type:3] 123.0
[type:3] 123.0
Op: <function op_return at 0x7ff3c4031c08>
Exited top-level function
standard lua output
Code: 123 123
woo 123 2
_ENV changed Test
123 123
It seems like my VM works like Lua does in terms of handling closures and upvalues. I currently don't handle returns or arguments properly. Vararg functions aren't supported except for native functions that use hackish ways (print looks at calling metadata to determine arg count).