Skip to content

Commit b26cb22

Browse files
committed
refactor(codegenerator): improve closure generation logic and add more comments
1 parent 104b3e8 commit b26cb22

1 file changed

Lines changed: 45 additions & 29 deletions

File tree

the-tiny-lua-compiler.lua

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1944,9 +1944,17 @@ CodeGenerator.CONFIG = {
19441944
MAX_REGISTERS = 250, -- 200 variables, 50 temp (5 reserved for safety)
19451945
SETLIST_MAX = 50, -- Max number of table elements for a single SETLIST instruction
19461946

1947+
-- Node types that can return multiple values (multiret)
19471948
MULTIRET_NODES = createLookupTable({"FunctionCall", "VarargExpression"}),
1949+
1950+
-- Node types that be stored as constants in `proto.constants` table
1951+
CONSTANT_NODES = createLookupTable({"StringLiteral", "NumericLiteral"}),
19481952
CONTROL_FLOW_OPERATOR_LOOKUP = createLookupTable({"and", "or"}),
1949-
UNARY_OPERATOR_LOOKUP = { ["-"] = "UNM", ["#"] = "LEN", ["not"] = "NOT" },
1953+
UNARY_OPERATOR_LOOKUP = {
1954+
["-"] = "UNM",
1955+
["#"] = "LEN",
1956+
["not"] = "NOT"
1957+
},
19501958
ARITHMETIC_OPERATOR_LOOKUP = {
19511959
["+"] = "ADD", ["-"] = "SUB",
19521960
["*"] = "MUL", ["/"] = "DIV",
@@ -1980,6 +1988,7 @@ CodeGenerator.CONFIG = {
19801988
["IndexExpression"] = "processIndexExpression",
19811989
["VarargExpression"] = "processVarargExpression",
19821990
},
1991+
19831992
STATEMENT_HANDLERS = {
19841993
["CallStatement"] = "processCallStatement",
19851994
["LocalDeclarationStatement"] = "processLocalDeclarationStatement",
@@ -2277,9 +2286,7 @@ end
22772286

22782287
--// Auxiliary/Helper Methods //--
22792288

2280-
-- Returns either "Upvalue", "Local", or "Global".
2281-
-- TODO: We shouldn't do that at compiling phase.
2282-
-- Is there a better way to do that?
2289+
-- Determines whether a variable is local, upvalue, or global.
22832290
function CodeGenerator:getUpvalueType(variableName)
22842291
local scope = self.currentScope
22852292
local isUpvalue = false
@@ -2367,7 +2374,7 @@ function CodeGenerator:setRegisterValue(node, copyFromRegister)
23672374
end
23682375

23692376
-- TODO: Make it much cleaner
2370-
-- NOTE: `isLastElementImplicit` is needed to prevent false multirets
2377+
-- NOTE: `isLastElemImplicit` is needed to prevent false multirets
23712378
-- in case there's an explicit node element that goes just after
23722379
-- the supposed multiret implicit element. Like here:
23732380
-- `{ 1, 2, get_three_four(), a = 2 }`. The table should look like this:
@@ -2475,13 +2482,13 @@ function CodeGenerator:processBinaryOperator(node, register)
24752482
local leftReg = self:processConstantOrExpression(left, register)
24762483
local rightReg = self:processConstantOrExpression(right)
24772484
local nodeOperator = self.CONFIG.COMPARISON_INSTRUCTION_LOOKUP[operator]
2478-
local instruction, flag = nodeOperator[1], nodeOperator[2]
2485+
local instruction, opposite = nodeOperator[1], nodeOperator[2]
24792486

24802487
local flip = (operator == ">" or operator == ">=")
24812488
local b, c = leftReg, rightReg
24822489
if flip then b, c = rightReg, leftReg end
24832490

2484-
self:emitInstruction(instruction, flag, b, c)
2491+
self:emitInstruction(instruction, opposite, b, c)
24852492
self:emitInstruction("JMP", 0, 1)
24862493

24872494
-- OP_LOADBOOL [A, B, C] R(A) := (Bool)B; if (C) pc++
@@ -3015,10 +3022,39 @@ function CodeGenerator:processFunctionBody(node)
30153022
end
30163023

30173024
self:processStatementList(node.Body.Statements)
3018-
self:emitInstruction("RETURN", 0, 1, 0) -- Default return statement
3025+
-- Generate default return statement.
3026+
self:emitInstruction("RETURN", 0, 1, 0)
30193027
self:leaveScope()
30203028
end
30213029

3030+
-- Adds `proto` prototype to the `self.proto.protos` list and generates
3031+
-- the "CLOSURE" and upvalue capturing pseudo instructions.
3032+
function CodeGenerator:generateClosure(proto, closureRegister)
3033+
local parentProto = self.proto
3034+
local protoIndex = #parentProto.protos + 1
3035+
table.insert(parentProto.protos, proto)
3036+
3037+
-- OP_CLOSURE [A, Bx] R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))
3038+
-- Proto indices are zero-based.
3039+
self:emitInstruction("CLOSURE", closureRegister, protoIndex - 1, 0)
3040+
3041+
-- After the "CLOSURE" instruction, we need to set up the upvalues
3042+
-- for the newly created function prototype. It is done by pseudo
3043+
-- instructions that follow the CLOSURE instruction.
3044+
for _, upvalueName in ipairs(proto.upvalues) do
3045+
local upvalueType = self:getUpvalueType(upvalueName)
3046+
if upvalueType == "Local" then
3047+
-- OP_MOVE [A, B] R(A) := R(B)
3048+
self:emitInstruction("MOVE", 0, self:findVariableRegister(upvalueName))
3049+
elseif upvalueType == "Upvalue" then
3050+
-- OP_GETUPVAL [A, B] R(A) := UpValue[B]
3051+
self:emitInstruction("GETUPVAL", 0, self:findOrCreateUpvalue(upvalueName))
3052+
else -- Assume it's a global.
3053+
error("Compiler: Possible parser error, the upvalue cannot be a global: " .. upvalueName)
3054+
end
3055+
end
3056+
end
3057+
30223058
-- Processes and compiles a function node into a function prototype.
30233059
--
30243060
-- functionNode - The AST node representing the function.
@@ -3035,27 +3071,7 @@ function CodeGenerator:processFunction(functionNode, closureRegister)
30353071
self.proto = parentProto
30363072

30373073
if closureRegister then
3038-
local protoIndex = #parentProto.protos + 1
3039-
parentProto.protos[protoIndex] = childProto
3040-
3041-
-- OP_CLOSURE [A, Bx] R(A) := closure(KPROTO[Bx], R(A), ... ,R(A+n))
3042-
self:emitInstruction("CLOSURE", closureRegister, protoIndex - 1, 0) -- Proto indices are zero-based.
3043-
3044-
-- After the "CLOSURE" instruction, we need to set up the upvalues
3045-
-- for the newly created function prototype. It is done by pseudo
3046-
-- instructions that follow the CLOSURE instruction.
3047-
for _, upvalueName in ipairs(childProto.upvalues) do
3048-
local upvalueType = self:getUpvalueType(upvalueName)
3049-
if upvalueType == "Local" then
3050-
-- OP_MOVE [A, B] R(A) := R(B)
3051-
self:emitInstruction("MOVE", 0, self:findVariableRegister(upvalueName))
3052-
elseif upvalueType == "Upvalue" then
3053-
-- OP_GETUPVAL [A, B] R(A) := UpValue[B]
3054-
self:emitInstruction("GETUPVAL", 0, self:findOrCreateUpvalue(upvalueName))
3055-
else -- Assume it's a global.
3056-
error("Compiler: Possible parser error, the upvalue cannot be a global: " .. upvalueName)
3057-
end
3058-
end
3074+
self:generateClosure(childProto, closureRegister)
30593075
end
30603076

30613077
return childProto

0 commit comments

Comments
 (0)