Skip to content

Commit

Permalink
Added a way to intercept output.
Browse files Browse the repository at this point in the history
Macros can use outputLua() and co. instead of returning code.
  • Loading branch information
ReFreezed committed Nov 16, 2021
1 parent 34a0498 commit b7675f3
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 10 deletions.
83 changes: 73 additions & 10 deletions preprocess.lua
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
- getCurrentPathIn, getCurrentPathOut
- getOutputSoFar, getOutputSizeSoFar, getCurrentLineNumberInOutput
- outputValue, outputLua, outputLuaTemplate
- startInterceptingOutput, stopInterceptingOutput
Search this file for 'EnvironmentTable' for more info.
Exported stuff from the library:
Expand Down Expand Up @@ -188,7 +189,8 @@ local isRunningMeta = false
local currentPathIn = ""
local currentPathOut = ""
local metaPathForErrorMessages = ""
local outputFromMeta = nil
local outputFromMetaStack = nil
local outputFromMeta = nil -- Top item in outputFromMetaStack.
local canOutputNil = true
local fastStrings = false

Expand Down Expand Up @@ -1321,6 +1323,8 @@ end


-- :EnvironmentTable
----------------------------------------------------------------

metaEnv = copyTable(_G, true) -- Include all standard Lua stuff.
metaEnv._G = metaEnv

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

-- getOutputSizeSoFar()
Expand All @@ -1497,7 +1501,7 @@ function metaFuncs.getOutputSizeSoFar()

local size = 0

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

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

local ln = 1

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

Expand Down Expand Up @@ -1825,9 +1829,34 @@ function metaFuncs.concatTokens(tokens)
return _concatTokens(tokens, nil, false, nil, nil)
end

-- startInterceptingOutput()
-- startInterceptingOutput( )
-- Start intercepting output until stopInterceptingOutput() is called.
-- The function can be called multiple times to intercept interceptions.
function metaFuncs.startInterceptingOutput()
errorIfNotRunningMeta(2)

outputFromMeta = {}
tableInsert(outputFromMetaStack, outputFromMeta)
end

-- stopInterceptingOutput()
-- luaString = stopInterceptingOutput( )
-- Stop intercepting output.
function metaFuncs.stopInterceptingOutput()
errorIfNotRunningMeta(2)

