Skip to content

Commit 7999e0a

Browse files
committed
Macro callees can now have lookups using square brackets.
1 parent 4670621 commit 7999e0a

File tree

4 files changed

+109
-41
lines changed

4 files changed

+109
-41
lines changed

preprocess.lua

Lines changed: 70 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1937,15 +1937,9 @@ local function doLateExpansionsResources(tokensToExpand, fileBuffers, params, st
19371937
local identTok = tokNext
19381938
tokNext, iNext = getNextUsableToken(tokenStack, iNext-1, nil, -1)
19391939

1940-
if isTokenAndNotNil(tokNext, "punctuation", "(") then
1941-
-- Apply the same 'ambiguous syntax' rule as Lua.
1942-
if isTokenAndNotNil(tokenStack[iNext+1], "whitespace") and tokenStack[iNext+1].value:find"\n" then
1943-
errorAtToken(fileBuffers, tokNext, nil, "Macro", "Ambiguous syntax near '(' - part of macro, or new statement?")
1944-
end
1945-
1946-
elseif not (tokNext and (
1940+
if not (tokNext and (
19471941
tokNext.type == "string"
1948-
or (tokNext.type == "punctuation" and isAny(tokNext.value, "{",".",":"))
1942+
or (tokNext.type == "punctuation" and isAny(tokNext.value, "(","{",".",":","["))
19491943
)) then
19501944
errorAtToken(fileBuffers, identTok, identTok.position+#identTok.representation, "Macro", "Syntax error: Expected '(' after macro name '%s'.", identTok.value)
19511945
end
@@ -2044,6 +2038,10 @@ local function expandMacro(tokens, fileBuffers, tokenStack, macroStartTok, isNes
20442038
end
20452039
tableInsert(tokens, newTokenAt({type="punctuation", value="(", representation="("}, macroStartTok))
20462040

2041+
--
2042+
-- Callee.
2043+
--
2044+
20472045
-- Add 'ident' for start of (or whole) callee.
20482046
local tokNext, iNext = getNextUsableToken(tokenStack, #tokenStack-1, nil, -1)
20492047
if not isTokenAndNotNil(tokNext, "identifier") then
@@ -2054,29 +2052,67 @@ local function expandMacro(tokens, fileBuffers, tokenStack, macroStartTok, isNes
20542052
tableInsert(tokens, tokNext)
20552053
local lastCalleeTok = tokNext
20562054

2057-
-- Maybe add '.field:method' for end of callee.
2058-
-- @Incomplete: @@name[expr]()
2055+
-- Maybe add '.field[expr]:method' for rest of callee.
20592056
tokNext, iNext = getNextUsableToken(tokenStack, #tokenStack, nil, -1)
20602057

2061-
while isTokenAndNotNil(tokNext, "punctuation") and (tokNext.value == "." or tokNext.value == ":") do
2062-
local punctTok = tokNext
2063-
local isMethodCall = (punctTok.value == ":")
2058+
while tokNext do
2059+
if isToken(tokNext, "punctuation", ".") or isToken(tokNext, "punctuation", ":") then
2060+
local punctTok = tokNext
2061+
popTokens(tokenStack, iNext) -- '.' or ':'
2062+
tableInsert(tokens, tokNext)
20642063

2065-
popTokens(tokenStack, iNext) -- '.' or ':'
2066-
tableInsert(tokens, tokNext)
2064+
tokNext, iNext = getNextUsableToken(tokenStack, #tokenStack, nil, -1)
2065+
if not tokNext then
2066+
errorAfterToken(fileBuffers, punctTok, "Macro", "Syntax error: Expected an identifier after '%s'.", punctTok.value)
2067+
end
2068+
popTokens(tokenStack, iNext) -- the identifier
2069+
tableInsert(tokens, tokNext)
20672070

2068-
tokNext, iNext = getNextUsableToken(tokenStack, #tokenStack, nil, -1)
2069-
if not tokNext then
2070-
errorAfterToken(fileBuffers, punctTok, "Macro", "Syntax error: Expected an identifier after '%s'.", punctTok.value)
2071-
end
2072-
popTokens(tokenStack, iNext) -- the identifier
2073-
tableInsert(tokens, tokNext)
2074-
lastCalleeTok = tokNext
2071+
lastCalleeTok = tokNext
2072+
tokNext, iNext = getNextUsableToken(tokenStack, #tokenStack, nil, -1)
20752073

2076-
tokNext, iNext = getNextUsableToken(tokenStack, #tokenStack, nil, -1)
2077-
if isMethodCall then break end
2074+
if punctTok.value == ":" then break end
2075+
2076+
elseif isToken(tokNext, "punctuation", "[") then
2077+
local punctTok = tokNext
2078+
popTokens(tokenStack, iNext) -- '['
2079+
tableInsert(tokens, tokNext)
2080+
2081+
local bracketBalance = 1
2082+
2083+
while true do
2084+
tokNext = tableRemove(tokenStack) -- anything
2085+
if not tokNext then
2086+
errorAtToken(
2087+
fileBuffers, punctTok, nil, "Macro",
2088+
"Syntax error: Could not find matching bracket before EOF. (Macro starts %s)",
2089+
getRelativeLocationText(macroStartTok, punctTok)
2090+
)
2091+
end
2092+
tableInsert(tokens, tokNext)
2093+
2094+
if isToken(tokNext, "punctuation", "[") then
2095+
bracketBalance = bracketBalance + 1
2096+
elseif isToken(tokNext, "punctuation", "]") then
2097+
bracketBalance = bracketBalance - 1
2098+
if bracketBalance == 0 then break end
2099+
elseif tokNext.type:find"^pp_" then
2100+
errorAtToken(fileBuffers, tokNext, nil, "Macro", "Preprocessor token inside metaprogram/macro name expression (starting %s).", getRelativeLocationText(macroStartTok, tokNext))
2101+
end
2102+
end
2103+
2104+
lastCalleeTok = tokNext
2105+
tokNext, iNext = getNextUsableToken(tokenStack, #tokenStack, nil, -1)
2106+
2107+
else
2108+
break
2109+
end
20782110
end
20792111

2112+
--
2113+
-- Arguments.
2114+
--
2115+
20802116
-- @insert identifier " ... "
20812117
if isTokenAndNotNil(tokNext, "string") then
20822118
local stringTok = tokNext
@@ -2172,11 +2208,9 @@ local function expandMacro(tokens, fileBuffers, tokenStack, macroStartTok, isNes
21722208
tableInsert(tokens, newTokenAt({type="punctuation", value=")", representation=")"}, tokens[#tokens]))
21732209

21742210
-- @insert identifier ( argument1, ... )
2175-
else
2176-
if not isTokenAndNotNil(tokNext, "punctuation", "(") then
2177-
printErrorTraceback("Internal error.")
2178-
errorAfterToken(fileBuffers, lastCalleeTok, "Macro", "Syntax error: Expected '(' after macro name.")
2179-
elseif isTokenAndNotNil(tokenStack[iNext+1], "whitespace") and tokenStack[iNext+1].value:find"\n" then
2211+
elseif isTokenAndNotNil(tokNext, "punctuation", "(") then
2212+
-- Apply the same 'ambiguous syntax' rule as Lua.
2213+
if isTokenAndNotNil(tokenStack[iNext+1], "whitespace") and tokenStack[iNext+1].value:find"\n" then
21802214
errorAtToken(fileBuffers, tokNext, nil, "Macro", "Ambiguous syntax near '(' - part of macro, or new statement?")
21812215
end
21822216

@@ -2313,8 +2347,15 @@ local function expandMacro(tokens, fileBuffers, tokenStack, macroStartTok, isNes
23132347

23142348
-- Add ')' for end of call.
23152349
tableInsert(tokens, tableRemove(tokenStack)) -- ')'
2350+
2351+
else
2352+
errorAfterToken(fileBuffers, lastCalleeTok, "Macro", "Syntax error: Expected '(' after macro name.")
23162353
end
23172354

2355+
--
2356+
-- End.
2357+
--
2358+
23182359
-- Add ')' for end of preprocessor block.
23192360
tableInsert(tokens, newTokenAt({type="punctuation", value=")", representation=")"}, tokens[#tokens]))
23202361
end

tests/quickTest.lua2p

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ local b = @@PASS_THROUGH( !!("2") )
134134
local c = @@PASS_THROUGH{ 1 + !(2) + 3 }
135135
local d = @@PASS_THROUGH(@@PASS_THROUGH{@@PASS_THROUGH( !!("1")!!("+")!!("2") )})
136136

137+
!local t = {field={object={method=function(obj, lua) return lua end}}}
138+
!local keys = {"object"}
139+
local n = @@t.field[keys[1]]:method(58)
140+
137141

138142

139143
-- Misc.

tests/quickTest.output.lua

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,37 +56,54 @@ print(s:match(funcCall)) -- "hello5( foo )"
5656

5757
-- File inserts.
5858

59-
local uhh = 7
60-
print("Final program - uhh: "..uhh)
59+
local uhh1 = 7
60+
local uhh2 = 7 -- @@ means the same as @insert.
61+
print("Final program - uhh: "..uhh1..", "..uhh2)
6162

6263

6364

6465
-- Macros.
6566

6667
print("Blargh!")
68+
print("Blargh!")
69+
-- !@insert BLARGH() -- Error: Macro inside metaprogram.
6770

68-
print(string.format('We are at %s:%d!', "misc/quickTest.lua2p", 87))
71+
print(string.format('We are at %s:%d!', "tests/quickTest.lua2p", 95))
6972

7073
local ok = 1==1
7174

7275
if not (ok) then error("Oh "..tonumber("7",10).." noes!") end
76+
-- @insert ASSERT ( 1 1 ) -- Syntax error!
77+
-- @insert ASSERT ( ok , ) -- Syntax error!
78+
-- @insert ASSERT ( , ok ) -- Syntax error!
79+
-- @insert ASSERT ( --[[]] , ok ) -- Syntax error!
7380

7481
local s = "foo"
75-
local t = { 496, b=true } -- @@func() means the same as @insert func().
82+
local t = { 496, b=true } -- @@ means the same as @insert.
83+
84+
-- local s = @@PASS_THROUGH `foo`
7685

7786
local f = function(a, b)
7887
while true do
7988
repeat until arePlanetsAligned("mars", "jupiter")
89+
-- repeat until arePlanetsAligned(`mars`, `jupiter`)
8090
break
8191
end
8292
return "", nil
8393
end
8494

95+
local a = 1+2*3
96+
local b = 2
97+
local c = { 1 + 2 + 3 }
98+
local d = {1+2}
99+
100+
local n = 58
101+
85102

86103

87104
-- Misc.
88105
print("dataFromCommandLine: Hello, world!")
89-
print("This file and line: tests/quickTest.lua2p:133")
106+
print("This file and line: tests/quickTest.lua2p:145")
90107

91108
for i = 1, 3 do
92109
do

tests/suite.lua

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -263,19 +263,19 @@ doTest("Macros", function()
263263
]]})
264264
assertCodeOutput(luaOut, [[t = {}]])
265265

266-
-- Macro with lookups.
266+
-- Macro name with lookups.
267267
local luaOut = assert(pp.processString{ code=[[
268-
!t = {o={m=function(o,v) return v end}}
269-
v = @@t.o:m(foo)
268+
!t, a = {t={o={m=function(o,v) return v end}}}, {"o"}
269+
v = @@t.t[ a[1] ]:m(foo)
270270
]]})
271271
assertCodeOutput(luaOut, [[v = foo]])
272272

273273
assert(not pp.processString{ code=[[
274-
!t = {o={m=function(o,v) return v end}}
274+
!t = {f=function(v) return v end}
275275
v = @@t.(foo)
276276
]]})
277277
assert(not pp.processString{ code=[[
278-
!t = {o={m=function(o,v) return v end}}
278+
!t = {o={m=function(o,v) return v end}}
279279
v = @@t.o:(foo)
280280
]]})
281281

@@ -325,13 +325,19 @@ doTest("Macros", function()
325325
v = @@VOID
326326
() 1
327327
]]})
328-
329328
assert(not pp.processString{ code=[[
330-
!t = {o={m=function(o,v) return v end}}
329+
!t = {o={m=function(o,v) return v end}}
331330
v = @@t.o:m
332331
(foo)
333332
]]})
334333

334+
-- Invalid: Preprocessor code inside macro name expression.
335+
assert(not pp.processString{ code=[[
336+
!function bad() return "f" end
337+
!t = {f=function(v) return v end}
338+
v = @@t[ @@bad() ](foo)
339+
]]})
340+
335341
-- Invalid: Bad macro arguments format.
336342
assert(not pp.processString{ code=[[ @insert type[] ]]})
337343
assert(not pp.processString{ code=[[ @insert type + 1 ]]})

0 commit comments

Comments
 (0)