Skip to content

Commit ffd695a

Browse files
committed
Fixed evaluate() sometimes raising an error instead of returning it.
Checking for duplicate names in `!!...`. Added more tests.
1 parent dbdd356 commit ffd695a

File tree

5 files changed

+70
-15
lines changed

5 files changed

+70
-15
lines changed

preprocess-cl.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ for i, pathIn in ipairs(pathsIn) do
536536
-- it's better if the user can choose whether to handle a message or not!
537537
--
538538
if lua == nil and type(messageHandler) == "function" then
539-
return assert(pp.getFileContents(name))
539+
return assert(pp.readFile(name))
540540
end
541541

542542
return lua

preprocess.lua

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,7 +1136,7 @@ end
11361136
-- value = evaluate( expression [, environment=getfenv() ] )
11371137
-- Returns nil and a message on error.
11381138
local function evaluate(expression, env)
1139-
local chunk, err = loadLuaString("return "..expression, "@", (env or getfenv(2)))
1139+
local chunk, err = loadLuaString("return "..expression, "@<evaluate>", (env or getfenv(2)))
11401140
if not chunk then
11411141
return nil, F("Invalid expression '%s'. (%s)", expression, (err:gsub("^:%d+: ", "")))
11421142
end
@@ -1145,7 +1145,10 @@ local function evaluate(expression, env)
11451145
return nil, F("Ambiguous expression '%s'. (Comma-separated list?)", expression)
11461146
end
11471147

1148-
return (chunk())
1148+
local ok, valueOrErr = pcall(chunk)
1149+
if not ok then return nil, valueOrErr end
1150+
1151+
return valueOrErr -- May be nil or false!
11491152
end
11501153

11511154

@@ -2658,6 +2661,8 @@ local function astParseMetaLine(tokens)
26582661
tokNext, iNext = getNextUsableToken(tokens, tokens.nextI, nil, 1)
26592662
end
26602663

2664+
local usedNames = {}
2665+
26612666
while true do
26622667
if not isTokenAndNotNil(tokNext, "identifier") then
26632668
local tok = tokNext or tokens[#tokens]
@@ -2666,10 +2671,18 @@ local function astParseMetaLine(tokens)
26662671
(astOutNode.names[1] and "" or "'local' or "),
26672672
getRelativeLocationText(ppEntryTok, tok)
26682673
)
2674+
elseif usedNames[tokNext.value] then
2675+
errorAtToken(
2676+
tokNext, nil, "Parser/DualCodeLine", "Duplicate name '%s' in %s. (Preprocessor line starts %s)",
2677+
tokNext.value,
2678+
(astOutNode.isDeclaration and "declaration" or "assignment"),
2679+
getRelativeLocationText(ppEntryTok, tokNext)
2680+
)
26692681
end
2670-
tableInsert(astOutNode.names, tokNext.value) -- @Robustness: Check for duplicate names.
2671-
tokens.nextI = iNext + 1 -- after the identifier
2672-
tokNext, iNext = getNextUsableToken(tokens, tokens.nextI, nil, 1)
2682+
tableInsert(astOutNode.names, tokNext.value)
2683+
usedNames[tokNext.value] = tokNext
2684+
tokens.nextI = iNext + 1 -- after the identifier
2685+
tokNext, iNext = getNextUsableToken(tokens, tokens.nextI, nil, 1)
26732686

26742687
if not isTokenAndNotNil(tokNext, "punctuation", ",") then break end
26752688
tokens.nextI = iNext + 1 -- after ','
@@ -2911,7 +2924,7 @@ local function astParseMacro(params, tokens)
29112924
-- @insert identifier ( argument1, ... )
29122925
elseif isTokenAndNotNil(tokNext, "punctuation", "(") then
29132926
-- Apply the same 'ambiguous syntax' rule as Lua. (Will comments mess this check up?)
2914-
if isTokenAndNotNil(tokens[iNext-1], "whitespace") and tokens[iNext-1].value:find"\n" then
2927+
if isTokenAndNotNil(tokens[iNext-1], "whitespace") and tokens[iNext-1].value:find("\n", 1, true) then
29152928
errorAtToken(tokNext, nil, "Parser/Macro", "Ambiguous syntax near '(' - part of macro, or new statement?")
29162929
end
29172930

tests/quickTest.lua2p

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ print("The end.")
218218

219219
!(
220220
--[==[ Test token stuff.
221-
for i, token in ipairs(assert(tokenize(assert(getFileContents"tests/quickTestInclude.lua")))) do
221+
for i, token in ipairs(assert(tokenize(assert(readFile"tests/quickTestInclude.lua")))) do
222222
print(i, token.type, "", (token.representation:gsub("\n", "<NEWLINE>")))
223223
end
224224

tests/runTestSuite.cmd

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@ CD /D "%~dp0.."
33

44
IF NOT EXIST local MD local
55

6-
lua tests/suite.lua
6+
SET _lua=%1
7+
IF [%_lua%]==[] SET _lua=lua
8+
9+
%_lua% tests/suite.lua

tests/suite.lua

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,16 @@ local results = {}
1111
local function doTest(description, f, ...)
1212
print("Running test: "..description)
1313

14-
-- f(...) -- DEBUG
1514
local ok, err = pcall(f, ...)
1615
if not ok then print("Error: "..tostring(err)) end
1716

1817
table.insert(results, {description=description, ok=ok})
1918
end
19+
local function doTestUnprotected(description, f, ...)
20+
print("Running test: "..description)
21+
f(...)
22+
table.insert(results, {description=description, ok=true})
23+
end
2024
local function addLabel(label)
2125
table.insert(results, {label=label})
2226
end
@@ -158,6 +162,9 @@ doTest("Dual code", function()
158162
!!local n, s = 5^5, "foo".."bar";
159163
]]})
160164
assertCodeOutput(luaOut, [[local n, s = 3125, "foobar";]])
165+
166+
-- Invalid: Duplicate names.
167+
assert(not pp.processString{ code=[[ !!x, y, x = 0 ]]})
161168
end)
162169

