Skip to content

Commit 04ba8ca

Browse files
committed
Added macro example. Added @@func() as short version of @insert func().
1 parent 6dd62c7 commit 04ba8ca

File tree

6 files changed

+128
-33
lines changed

6 files changed

+128
-33
lines changed

examples/macros.lua2p

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
--[[============================================================
2+
--=
3+
--= LuaPreprocess example: Macros.
4+
--=
5+
--= Here we define a better assert function using a macro.
6+
--=
7+
--============================================================]]
8+
9+
!(
10+
local DEBUG = true
11+
12+
function assert(conditionCode, messageCode)
13+
if not DEBUG then
14+
-- Make assert() calls do absolutely nothing if we're not in debug mode.
15+
return ""
16+
end
17+
if not messageCode then
18+
messageCode = string.format("%q", "Assertion failed: "..conditionCode)
19+
end
20+
return "if not ("..conditionCode..") then error("..messageCode..") end"
21+
end
22+
)
23+
24+
local i = 4
25+
26+
--
27+
-- A call to Lua's normal assert function might look something like this. A
28+
-- problem is that the message expression is evaluated even if the condition
29+
-- is true, which is completely unnecessary. (This example is very simple of
30+
-- course, but imagine more costly operations happening.)
31+
--
32+
assert(i > 1 and i < 7, "Invalid index. It must be 1<=i<=7 but is "..i)
33+
34+
--
35+
-- By prepending @insert we actually call the assert function in the
36+
-- metaprogram which, as we defined above, separates the condition and the
37+
-- message arguments so that the message expression never evaluates as long as
38+
-- the condition is true.
39+
--
40+
@insert assert(i > 1 and i < 7, "Invalid index. It must be 1<=i<=7 but is "..i)
41+
42+
-- We also made the default message better by including the condition code
43+
-- itself in the message.
44+
@insert assert(i > 1 and i < 7)
45+
46+
print("'i' is all good!")

examples/macros.output.lua

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
--[[============================================================
2+
--=
3+
--= LuaPreprocess example: Macros.
4+
--=
5+
--= Here we define a better assert function using a macro.
6+
--=
7+
--============================================================]]
8+
9+
local i = 4
10+
11+
--
12+
-- A call to Lua's normal assert function might look something like this. A
13+
-- problem is that the message expression is evaluated even if the condition
14+
-- is true, which is completely unnecessary. (This example is very simple of
15+
-- course, but imagine more costly operations happening.)
16+
--
17+
assert(i > 1 and i < 7, "Invalid index. It must be 1<=i<=7 but is "..i)
18+
19+
--
20+
-- By prepending @insert we actually call the assert function in the
21+
-- metaprogram which, as we defined above, separates the condition and the
22+
-- message arguments so that the message expression never evaluates as long as
23+
-- the condition is true.
24+
--
25+
if not (i > 1 and i < 7) then error("Invalid index. It must be 1<=i<=7 but is "..i) end
26+
27+
-- We also made the default message better by including the condition code
28+
-- itself in the message.
29+
if not (i > 1 and i < 7) then error("Assertion failed: i > 1 and i < 7") end
30+
31+
print("'i' is all good!")

