Extra functionality
Preprocessor keywords
In addition to the exclamation mark (!
) there is another symbol with special meaning in LuaPreprocess: the at sign (@
).
It's used as prefix for a few special preprocessor keywords that do different things.
- @file
- @line
- @insert
- @insert "name"
- @insert func() (macros)
@file
v1.11
Inserts the path to the current file as a string literal, e.g. "src/scenes/main.lua2p"
.
print("Current file: "..@file)
-- Example output:
print("Current file: ".."src/scenes/main.lua2p")
@line
v1.11 Inserts the current line number as an integer numeral.
print("Current line: "..@line)
-- Example output:
print("Current line: ".. 372)
@insert
This keyword has two variants.
@insert "name"
v1.10
This variant inserts a resource as-is in-place before the metaprogram runs (the resource being a Lua code string from somewhere).
By default, name
is a path to a file to be inserted but this behavior can be changed by defining params.onInsert()
when calling processFile
or processString
(or by handling the "insert"
message in the message handler in the command line program).
-- script.lua
local one = 1
@insert "partialScript.lua"
print(one + two)
-- partialScript.lua
local two = !( 1+1 )
-- Output:
local one = 1
local two = 2
print(one + two)
The keyword can also appear in the metaprogram anywhere.
-- script.lua
!(
@insert "yellFunction.lua"
yell("aaargh")
)
local versionText = !( "Version: " .. @insert "appVersion.txt" )
print(versionText) -- Version: 1.2.3
-- yellFunction.lua
local function yell(text)
print(text:upper().."!!!")
end
-- appVersion.txt
"1.2.3"
v1.13
@insert
can also be written more compactly as @@
:
@@"yellFunction.lua"
@insert func()
v1.13
This variant outputs the result returned from a function func()
defined in the metaprogram (like !!(func())
)
except all arguments are converted to individual strings containing the apparent Lua code before the call.
We call these macros (similar to macros in C/C++ and other languages).
-- Define a better assert function.
!(
local DEBUG = true
local function ASSERT(conditionCode, messageCode)
if not DEBUG then
-- Make ASSERT() calls do nothing if we're not in debug mode.
return ""
end
if not messageCode then
messageCode = string.format("%q", "Assertion failed: "..conditionCode)
end
return "if not ("..conditionCode..") then error("..messageCode..") end"
end
)
local text = "Herzlich willkommen!"
@insert ASSERT(#text < 15, "Text is too long: "..text)
-- Output:
local text = "Herzlich willkommen!"
if not (#text < 15) then error("Text is too long: "..text) end
Note: An
ASSERT
macro is already provided by the library.
@insert
can also be written more compactly as @@
:
@@ASSERT(#text < 15, "Text is too long: "..text)
@@ASSERT
kind of looks like a preprocessor keyword here, so we could call it a user-defined preprocessor keyword if we wanted to (even though it's not actually a keyword).
v1.14
!(expression)
and !!(expression)
work in macros.
Note that code blocks in macros do not output anything themselves - instead, their result is concatenated with the surrounding Lua code to be part of the argument for the macro function.
Macros can also be nested.
!local variableName = "text"
!local maxLength = 3*5
@@ASSERT(
#!!(variableName) < !(maxLength),
@@string.upper("Text is too long: ") .. !!(variableName)
)
-- Output:
local text = "Herzlich willkommen!"
if not (#text < 15) then error("TEXT IS TOO LONG: " .. text) end
Note that string.upper
receives "\"Text is too long: \""
here, i.e. a Lua code string,
but it works because the function doesn't change the quote characters.
These are all the forms macros can have:
@@func() -- Syntax sugar for @insert func()
@@func{} -- Syntax sugar for @@func({})
@@func"" -- Syntax sugar for @@func("")
@@func!(e) -- Syntax sugar for @@func(!(e))
@@func!!(e) -- Syntax sugar for @@func(!!(e)) - this is functionally the same as !!(func(e))
v1.16
Macro functions can choose whether to return a Lua code string or use outputLua
(and related functions).
!(
local function DOG_1()
return "getDog()"
end
local function DOG_2()
outputLua("getDog()")
end
)
-- The result for these two lines are the same:
local dog = @@DOG_1()
local dog = @@DOG_2()
-- Output:
local dog = getDog()
local dog = getDog()
-- Combining both methods raises an error.
!(
local function DOG_3()
outputLua("getDog()")
return "getDog()"
end
)
local dog = @@DOG_3() -- Error!
v1.19
Any other use of !
also works in macros.
!(
local function ONE_TWO_ONE(one, two)
return one .. two .. one
end
)
@@ONE_TWO_ONE(
!outputLua("bark()") -- The output is captured by the macro's 1st argument.
,
!outputLua("meow()") -- The output is captured by the macro's 2nd argument.
)
-- Output:
bark()
meow()
bark()
Preprocessor symbols
v1.16
Preprocessor symbols output Lua code similarly to !!(expression)
.
A symbol is a dollar sign ($
) followed by a name referencing a variable in the metaprogram.
!local EXPRESSION = "5*getFoo()"
-- These two lines are equivalent:
local x = $EXPRESSION
local x = !!(EXPRESSION)
-- Output:
local x = 5*getFoo()
local x = 5*getFoo()
A difference from !!(expression)
is that if the name references a function (v1.18 or callable table) then the function (or table) is called.
!(
local count = 0
local function NEW_ID()
count = count + 1
return toLua(count)
end
)
local someId = $NEW_ID
local otherId = $NEW_ID
-- Output:
local someId = 1
local otherId = 2
Preprocessor symbols and macros can work very well together.
!local function ADD_IF_SINGLE_DIGIT(variable, value)
if $variable <= 9 then
$variable = $variable + $value
end
!end
local x = 0
@@ADD_IF_SINGLE_DIGIT(x, 100)
-- Output:
local x = 0
if x <= 9 then
x = x + 100
end
Note how the body of the ADD_IF_SINGLE_DIGIT
function is not part of the metaprogram (except for the $variable
and $value
symbols).
We could write the same function like this:
!(
local function ADD_IF_SINGLE_DIGIT(variable, value)
outputLua("if ",variable," <= 9 then\n")
outputLua("\t",variable," = ",variable," + ",value,"\n")
outputLua("end\n")
end
)
Backtick strings
The backtickStrings
parameter (or --backtickstrings
option) enables the backtick (`
) to be used as string literal delimiters.
Backtick strings don't interpret any escape sequences and can't contain other backticks.
The strings can span multiple lines.
This feature can be nice for strings that contain Lua code and you want your text editor to apply normal syntax highlighting to the string contents. Example:
!local DOUBLE_X = `
x = x*2
`
local x = 1
$DOUBLE_X
$DOUBLE_X
print(x)
-- Output:
local x = 1
x = x*2
x = x*2
print(x)
Page updated: 2022-07-08