Skip to content

Commit b7675f3

Browse files
committed
Added a way to intercept output.
Macros can use outputLua() and co. instead of returning code.
1 parent 34a0498 commit b7675f3

File tree

4 files changed

+115
-10
lines changed

4 files changed

+115
-10
lines changed

preprocess.lua

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
- getCurrentPathIn, getCurrentPathOut
2727
- getOutputSoFar, getOutputSizeSoFar, getCurrentLineNumberInOutput
2828
- outputValue, outputLua, outputLuaTemplate
29+
- startInterceptingOutput, stopInterceptingOutput
2930
Search this file for 'EnvironmentTable' for more info.
3031
3132
Exported stuff from the library:
@@ -188,7 +189,8 @@ local isRunningMeta = false
188189
local currentPathIn = ""
189190
local currentPathOut = ""
190191
local metaPathForErrorMessages = ""
191-
local outputFromMeta = nil
192+
local outputFromMetaStack = nil
193+
local outputFromMeta = nil -- Top item in outputFromMetaStack.
192194
local canOutputNil = true
193195
local fastStrings = false
194196

@@ -1321,6 +1323,8 @@ end
13211323

13221324

13231325
-- :EnvironmentTable
1326+
----------------------------------------------------------------
1327+
13241328
metaEnv = copyTable(_G, true) -- Include all standard Lua stuff.
13251329
metaEnv._G = metaEnv
13261330

@@ -1485,7 +1489,7 @@ end
14851489
-- Raises an error if no file or string is being processed.
14861490
function metaFuncs.getOutputSoFar(asTable)
14871491
errorIfNotRunningMeta(2)
1488-
return asTable and copyArray(outputFromMeta) or table.concat(outputFromMeta)
1492+
return asTable and copyArray(outputFromMetaStack[1]) or table.concat(outputFromMetaStack[1]) -- Should there be a way to get the contents of outputFromMeta etc.? :GetMoreOutputFromStack
14891493
end
14901494

14911495
-- getOutputSizeSoFar()
@@ -1497,7 +1501,7 @@ function metaFuncs.getOutputSizeSoFar()
14971501

14981502
local size = 0
14991503

1500-
for _, lua in ipairs(outputFromMeta) do
1504+
for _, lua in ipairs(outputFromMetaStack[1]) do -- :GetMoreOutputFromStack
15011505
size = size + #lua
15021506
end
15031507

@@ -1512,7 +1516,7 @@ function metaFuncs.getCurrentLineNumberInOutput()
15121516

15131517
local ln = 1
15141518

1515-
for _, lua in ipairs(outputFromMeta) do
1519+
for _, lua in ipairs(outputFromMetaStack[1]) do -- :GetMoreOutputFromStack
15161520
ln = ln + countString(lua, "\n", true)
15171521
end
15181522

@@ -1825,9 +1829,34 @@ function metaFuncs.concatTokens(tokens)
18251829
return _concatTokens(tokens, nil, false, nil, nil)
18261830
end
18271831

