Library to generate Lua code from a syntax tree.
# comment
# local variables
local a, b = 1, 2
# function calls have no ()
print a, "example", b
# ! is a call with no args
local input = tonumber io.read!
# everything is an expression
print if input>5: "greater than 5" else "less than or equal to 5"
# two options for block syntax
if cond
print "test"
end
if cond: print "test"
# string interpolation with $ in double-quoted strings
print "$a + $b = $(a + b)"
# loops evaluate to a list
local list = for i = 1, 5: i
for k, v in ipairs list: print k, v
# table constructors don't need commas before newlines
local tbl = {
# key->value syntax
456 -> "asdf"
# sugar for literal strings
thing: 123
tbl: {'a', 'b'}
}
# table deconstruction
local {thing:thing, tbl:{a, b}} = tbl
print thing, a, b
# "in" syntax sugar for multiple comparisons with the same value
print 'bar' in ('foo', 'bar')
print 5 in (4, 7)
print 4 in (4, 7)
print 4 in (4<=>7) # range (inclusive)
print 4 in (4<>7) # range (exclusive)
print 4 in (4<=->7) # range (includes only lower limit)
print 4 in (4<-=>7) # range (includes only upper limit)
print 50 in (4<=>7, 10<=>20, 50) # ranges and choices can be combined
print 'bar' in ('a'<=>'c') # ranges work with any comparable values
local cls = {}
cls.__index = cls
cls.new = fn val
local self = {v: val}
return self
end
# @ is short for self.
cls.foo = fn self, n
return @v + n
end
# calling an @name automatically uses self as the first arg
cls.bar = fn self
@v = @foo 5
end
# \ is a method call
local i = cls.new 3
print cls\foo 3
cls\bar!
print cls\foo 3
Each node is a table with [1] containing the type of the node as a string, plus other info.
Each node is also either a statement or an expression. Many nodes only accept either one or the other as child node in certain cases.
{'seq', ...}(statement)
A sequence of statements run in order.
{'while', cond, body}(statement)
A while loop. cond is an expression, and body is a statement.
{'repeat', body, cond}(statement)
A repeat loop. cond is an expression, and body is a statement.
{'for_num', var, istart, iend, istep, body}(statement)
A numeric for loop. var is a string, istart, iend, and istep are expressions (but istep can be false to omit it), and body is a statement.
{'for_iter', var_list, iter, body}(statement)
An iterator for loop. var_list is a list of strings, iter is the iterator (explist is allowed for multiple values), and body is a statement.
{'do', body}(statement)
Creates a new scope for the body statement to run in.
{'goto', label}(statement)
Jump to the label named by the label string. If this is used the resulting code will not be Lua 5.1 compatible.
{'label', label}(statement)
Create a goto label named by the label string. If this is used the resulting code will not be Lua 5.1 compatible.
{'break'}(statement)
Break out of the innermost loop.
{'return', exp}(statement)
Return the value exp from the current function. exp can be an explist node for multiple values.
{'assign', lhs, rhs}(statement)
Assignment operator. For multiple values on either side, use an explist node.
{'local', lhs, rhs}(statement)
Create local variables. lhs is either a name node or explist of name nodes, and rhs is an optional value to assign to the variables (explist is allowed).
{'if', cond, true_body, elseif_cond, elseif_body, else_body}(statement)
An if statement. The else_body is optional, and the elseif_cond and elseif_body can be repeated 0 or more times. The conditions are expected to be expressions, and the bodies should be statements.
{'name', str}(expression)
A variable name.
{'number', str}(expression)
A literal number. str is a string representation of the number, in a format that can be inserted directly into a Lua script file.
{'string', str}(expression)
A literal string. str is the contents of the string.
{'true'}(expression)
A boolean true value.
{'false'}(expression)
A boolean false value.
{'nil'}(expression)
A nil value.
{'binop', op, lhs, rhs}(expression)
A binary operator expression. op is a string containing a valid Lua binary operator, and lhs and rhs are the sub-expressions.
{'unop', op, sub}(expression)
A unary operator expression. op is a string containing a valid Lua unary operator, and sub is the sub-expression.
{'gettable', tbl, key}(expression)
Get the value at key from tbl.
{'call', fn, arg}(any)
Calls fn with arg as the argument. arg can be an explist node for multiple args.
{'method_call', tbl, name, arg}(any)
Calls tbl.name with tbl, arg as the arguments. Translates to the : operator in Lua. Note that name is a string, not an expression that results in a string.
{'table', key1, val1, key2, val2, ...}(expression)
A table constructor. For array items, the key can be false.
{'function', {...}, body}(expression)
A function expression. ... is a list of arg name string, body is the statement inside the function.
{'vararg'}(expression)
Creates a ... in the resulting code.
{'explist', ...}(expression, but only usable where a comma-separated list is acceptable in Lua)
A comma-separated list of expressions. Often used as the arg expression for function calls, or the return statement.
{'quote', node}(expression)
Put a table constructor that creates a table equivalent to node in the resulting code. Used to implement macros.
{'dequote', node}(any)
Run the statement node during te code-generation process, and replace the dequote node with the node that it returns. Used to implement macros.
The expr_to_stat function takes an AST which ignores the distinction between statements and expressions, and changes it so that it represents a valid Lua program while retaining its original meaning.
Some important notes about how the conversion is done:
if statements evaluate to the contents of the branch that was chosen, or nil of none of the branches match and there is no else:
f(if x then y else z end)
---
local tmp1
if x then
tmp1 = y
else
tmp1 = z
end
f(tmp1)
Any loop evaluates to a list of the values returned on each iteration:
x = for i = 1, 10 do i end
---
local tmp1, tmp2 = 1, {}
for i = 1, 10 do
tmp2[tmp1] = i
tmp1 = tmp1 + 1
end
x = tmp2
When an expression not usable as a statement in Lua doesn't have its result used, it's wrapped in a dummy statement:
a + b
---
if a + b then end
Assignment (either with the assign or local node) results in the varaible's new value, or a list of values if there are multiple variables:
f((a, b) = thing())
---
local tmp1, tmp2 = thing()
a, b = tmp1, tmp2
f(tmp1, tmp2)