local interceptedLua = tableRemove(outputFromMetaStack)
outputFromMeta = outputFromMetaStack[#outputFromMetaStack] or error("Called stopInterceptingOutput() before calling startInterceptingOutput()", 2)

return table.concat(interceptedLua)
end

-- Extra stuff used by the command line program:
metaFuncs.tryToFormatError = tryToFormatError

----------------------------------------------------------------



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

local function finalizeMacro(lua)
if lua == nil then
return (metaFuncs.stopInterceptingOutput())
elseif type(lua) ~= "string" then
error("[Macro] Value is not Lua code.", 2)
elseif outputFromMeta[1] then
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.
else
metaFuncs.stopInterceptingOutput() -- Returns "" because nothing was outputted.
return lua
end
end
function metaEnv.__MACRO()
metaFuncs.startInterceptingOutput()
return finalizeMacro
end

function metaEnv.__EVALSYMBOL(v)
if type(v) == "function" then
v = v()
Expand Down Expand Up @@ -2152,13 +2198,18 @@ end

local function expandMacro(tokens, fileBuffers, tokenStack, macroStartTok, isNested)
-- @Robustness: Make sure key tokens came from the same source file.

-- Add '!!(' for start of preprocessor block.
if isNested then
tableInsert(tokens, newTokenAt({type="identifier", value="__ASSERTLUA", representation="__ASSERTLUA"}, macroStartTok))
else
tableInsert(tokens, newTokenAt({type="pp_entry", value="!!", representation="!!", double=true}, macroStartTok))
if not isNested then
tableInsert(tokens, newTokenAt({type="pp_entry", value="!!", representation="!!", double=true}, macroStartTok))
tableInsert(tokens, newTokenAt({type="punctuation", value="(", representation="(" }, macroStartTok))
end
tableInsert(tokens, newTokenAt({type="punctuation", value="(", representation="("}, macroStartTok))

-- Start macro wrapper.
tableInsert(tokens, newTokenAt({type="identifier", value="__MACRO", representation="__MACRO" }, macroStartTok))
tableInsert(tokens, newTokenAt({type="punctuation", value="(", representation="(" }, macroStartTok))
tableInsert(tokens, newTokenAt({type="punctuation", value=")", representation=")" }, macroStartTok))
tableInsert(tokens, newTokenAt({type="punctuation", value="(", representation="(" }, macroStartTok))

--
-- Callee.
Expand Down Expand Up @@ -2496,8 +2547,13 @@ local function expandMacro(tokens, fileBuffers, tokenStack, macroStartTok, isNes
-- End.
--

-- Add ')' for end of preprocessor block.
-- End macro wrapper.
tableInsert(tokens, newTokenAt({type="punctuation", value=")", representation=")"}, tokens[#tokens]))

-- Add ')' for end of preprocessor block.
if not isNested then
tableInsert(tokens, newTokenAt({type="punctuation", value=")", representation=")"}, tokens[#tokens]))
end
end

local function doLateExpansionsMacros(tokensToExpand, fileBuffers, params, stats)
Expand Down Expand Up @@ -2969,6 +3025,7 @@ local function _processFileOrString(params, isFile)

metaPathForErrorMessages = params.pathMeta or "<meta>"
outputFromMeta = {}
outputFromMetaStack = {outputFromMeta}
canOutputNil = params.canOutputNil ~= false
fastStrings = params.fastStrings

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

if outputFromMetaStack[2] then
error("Called startInterceptingOutput() more times than stopInterceptingOutput().")
end

local lua = table.concat(outputFromMeta)
--[[ :PrintCode
print("=OUTPUT=============================")
Expand All @@ -3002,6 +3063,7 @@ local function _processFileOrString(params, isFile)
--]]

metaPathForErrorMessages = ""
outputFromMetaStack = nil
outputFromMeta = nil
canOutputNil = true

Expand Down Expand Up @@ -3103,6 +3165,7 @@ local function processFileOrString(params, isFile)
currentPathIn = ""
currentPathOut = ""
metaPathForErrorMessages = ""
outputFromMetaStack = nil
outputFromMeta = nil
canOutputNil = true
fastStrings = false
Expand Down
12 changes: 12 additions & 0 deletions tests/quickTest.lua2p
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,18 @@ local n = @@t.field[keys[1]]:method(58)
local n1 = @@ADD1!(43-2)
local n2 = @@ADD1!!("43-2")

!local function FOO1(x) return x end
!local function FOO2(x) outputLua(x) end
local x = 7
local y = @@FOO1(x)
local y = @@FOO2(x)

!startInterceptingOutput()
a = some
other = 500921
!local lua = stopInterceptingOutput():gsub("%a+", "%0Derp")
!!(lua)



-- Symbols.
Expand Down
7 changes: 7 additions & 0 deletions tests/quickTest.output.lua
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@ local n = 58
local n1 = 41+1
local n2 = 43-2+1

local x = 7
local y = x
local y = x

aDerp = someDerp
otherDerp = 500921



-- Symbols
Expand Down
23 changes: 23 additions & 0 deletions tests/suite.lua
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,13 @@ doTest("Macros", function()

-- Invalid: Nested code block in macro.
assert(not pp.processString{ code=[[ !(function ECHO(v) return v end) v = @@ECHO( !!( !(1) ) ) ]]})

-- Using outputLua().
assertCodeOutput(assert(pp.processString{ code=[[ !(function Y() return ("y") end) x = @@Y() ]]}), [[x = y]])
assertCodeOutput(assert(pp.processString{ code=[[ !(function Y() outputLua("y") end) x = @@Y() ]]}), [[x = y]])

-- Invalid: Both using outputLua() and returning code.
assert(not pp.processString{ code=[[ !(function Y() outputLua("y") ; return "z" end) x = @@Y() ]]})
end)

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

doTest("Output interception", function()
local pp = ppChunk()

local luaOut = assert(pp.processString{ code=[[
!startInterceptingOutput()
local foo = bar
!local lua = stopInterceptingOutput():gsub("(%a+) *= *(%a+)", "%2 = %1")
$lua
]] })
assertCodeOutput(luaOut, [[local bar = foo]])

-- Invalid: Unbalanced interception start/stop calls.
assert(not pp.processString{ code=[[ !startInterceptingOutput() ]]})
assert(not pp.processString{ code=[[ !stopInterceptingOutput() ]]})
end)



addLabel("Command line")
Expand Down

0 comments on commit b7675f3

Please sign in to comment.