preprocess.lua

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
--=
66
--= License: MIT (see the bottom of this file)
77
--= Website: https://github.com/ReFreezed/LuaPreprocess
8+
--= Documentation: https://github.com/ReFreezed/LuaPreprocess/wiki
89
--=
910
--= Tested with Lua 5.1, 5.2, 5.3 and 5.4.
1011
--=
@@ -37,8 +38,8 @@
3738
3839
How to metaprogram:
3940
40-
The exclamation mark (!) is used to indicate what code is part
41-
of the metaprogram. There are 4 ways to write metaprogram code:
41+
The exclamation mark (!) is used to indicate what code is part of
42+
the metaprogram. There are 4 main ways to write metaprogram code:
4243
4344
!... The line will simply run during preprocessing. The line can span multiple actual lines if it contains brackets.
4445
!!... The line will appear in both the metaprogram and the final program. The line must be an assignment.
@@ -79,10 +80,10 @@
7980
8081
-- Extended preprocessor line. (Lines are consumed until brackets
8182
-- are balanced when the end of the line has been reached.)
82-
!newClass{
83+
!newClass{ -- Starts here.
8384
name = "Entity",
8485
props = {x=0, y=0},
85-
}
86+
} -- Ends here.
8687
8788
-- Preprocessor block.
8889
!(
@@ -100,27 +101,22 @@
100101
101102
-- Dual code (both preprocessor line and final output).
102103
!!local partial = "Hello"
103-
local whole = partial..!(partial..", world!")
104+
local whole = partial .. !(partial..", world!")
104105
print(whole) -- HelloHello, world!
105106
106107
-- Beware in preprocessor blocks that only call a single function!
107-
!(func()) -- This will bee seen as an inline block and output whatever value func() returns as a literal.
108-
!(func();) -- If that's not wanted then a trailing ";" will prevent that. This line won't output anything by itself.
109-
-- When the full metaprogram is generated, "!(func())" translates into "outputValue(func())"
110-
-- while "!(func();)" simply translates into "func();" (because "outputValue(func();)" would be invalid Lua code).
111-
-- Though in this specific case a preprocessor line would be nicer:
108+
!( func() ) -- This will bee seen as an inline block and output whatever value func() returns as a literal.
109+
!( func(); ) -- If that's not wanted then a trailing `;` will prevent that. This line won't output anything by itself.
110+
-- When the full metaprogram is generated, `!(func())` translates into `outputValue(func())`
111+
-- while `!(func();)` simply translates into `func();` (because `outputValue(func();)` would be invalid Lua code).
112+
-- Though in this specific case a preprocessor line (without the parenthesis) would be nicer:
112113
!func()
113114
114-
--============================================================]]
115+
-- For the full documentation, see: https://github.com/ReFreezed/LuaPreprocess/wiki
115116
117+
--============================================================]]
116118

117119

118-
--[[ Make sure the library doesn't add globals.
119-
setmetatable(_G, {__newindex=function(_G, k, v)
120-
print(debug.traceback("WARNING: Setting global '"..tostring(k).."'.", 2))
121-
rawset(_G, k, v)
122-
end})
123-
--]]
124120

125121
local PP_VERSION = "1.12.0"
126122

@@ -206,7 +202,7 @@ local _tokenize
206202
local assertarg
207203
local copyTable
208204
local countString, countSubString
209-
local error, errorline, errorOnLine, errorInFile, errorAtToken
205+
local error, errorLine, errorOnLine, errorInFile, errorAtToken
210206
local errorIfNotRunningMeta
211207
local escapePattern
212208
local F, tryToFormatError
@@ -232,9 +228,9 @@ function tryToFormatError(err0)
232228
local err, path, ln = nil
233229

234230
if type(err0) == "string" then
235-
do path, ln, err = err0:match'^(%a:[%w_/\\.]+):(%d+): (.*)'
236-
if not err then path, ln, err = err0:match'^([%w_/\\.]+):(%d+): (.*)'
237-
if not err then path, ln, err = err0:match'^(.-):(%d+): (.*)'
231+
do path, ln, err = err0:match"^(%a:[%w_/\\.]+):(%d+): (.*)"
232+
if not err then path, ln, err = err0:match"^([%w_/\\.]+):(%d+): (.*)"
233+
if not err then path, ln, err = err0:match"^(.-):(%d+): (.*)"
238234
end end end
239235
end
240236

@@ -296,7 +292,7 @@ function error(err, level)
296292
currentErrorHandler(err, level)
297293
end
298294