1832+
-- startInterceptingOutput()
1833+
-- startInterceptingOutput( )
1834+
-- Start intercepting output until stopInterceptingOutput() is called.
1835+
-- The function can be called multiple times to intercept interceptions.
1836+
function metaFuncs.startInterceptingOutput()
1837+
errorIfNotRunningMeta(2)
1838+
1839+
outputFromMeta = {}
1840+
tableInsert(outputFromMetaStack, outputFromMeta)
1841+
end
1842+
1843+
-- stopInterceptingOutput()
1844+
-- luaString = stopInterceptingOutput( )
1845+
-- Stop intercepting output.
1846+
function metaFuncs.stopInterceptingOutput()
1847+
errorIfNotRunningMeta(2)
1848+
1849+
local interceptedLua = tableRemove(outputFromMetaStack)
1850+
outputFromMeta = outputFromMetaStack[#outputFromMetaStack] or error("Called stopInterceptingOutput() before calling startInterceptingOutput()", 2)
1851+
1852+
return table.concat(interceptedLua)
1853+
end
1854+
18281855
-- Extra stuff used by the command line program:
18291856
metaFuncs.tryToFormatError = tryToFormatError
18301857

1858+
----------------------------------------------------------------
1859+
18311860

18321861

18331862
for k, v in pairs(metaFuncs) do metaEnv[k] = v end
@@ -1845,6 +1874,23 @@ function metaEnv.__ASSERTLUA(lua)
18451874
return lua
18461875
end
18471876

1877+
local function finalizeMacro(lua)
1878+
if lua == nil then
1879+
return (metaFuncs.stopInterceptingOutput())
1880+
elseif type(lua) ~= "string" then
1881+
error("[Macro] Value is not Lua code.", 2)
1882+
elseif outputFromMeta[1] then
1883+
error("[Macro] Got Lua code from both value expression and outputLua(). Only one method may be used.", 2) -- It's also possible interception calls are unbalanced.
1884+
else
1885+
metaFuncs.stopInterceptingOutput() -- Returns "" because nothing was outputted.
1886+
return lua
1887+
end
1888+
end
1889+
function metaEnv.__MACRO()
1890+
metaFuncs.startInterceptingOutput()
1891+
return finalizeMacro
1892+
end
1893+
18481894
function metaEnv.__EVALSYMBOL(v)
18491895
if type(v) == "function" then
18501896
v = v()
@@ -2152,13 +2198,18 @@ end
21522198

21532199
local function expandMacro(tokens, fileBuffers, tokenStack, macroStartTok, isNested)
21542200
-- @Robustness: Make sure key tokens came from the same source file.
2201+
21552202
-- Add '!!(' for start of preprocessor block.
2156-
if isNested then
2157-
tableInsert(tokens, newTokenAt({type="identifier", value="__ASSERTLUA", representation="__ASSERTLUA"}, macroStartTok))
2158-
else
2159-
tableInsert(tokens, newTokenAt({type="pp_entry", value="!!", representation="!!", double=true}, macroStartTok))
2203+
if not isNested then
2204+
tableInsert(tokens, newTokenAt({type="pp_entry", value="!!", representation="!!", double=true}, macroStartTok))
2205+
tableInsert(tokens, newTokenAt({type="punctuation", value="(", representation="(" }, macroStartTok))
21602206
end
2161-
tableInsert(tokens, newTokenAt({type="punctuation", value="(", representation="("}, macroStartTok))
2207+
2208+
-- Start macro wrapper.
2209+
tableInsert(tokens, newTokenAt({type="identifier", value="__MACRO", representation="__MACRO" }, macroStartTok))
2210+
tableInsert(tokens, newTokenAt({type="punctuation", value="(", representation="(" }, macroStartTok))
2211+
tableInsert(tokens, newTokenAt({type="punctuation", value=")", representation=")" }, macroStartTok))
2212+
tableInsert(tokens, newTokenAt({type="punctuation", value="(", representation="(" }, macroStartTok))
21622213

21632214
--
21642215
-- Callee.
@@ -2496,8 +2547,13 @@ local function expandMacro(tokens, fileBuffers, tokenStack, macroStartTok, isNes
24962547
-- End.
24972548
--
24982549

2499-
-- Add ')' for end of preprocessor block.
2550+
-- End macro wrapper.
25002551
tableInsert(tokens, newTokenAt({type="punctuation", value=")", representation=")"}, tokens[#tokens]))
2552+
2553+
-- Add ')' for end of preprocessor block.
2554+
if not isNested then
2555+
tableInsert(tokens, newTokenAt({type="punctuation", value=")", representation=")"}, tokens[#tokens]))
2556+
end
25012557
end
25022558

25032559
local function doLateExpansionsMacros(tokensToExpand, fileBuffers, params, stats)
@@ -2969,6 +3025,7 @@ local function _processFileOrString(params, isFile)
29693025

29703026
metaPathForErrorMessages = params.pathMeta or "<meta>"
29713027
outputFromMeta = {}
3028+
outputFromMetaStack = {outputFromMeta}
29723029
canOutputNil = params.canOutputNil ~= false
29733030
fastStrings = params.fastStrings
29743031

@@ -2994,6 +3051,10 @@ local function _processFileOrString(params, isFile)
29943051
os.remove(params.pathMeta)
29953052
end
29963053

3054+
if outputFromMetaStack[2] then
3055+
error("Called startInterceptingOutput() more times than stopInterceptingOutput().")
3056+
end
3057+
29973058
local lua = table.concat(outputFromMeta)
29983059
--[[ :PrintCode
29993060
print("=OUTPUT=============================")
@@ -3002,6 +3063,7 @@ local function _processFileOrString(params, isFile)
30023063
--]]
30033064

30043065
metaPathForErrorMessages = ""
3066+
outputFromMetaStack = nil
30053067
outputFromMeta = nil
30063068
canOutputNil = true
30073069

@@ -3103,6 +3165,7 @@ local function processFileOrString(params, isFile)
31033165
currentPathIn = ""
31043166
currentPathOut = ""
31053167
metaPathForErrorMessages = ""
3168+
outputFromMetaStack = nil
31063169
outputFromMeta = nil
31073170
canOutputNil = true
31083171
fastStrings = false

tests/quickTest.lua2p

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,18 @@ local n = @@t.field[keys[1]]:method(58)
142142
local n1 = @@ADD1!(43-2)
143143
local n2 = @@ADD1!!("43-2")
144144

145+
!local function FOO1(x) return x end
146+
!local function FOO2(x) outputLua(x) end
147+
local x = 7
148+
local y = @@FOO1(x)
149+
local y = @@FOO2(x)
150+
151+
!startInterceptingOutput()
152+
a = some
153+
other = 500921
154+
!local lua = stopInterceptingOutput():gsub("%a+", "%0Derp")
155+
!!(lua)
156+
145157

146158

147159
-- Symbols.

tests/quickTest.output.lua

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ local n = 58
102102
local n1 = 41+1
103103
local n2 = 43-2+1
104104

105+
local x = 7
106+
local y = x
107+
local y = x
108+
109+
aDerp = someDerp
110+
otherDerp = 500921
111+
105112

106113

107114
-- Symbols

tests/suite.lua

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,13 @@ doTest("Macros", function()
369369

370370
-- Invalid: Nested code block in macro.
371371
assert(not pp.processString{ code=[[ !(function ECHO(v) return v end) v = @@ECHO( !!( !(1) ) ) ]]})
372+
373+
-- Using outputLua().
374+
assertCodeOutput(assert(pp.processString{ code=[[ !(function Y() return ("y") end) x = @@Y() ]]}), [[x = y]])
375+
assertCodeOutput(assert(pp.processString{ code=[[ !(function Y() outputLua("y") end) x = @@Y() ]]}), [[x = y]])
376+
377+
-- Invalid: Both using outputLua() and returning code.
378+
assert(not pp.processString{ code=[[ !(function Y() outputLua("y") ; return "z" end) x = @@Y() ]]})
372379
end)
373380

374381
doTest("Preprocessor symbols", function()
@@ -514,6 +521,22 @@ doTest("Serialize", function()
514521
assertCodeOutput(luaOut, [[{a=2,f=176,z=99}]]) -- Note: Table keys should be sorted.
515522
end)
516523

524+
doTest("Output interception", function()
525+
local pp = ppChunk()
526+
527+
local luaOut = assert(pp.processString{ code=[[
528+
!startInterceptingOutput()
529+
local foo = bar
530+
!local lua = stopInterceptingOutput():gsub("(%a+) *= *(%a+)", "%2 = %1")
531+
$lua
532+
]] })
533+
assertCodeOutput(luaOut, [[local bar = foo]])
534+
535+
-- Invalid: Unbalanced interception start/stop calls.
536+
assert(not pp.processString{ code=[[ !startInterceptingOutput() ]]})
537+
assert(not pp.processString{ code=[[ !stopInterceptingOutput() ]]})
538+
end)
539+
517540

518541

519542
addLabel("Command line")

0 commit comments

Comments
 (0)