@@ -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.
22832290function CodeGenerator :getUpvalueType (variableName )
22842291 local scope = self .currentScope
22852292 local isUpvalue = false
@@ -2367,7 +2374,7 @@ function CodeGenerator:setRegisterValue(node, copyFromRegister)
23672374end
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 ()
30203028end
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