The parser produces an Abstract Syntax Tree (AST) made of nested Lua tables. Each node has a kind field that identifies its type. This document specifies every node type TLC can produce.
The root node of every AST.
{ kind = "Program", body = <Block> }A sequence of statements. Every scope boundary (function body, if-clause, loop body) produces a Block.
{ kind = "Block", statements = <list_of_statements> }A number constant. value is the numeric value, raw is the original source text.
{ kind = "NumericLiteral", value = <number>, raw = <string> }
-- Example: 42, 3.14, 0xFF, 1e10A string constant (single-quoted, double-quoted, or long string).
{ kind = "StringLiteral", value = <string> }
-- Example: "hello", 'world', [[long string]]{ kind = "BooleanLiteral", value = <boolean> }
-- value is true or false{ kind = "NilLiteral" }A variable or function name reference.
{ kind = "Identifier", value = <string> }
-- Example: x, myVar, _GThe ... expression inside a vararg function.
{ kind = "VarargExpression" }An anonymous function definition. Also used as the body field in LocalFunctionDeclaration and as the value in desugared function declaration assignments.
{
kind = "FunctionExpression",
body = <Block>,
parameters = <list_of_strings>,
isVararg = <boolean>
}A unary operation: -x, not x, or #x.
{
kind = "UnaryOperator",
operator = <string>, -- "-", "not", "#"
operand = <node>
}A binary operation.
{
kind = "BinaryOperator",
operator = <string>, -- "+", "-", "*", "/", "%", "^", "..",
-- "==", "~=", "<", ">", "<=", ">=",
-- "and", "or"
left = <node>,
right = <node>
}A function or method call.
{
kind = "FunctionCall",
callee = <node>,
arguments = <list_of_nodes>,
isMethodCall = <boolean>? -- nil by default, true for obj:method() syntax
}When isMethodCall is true, callee is an IndexExpression where the method name is the index, and the object is implicitly passed as the first argument by the VM.
Table field access via table.key or table[expr].
{
kind = "IndexExpression",
base = <node>, -- the table
index = <node>, -- the key
}For dot syntax (t.key), index is a StringLiteral node. For bracket syntax (t[expr]), index is an arbitrary expression.
A table literal { ... }.
{
kind = "TableConstructor",
elements = <list_of_TableElement>
}A single entry in a table constructor.
{
kind = "TableElement",
key = <node>,
value = <node>,
isImplicit = <boolean> -- true for positional entries like {1, 2, 3}
}For implicit keys ({expr1, expr2}), key is a NumericLiteral with sequential indices starting at 1.
An expression wrapped in parentheses. This is not purely cosmetic -- in Lua, parentheses force a multi-return expression to adjust to a single value. (f()) returns one value, f() may return many.
{
kind = "ParenthesizedExpression",
expression = <node>
}local var1, var2 = expr1, expr2
{
kind = "LocalDeclarationStatement",
variables = <list_of_strings>,
initializers = <list_of_nodes> -- may be empty
}local function name(...) ... end
{
kind = "LocalFunctionDeclaration",
name = <string>,
body = <FunctionExpression>
}lvalue1, lvalue2 = expr1, expr2
Each lvalue is either an Identifier or IndexExpression node.
{
kind = "AssignmentStatement",
lvalues = <list_of_nodes>,
expressions = <list_of_nodes>
}A function call used as a statement (the return value is discarded).
{
kind = "CallStatement",
expression = <FunctionCall>
}{
kind = "IfStatement",
clauses = <list_of_IfClauses>,
elseClause = <Block> or nil
}A single if or elseif branch.
{
kind = "IfClause",
condition = <node>,
body = <Block>
}while condition do ... end
{
kind = "WhileStatement",
condition = <node>,
body = <Block>
}repeat ... until condition
{
kind = "RepeatStatement",
body = <Block>,
condition = <node>
}Note: In Lua, locals declared inside the repeat block are visible in the until condition. The parser handles this scoping correctly.
for var = start, limit[, step] do ... end
{
kind = "ForNumericStatement",
variable = <string>,
start = <node>,
limit = <node>,
step = <node> or nil, -- nil means implicit step of 1
body = <Block>
}for iter1, iter2 in expr1, expr2 do ... end
{
kind = "ForGenericStatement",
iterators = <list_of_strings>,
expressions = <list_of_nodes>,
body = <Block>
}do ... end
{
kind = "DoStatement",
body = <Block>
}return expr1, expr2, ...
{
kind = "ReturnStatement",
expressions = <list_of_nodes> -- may be empty
}{ kind = "BreakStatement" }Given the source code:
local x = 1 + 2
print(x)TLC produces:
{
kind = "Program",
body = {
kind = "Block",
statements = {
{
kind = "LocalDeclarationStatement",
variables = {"x"},
initializers = {
{
kind = "BinaryOperator",
operator = "+",
left = {kind = "NumericLiteral", value = 1, raw = "1"},
right = {kind = "NumericLiteral", value = 2, raw = "2"}
}
}
},
{
kind = "CallStatement",
expression = {
kind = "FunctionCall",
callee = {kind = "Identifier", value = "print"},
arguments = {
{kind = "Identifier", value = "x"}
}
}
}
}
}
}