-
Notifications
You must be signed in to change notification settings - Fork 5
Home
The exclamation mark (!) is used to indicate what code is part of the metaprogram. There are 4 ways to write metaprogram code:
-
!...
- One exclamation mark. -
!!...
- Two exclamation marks. -
!( ... )
- One exclamation mark with a parenthesis. -
!!( ... )
- Two exclamation marks with a parenthesis.
The line will simply run during preprocessing. The line can span multiple physical lines if it contains brackets. Examples:
-- Simple preprocessor lines.
!if not isDeveloper then
sendTelemetry()
!end
-- Span multiple lines.
!newClass{
name = "Entity",
props = {x=0, y=0},
}
-- There can be stuff before a preprocessor line.
local foo = 10 !print("We've reached foo.")
-- Example output:
sendTelemetry()
function newEntity()
return {__classname="Entity", x=0, y=0}
end
local foo = 10
The line will appear in both the metaprogram and the final program. The line must be an assignment. Examples:
-- The expression will be evaluated in the metaprogram and the
-- result will appear in the final program as a literal value.
!!local tau = 2*math.pi
!!local aAndTau = ("a"):rep(20)..tau
-- Output:
local tau = 6.283185
local aAndTau = "aaaaaaaaaaaaaaaaaaaa6.283185"
If the parenthesis contains an expression the result of the expression will be outputted as a literal value, otherwise the code will just run as-is. Examples:
-- Output values.
local bigNumber = !( 5^10 )
local manyAbcs = !( ("abc"):rep(10) )
-- Run a block of code.
!(
local dogWord = "Woof "
function getDogText()
return dogWord:rep(3)
end
outputLua("dog = ")
outputValue(getDogText())
)
-- Output:
local bigNumber = 9765625
local manyAbcs = "abcabcabcabcabcabcabcabcabcabc"
dog = "Woof Woof Woof "
The expression in the parenthesis will be outputted as Lua code. The expression must result in a string. Examples:
local font = !!( isDeveloper and "loadDevFont()" or "loadUserFont()" )
!local globals = {pi=math.pi, tau=2*math.pi}
!for k, v in pairs(globals) do
_G.!!(k) = !(v)
!end
-- Example output:
local font = loadUserFont()
_G.pi = 3.14159265358979323846
_G.tau = 6.28318530717958647693
These examples show two ways of doing the same thing using inline code and a code block.
-- Using inline code.
local oddNumbers = {
!for v = 1, 5, 2 do
!( v ),
!end
}
-- Using a code block.
!(
outputLua("local oddNumbers = {\n")
for v = 1, 5, 2 do
outputLua("\t")
outputValue(v)
outputLua(",\n")
end
outputLua("}")
)
-- Output:
local oddNumbers = {
1,
3,
5,
}
-- Using inline code.
!local alpha = "[%a_]"
!local alphaNumeric = "[%w_]"
local identifierPattern = !( "^"..alpha..alphaNumeric.."*$" )
-- Using a code block.
!(
local alpha = "[%a_]"
local alphaNumeric = "[%w_]"
outputLua("local identifierPattern = ")
outputValue("^"..alpha..alphaNumeric.."*$")
)
-- Output:
local identifierPattern = "^[%a_][%w_]*$"
Beware in code blocks that only call a single function:
-- This will bee seen as an inline block and output whatever value
-- func() returns as a literal.
!( func() )
-- If that's not wanted then a trailing ";" will prevent that.
-- This line won't output anything (unless func() calls outputLua()
-- or outputValue()).
!( func(); )
-- When the full metaprogram is generated, `!(func())` translates
-- into `outputValue(func())` while `!(func();)` simply translates
-- into `func();` (because `outputValue(func();)` would be invalid
-- Lua code).
-- Anyway, in this specific case a preprocessor line (without the
-- parenthesis) would be nicer:
!func()