299-
function errorline(err)
295+
function errorLine(err)
300296
print(tryToFormatError(err))
301297
currentErrorHandler(err, 2)
302298
end
@@ -674,9 +670,14 @@ function _tokenize(s, path, allowMetaTokens, allowBacktickStrings, allowJitSynta
674670

675671
-- Preprocessor: Keyword.
676672
elseif allowMetaTokens and s:find("^@", ptr) then
677-
local i1, i2, repr, word = s:find("^(@([%a_][%w_]*))", ptr)
678-
ptr = i2+1
679-
tok = {type="pp_keyword", representation=repr, value=word}
673+
if s:find("^@@", ptr) then
674+
ptr = ptr+2
675+
tok = {type="pp_keyword", representation="@@", value="insert"}
676+
else
677+
local i1, i2, repr, word = s:find("^(@([%a_][%w_]*))", ptr)
678+
ptr = i2+1
679+
tok = {type="pp_keyword", representation=repr, value=word}
680+
end
680681

681682
else
682683
return nil, errorInFile(s, path, ptr, "Tokenizer", "Unknown character.")
@@ -1179,7 +1180,7 @@ function metaFuncs.run(path, ...)
11791180
assertarg(1, path, "string")
11801181

11811182
local mainChunk, err = loadLuaFile(path, metaEnv)
1182-
if not mainChunk then errorline(err) end
1183+
if not mainChunk then errorLine(err) end
11831184

11841185
-- We want multiple return values while avoiding a tail call to preserve stack info.
11851186
local returnValues = pack(mainChunk(...))
@@ -1627,7 +1628,7 @@ local function processKeywords(tokensRaw, fileBuffers, params, stats)
16271628
if not (isTokenAndNotNil(tokNext, "string") or isTokenAndNotNil(tokNext, "identifier")) then
16281629
errorAtToken(
16291630
fileBuffers, ppKeywordTok, (tokNext and tokNext.position or ppKeywordTok.position+#ppKeywordTok.representation),
1630-
"Parser", "Expected a string or identifier after @insert."
1631+
"Parser", "Expected a string or identifier after %s.", ppKeywordTok.representation
16311632
)
16321633
end
16331634

@@ -1950,7 +1951,7 @@ local function _processFileOrString(params, isFile)
19501951
luaUnprocessed, err = getFileContents(pathIn)
19511952

19521953
if not luaUnprocessed then
1953-
errorline("Could not read file: "..err)
1954+
errorLine("Could not read file: "..err)
19541955
end
19551956

19561957
currentPathIn = params.pathIn
@@ -2376,7 +2377,7 @@ local function _processFileOrString(params, isFile)
23762377
if type(luaModified) == "string" then
23772378
lua = luaModified
23782379
elseif luaModified ~= nil then
2379-
errorline("onAfterMeta() did not return a string. (Got "..type(luaModified)..")")
2380+
errorLine("onAfterMeta() did not return a string. (Got "..type(luaModified)..")")
23802381
end
23812382
end
23822383

tests/quickTest.lua2p

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ a = a..!(b)..a -- Comment, string concat.
2222
!local bool = --[[ Just a multiline
2323
comment here...]] true
2424

25+
!local function wrapped(concept)
26+
print!("Get wrapped! Also, "..concept.."...")
27+
!end
28+
!wrapped("dogs")
29+
!wrapped("clouds")
30+
2531

2632

2733
!(
@@ -108,7 +114,7 @@ local ok = 1==1
108114

109115
!local function PASS_THROUGH(lua) return lua end
110116
local s = @insert PASS_THROUGH "foo"
111-
local t = @insert PASS_THROUGH { 496, b=true }
117+
local t = @@ PASS_THROUGH { 496, b=true } -- @@func() means the same as @insert func().
112118

113119
local f = @insert PASS_THROUGH(function(a, b)
114120
while true do

tests/quickTest.output.lua

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,18 @@ local ok = 1==1
6666
if not (ok) then error("Oh "..tonumber("7",10).." noes!") end
6767

6868
local s = "foo"
69-
local t = { 496, b=true }
69+
local t = { 496, b=true } -- @@func() means the same as @insert func().
7070

71+
local f = function(a, b)
72+
while true do
73+
repeat until arePlanetsAligned("mars", "jupiter")
74+
break
75+
end
76+
return "", nil
77+
end
7178

7279

80+
81+
-- Misc.
7382
print("dataFromCommandLine: Hello, world!")
7483
print("The end.")

tests/runExamples.cmd

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
CD /D "%~dp0.."
33

44
SETLOCAL EnableDelayedExpansion
5+
SET _fails=0
56

67
FOR /R examples %%G IN (*.lua2p) DO (
78
ECHO. & ECHO Processing example '%%~nxG'...
89
lua preprocess-cl.lua "%%G" --debug --silent
9-
IF !ERRORLEVEL! EQU 0 lua "%%~dpnG.lua"
10+
IF !ERRORLEVEL! EQU 0 ( lua "%%~dpnG.lua" ) ELSE ( SET /A "_fails=!_fails!+1" )
1011
)
1112

12-
ECHO. & ECHO All examples finished!
13+
ECHO.
14+
IF %_fails% EQU 0 ( ECHO Finished examples successfully. ) ELSE ( ECHO Finished examples with %_fails% failures. )

0 commit comments

Comments
 (0)