163170
doTest("Expression or not?", function()
@@ -314,7 +321,7 @@ doTest("Macros", function()
314321
]]})
315322
assertCodeOutput(luaOut, [[v = woof_woof_woof_woof_woof_woof_woof_woof]])
316323

317-
-- Code blocks in macros.
324+
-- Metaprogram code in macros.
318325
assertCodeOutput(assert(pp.processString{ code=[[ !(function ECHO(v) return v end) n = @@ECHO( !( 1 ) ) ]]}), [[n = 1]] )
319326
assertCodeOutput(assert(pp.processString{ code=[[ !(function ECHO(v) return v end) n = @@ECHO( !!("1") ) ]]}), [[n = 1]] )
320327
assertCodeOutput(assert(pp.processString{ code=[[ !(function ECHO(v) return v end) n = @@ECHO{ !( 1 ) } ]]}), [[n = { 1 }]] )
@@ -336,6 +343,24 @@ doTest("Macros", function()
336343
assertCodeOutput(assert(pp.processString{ code=[[ !(function ECHO(v) return v end) n = @@ECHO( !(do outputLua"1" end) ) ]]}), [[n = 1]] )
337344
assertCodeOutput(assert(pp.processString{ code=[[ !(function ECHO(v) return v end) n = @@ECHO{ !(do outputLua"1" end) } ]]}), [[n = { 1 }]] )
338345

346+
local luaOut = assert(pp.processString{ code=[[
347+
!function ECHO(v) return v end
348+
n = @@ECHO(
349+
!outputLua("1")
350+
)
351+
]]})
352+
assertCodeOutput(luaOut, [[n = 1]])
353+
354+
-- Prefixes/suffixes.
355+
assert(pp.processString{ macroPrefix="MACRO_", code=[[
356+
!local function MACRO_FOO() return "" end
357+
@@FOO()
358+
]]})
359+
assert(pp.processString{ macroSuffix="_MACRO", code=[[
360+
!local function FOO_MACRO() return "" end
361+
@@FOO()
362+
]]})
363+
339364
-- Invalid code in arguments (which is ok).
340365
local luaOut = assert(pp.processString{ code=[[
341366
!function BINOP(operator, a, b) return a..operator..b end
@@ -591,10 +616,13 @@ doTest("Resources and evaluation", function()
591616
onInsert = function(name) return name end,
592617
})
593618

594-
assert(pp.processString{
595-
code = [[ !x = 8 ; assert(evaluate("2^x") == 2^x) ]],
596-
onInsert = function(name) return name end,
597-
})
619+
_G. x = 8 ; assert(pp.evaluate("2^x" ) == 2^x) ; _G.x = nil
620+
local x = 8 ; assert(pp.evaluate("2^x", {x=x}) == 2^x)
621+
assert(not pp.evaluate("2^x")) -- (Global) x should be nil.
622+
623+
if jit then
624+
assert(assert(pp.evaluate"0b101") == 5)
625+
end
598626
end)
599627

600628
doTest("Indentation", function()
@@ -603,6 +631,9 @@ doTest("Indentation", function()
603631
assert(pp.getIndentation(" \t foo") == " \t ")
604632
assert(pp.getIndentation(" \n foo") == " ")
605633

634+
assertCodeOutput(assert(pp.processString{ code= "\t \tindent = !(getCurrentIndentationInOutput(4))" }), [[indent = 8]])
635+
assertCodeOutput(assert(pp.processString{ code="\n\n\t \tindent = !(getCurrentIndentationInOutput(4))\n\n"}), [[indent = 8]])
636+
606637
-- Spaces.
607638
local indent, expect = pp.getIndentation("" , 4), 0 ; if indent ~= expect then error(expect.." "..indent) end
608639
local indent, expect = pp.getIndentation(" " , 4), 1 ; if indent ~= expect then error(expect.." "..indent) end
@@ -626,6 +657,9 @@ end)
626657
doTest("Misc.", function()
627658
local pp = ppChunk()
628659

660+
assert(pp.metaEnvironment.table == table)
661+
662+
-- Natural comparisons.
629663
assert( ("foo9" < "foo10") == false)
630664
assert(pp.compareNatural("foo9", "foo10") == true )
631665

@@ -642,6 +676,11 @@ doTest("Misc.", function()
642676
assert(keys[order] == k)
643677
end
644678
end
679+
680+
-- Current output.
681+
assertCodeOutput(assert(pp.processString{ code="x = 1 ; y = !(getOutputSoFar())" }), 'x = 1 ; y = "x = 1 ; y = "')
682+
assertCodeOutput(assert(pp.processString{ code="x = !(getOutputSoFarOnLine ())\n\ty = !(getOutputSoFarOnLine ())"}), 'x = "x = "\n\ty = "\\ty = "')
683+
assertCodeOutput(assert(pp.processString{ code="x = !(getCurrentLineNumberInOutput())\n\ty = !(getCurrentLineNumberInOutput())"}), "x = 1\n\ty = 2")
645684
end)
646685

647686

0 commit comments

Comments
 (0)