Skip to content

Commit 99395d5

Browse files
committed
Dual code now supports multiple identifiers: !!x,y=...
1 parent 6c47475 commit 99395d5

File tree

4 files changed

+94
-79
lines changed

4 files changed

+94
-79
lines changed

preprocess.lua

Lines changed: 78 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ local assertarg
201201
local cleanError
202202
local copyTable
203203
local countString, countSubString
204-
local errorf, errorLine, errorfLine, errorOnLine, errorInFile, errorAtToken
204+
local errorf, errorLine, errorfLine, errorOnLine, errorInFile, errorAtToken, errorAfterToken
205205
local errorIfNotRunningMeta
206206
local escapePattern
207207
local F, tryToFormatError
@@ -382,6 +382,11 @@ function errorAtToken(fileBuffers, tok, pos, agent, s, ...)
382382
errorInFile(fileBuffers[tok.file], tok.file, (pos or tok.position), agent, s, ...)
383383
end
384384

385+
-- errorAfterToken( fileBuffers, token, agent, s, ... )
386+
function errorAfterToken(fileBuffers, tok, agent, s, ...)
387+
errorInFile(fileBuffers[tok.file], tok.file, tok.position+#tok.representation, agent, s, ...)
388+
end
389+
385390

386391

387392
function cleanError(err)
@@ -1171,15 +1176,16 @@ end
11711176

11721177

11731178
-- token, index = getNextUsableToken( tokens, startIndex [, indexLimit, direction=1 ] )
1174-
function getNextUsableToken(tokens, i, iLimit, dir)
1179+
function getNextUsableToken(tokens, iStart, iLimit, dir)
11751180
dir = dir or 1
11761181

1177-
iLimit
1178-
= dir < 0
1182+
iLimit = (
1183+
dir < 0
11791184
and math.max((iLimit or 1 ), 1)
11801185
or math.min((iLimit or 1/0), #tokens)
1186+
)
11811187

1182-
for i = i, iLimit, dir do
1188+
for i = iStart, iLimit, dir do
11831189
if not USELESS_TOKENS[tokens[i].type] then
11841190
return tokens[i], i
11851191
end
@@ -2242,71 +2248,52 @@ local function _processFileOrString(params, isFile)
22422248
-- !!x = ...
22432249

22442250
-- Check whether local or not.
2245-
local tok, i = getNextUsableToken(tokens, metaLineIndexStart, metaLineIndexEnd)
2246-
if not tok then
2247-
errorAtToken(fileBuffers, tokens[metaLineIndexStart], nil, "Parser/DualCodeLine", "Unexpected end of preprocessor line.")
2248-
end
2249-
2250-
local isLocal = isToken(tok, "keyword", "local")
2251+
local iPrev, tok, i = metaLineIndexStart-1, getNextUsableToken(tokens, metaLineIndexStart, metaLineIndexEnd)
2252+
local isLocal = isTokenAndNotNil(tok, "keyword", "local")
22512253

22522254
if isLocal then
2253-
tok, i = getNextUsableToken(tokens, i+1, metaLineIndexEnd)
2254-
if not tok then
2255-
errorAtToken(fileBuffers, tokens[metaLineIndexStart], nil, "Parser/DualCodeLine", "Unexpected end of preprocessor line.")
2256-
end
2255+
iPrev, tok, i = i, getNextUsableToken(tokens, i+1, metaLineIndexEnd)
22572256
end
22582257

22592258
-- Check for identifier.
2260-
-- @Incomplete: Support multiple assignments. :MultipleAssignments
2261-
if not isToken(tok, "identifier") then
2262-
errorAtToken(fileBuffers, tok, nil, "Parser/DualCodeLine", "Expected an identifier.")
2259+
if isTokenAndNotNil(tok, "identifier") then
2260+
-- void
2261+
elseif isLocal then
2262+
errorAfterToken(fileBuffers, tokens[iPrev], "Parser/DualCodeLine", "Expected an identifier.")
2263+
else
2264+
errorAfterToken(fileBuffers, tokens[iPrev], "Parser/DualCodeLine", "Expected an identifier or 'local'.")
22632265
end
22642266

2265-
local identTok = tok
2266-
local ident = identTok.value
2267+
local identTokens = {tok}
2268+
iPrev, tok, i = i, getNextUsableToken(tokens, i+1, metaLineIndexEnd)
2269+
2270+
while isTokenAndNotNil(tok, "punctuation", ",") do
2271+
iPrev, tok, i = i, getNextUsableToken(tokens, i+1, metaLineIndexEnd)
2272+
if not isTokenAndNotNil(tok, "identifier") then
2273+
errorAfterToken(fileBuffers, tokens[iPrev], "Parser/DualCodeLine", "Expected an identifier after ','.")
2274+
end
2275+
2276+
tableInsert(identTokens, tok)
2277+
iPrev, tok, i = i, getNextUsableToken(tokens, i+1, metaLineIndexEnd)
2278+
end
22672279

22682280
-- Check for "=".
2269-
tok, i = getNextUsableToken(tokens, i+1, metaLineIndexEnd)
2270-
if not tok then
2271-
errorAtToken(fileBuffers, tokens[metaLineIndexStart], nil, "Parser/DualCodeLine", "Unexpected end of preprocessor line.")
2272-
elseif isToken(tok, "punctuation", ",") then
2273-
-- :MultipleAssignments
2274-
errorAtToken(fileBuffers, identTok, nil, "Parser/DualCodeLine", "Preprocessor line must be a single assignment. (Multiple assignments are not supported.)")
2275-
elseif not isToken(tok, "punctuation", "=") then
2276-
errorAtToken(fileBuffers, identTok, nil, "Parser/DualCodeLine", "Preprocessor line must be an assignment.")
2281+
if not isTokenAndNotNil(tok, "punctuation", "=") then
2282+
errorAfterToken(fileBuffers, tokens[iPrev], "Parser/DualCodeLine", "Expected '='.")
22772283
end
22782284

22792285
local indexAfterEqualSign = i+1
22802286

2281-
if not getNextUsableToken(tokens, indexAfterEqualSign, metaLineIndexEnd) then
2282-
errorAtToken(fileBuffers, tok, nil, "Parser/DualCodeLine", "Unexpected end of preprocessor line.")
2283-
end
2284-
22852287
-- Check if the rest of the line is an expression.
2286-
if true then
2287-
local lastUsableToken, lastUsableIndex = getNextUsableToken(tokens, metaLineIndexEnd, 1, -1)
2288+
local parts = {"return'',"}
2289+
insertTokenRepresentations(parts, tokens, indexAfterEqualSign, metaLineIndexEnd)
22882290

2289-
local parts = {"return ("}
2290-
if isToken(lastUsableToken, "punctuation", ";") then
2291-
insertTokenRepresentations(parts, tokens, indexAfterEqualSign, lastUsableIndex-1)
2291+
if not loadLuaString(table.concat(parts)) then
2292+
iPrev, tok, i = i, getNextUsableToken(tokens, indexAfterEqualSign, metaLineIndexEnd)
2293+
if tok then
2294+
errorAtToken(fileBuffers, tok, nil, "Parser/DualCodeLine", "Invalid value expression after '='.")
22922295
else
2293-
insertTokenRepresentations(parts, tokens, indexAfterEqualSign, metaLineIndexEnd)
2294-
end
2295-
tableInsert(parts, "\n)")
2296-
2297-
if not loadLuaString(table.concat(parts), "@") then
2298-
parts = {"testValue = "}
2299-
if isToken(lastUsableToken, "punctuation", ";") then
2300-
insertTokenRepresentations(parts, tokens, indexAfterEqualSign, lastUsableIndex-1)
2301-
else
2302-
insertTokenRepresentations(parts, tokens, indexAfterEqualSign, metaLineIndexEnd)
2303-
end
2304-
2305-
if loadLuaString(table.concat(parts), "@") then
2306-
errorAtToken(fileBuffers, tokens[metaLineIndexStart], nil, "Parser/DualCodeLine", "Preprocessor line must be a single assignment statement.")
2307-
else
2308-
-- void (A normal Lua error will trigger later.)
2309-
end
2296+
errorAfterToken(fileBuffers, tokens[indexAfterEqualSign-1], "Parser/DualCodeLine", "Invalid value expression after '='.")
23102297
end
23112298
end
23122299

@@ -2323,12 +2310,25 @@ local function _processFileOrString(params, isFile)
23232310
outputLineNumber(metaParts, tokens[metaLineIndexStart].line)
23242311
end
23252312

2326-
if isLocal then tableInsert(metaParts, 'local ') end
2313+
if isLocal then tableInsert(metaParts, "local ") end
23272314

2328-
tableInsert(metaParts, ident)
2329-
tableInsert(metaParts, ' = "); __VAL(')
2330-
tableInsert(metaParts, ident)
2331-
tableInsert(metaParts, '); __LUA("\\n")\n')
2315+
for identIndex, identTok in ipairs(identTokens) do
2316+
if identIndex > 1 then tableInsert(metaParts, ", ") end
2317+
tableInsert(metaParts, identTok.value)
2318+
end
2319+
tableInsert(metaParts, ' = ")')
2320+
for identIndex, identTok in ipairs(identTokens) do
2321+
if identIndex > 1 then tableInsert(metaParts, '; __LUA(", ")') end
2322+
tableInsert(metaParts, "; __VAL(")
2323+
tableInsert(metaParts, identTok.value)
2324+
tableInsert(metaParts, ")")
2325+
end
2326+
2327+
if isToken(getNextUsableToken(tokens, metaLineIndexEnd, 1, -1), "punctuation", ";") then
2328+
tableInsert(metaParts, '; __LUA(";\\n");\n')
2329+
else
2330+
tableInsert(metaParts, '; __LUA("\\n")\n')
2331+
end
23322332

23332333
else
23342334
tableInsert(metaParts, '__LUA"')
@@ -2337,18 +2337,31 @@ local function _processFileOrString(params, isFile)
23372337
outputLineNumber(metaParts, tokens[metaLineIndexStart].line)
23382338
end
23392339

2340-
if isLocal then tableInsert(metaParts, 'local ') end
2340+
if isLocal then tableInsert(metaParts, "local ") end
23412341

2342-
tableInsert(metaParts, ident)
2343-
tableInsert(metaParts, ' = "__VAL(')
2344-
tableInsert(metaParts, ident)
2345-
tableInsert(metaParts, ')__LUA"\\n"\n')
2342+
for identIndex, identTok in ipairs(identTokens) do
2343+
if identIndex > 1 then tableInsert(metaParts, ", ") end
2344+
tableInsert(metaParts, identTok.value)
2345+
end
2346+
tableInsert(metaParts, ' = "')
2347+
for identIndex, identTok in ipairs(identTokens) do
2348+
if identIndex > 1 then tableInsert(metaParts, '__LUA", "') end
2349+
tableInsert(metaParts, "__VAL(")
2350+
tableInsert(metaParts, identTok.value)
2351+
tableInsert(metaParts, ")")
2352+
end
2353+
2354+
if isToken(getNextUsableToken(tokens, metaLineIndexEnd, 1, -1), "punctuation", ";") then
2355+
tableInsert(metaParts, '__LUA";\\n";\n')
2356+
else
2357+
tableInsert(metaParts, '__LUA"\\n"\n')
2358+
end
23462359
end
23472360

23482361
flushTokensToProcess()
23492362
end--outputFinalDualValueStatement()
23502363

2351-
-- Note: Can be multiple lines if extended.
2364+
-- Note: Can be multiple actual lines if extended.
23522365
local function processMetaLine(isDual, metaStartTok)
23532366
local metaLineIndexStart = tokenIndex
23542367
local bracketBalance = 0

tests/quickTest.lua2p

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,10 @@ local z = !(z)
6161

6262

6363
-- Dual code. (Outputs both both preprocessor code and normal Lua. Can only be used for assignment statements.)
64-
!!local alpha = "[%a_]"
65-
!!local alphanum = "[%a%d_]"
66-
!!local num = "%"..justTheLetterD -- The value expression is evaluated in the metaprogram before outputted to the final program.
67-
!!local ident = alpha..alphanum.."*"
68-
local funcCall = !(ident.."%(.-%)")
64+
!!local alpha, alphanum = "[%a_]", "[%a%d_]"
65+
!!local num = "%"..justTheLetterD -- The value expression is evaluated in the metaprogram before outputted to the final program.
66+
!!local ident = alpha..alphanum.."*"
67+
local funcCall = !(ident.."%(.-%)")
6968

7069
local s = [[:: 2 * hello5( foo ){ ... }]]
7170
print(s:match(ident)) -- "hello5"

tests/quickTest.output.lua

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,10 @@ local z = 137
4141

4242

4343
-- Dual code. (Outputs both both preprocessor code and normal Lua. Can only be used for assignment statements.)
44-
local alpha = "[%a_]"
45-
local alphanum = "[%a%d_]"
46-
local num = "%d"
47-
local ident = "[%a_][%a%d_]*"
48-
local funcCall = "[%a_][%a%d_]*%(.-%)"
44+
local alpha, alphanum = "[%a_]", "[%a%d_]"
45+
local num = "%d"
46+
local ident = "[%a_][%a%d_]*"
47+
local funcCall = "[%a_][%a%d_]*%(.-%)"
4948

5049
local s = [[:: 2 * hello5( foo ){ ... }]]
5150
print(s:match(ident)) -- "hello5"

tests/runTests.lua

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,14 +137,18 @@ end)
137137

138138
doTest("Dual code", function()
139139
local pp = assert(loadfile"preprocess.lua")()
140-
local luaIn = [[
140+
141+
local luaOut = assert(pp.processString{ code=[[
141142
!local one = 1
142143
!local two = 2
143144
!!local sum = one+two -- The expression is evaluated in the metaprogram.
144-
]]
145-
146-
local luaOut = assert(pp.processString{ code=luaIn })
145+
]]})
147146
assertCodeOutput(luaOut, [[local sum = 3]])
147+
148+
local luaOut = assert(pp.processString{ code=[[
149+
!!local n, s = 5^5, "foo".."bar";
150+
]]})
151+
assertCodeOutput(luaOut, [[local n, s = 3125, "foobar";]])
148152
end)
149153

150154
doTest("Expression or not?", function()

0 commit comments

Comments
 (0)