texmod.read: Fix [transform followed by a lowercase letter

This commit is contained in:
Lars Mueller 2023-05-27 19:12:49 +02:00
parent 5dc6307661
commit 520ecc641b

@ -166,6 +166,22 @@ function pr.lowpart(r)
return percent, r:subtexp() return percent, r:subtexp()
end end
-- Build a prefix tree of parameter readers to greedily match the longest texture modifier prefix;
-- just matching `%a+` and looking it up in a table
-- doesn't work since `[transform` may be followed by a lowercase transform name
-- TODO (?...) consolidate with `modlib.trie`
local texmod_reader_trie = {}
for _, readers in pairs{pr, gr} do
for type in pairs(readers) do
local subtrie = texmod_reader_trie
for char in type:gmatch"." do
subtrie[char] = subtrie[char] or {}
subtrie = subtrie[char]
end
subtrie.type = type
end
end
-- Reader methods. We use `r` instead of the `self` "sugar" for consistency (and to save us some typing). -- Reader methods. We use `r` instead of the `self` "sugar" for consistency (and to save us some typing).
local rm = {} local rm = {}
@ -185,6 +201,7 @@ function rm.peek(r)
end end
end end
function rm.popchar(r) function rm.popchar(r)
assert(not r.eof, "unexpected eof")
r.escapes = 0 r.escapes = 0
while true do while true do
r.character = r:read_char() r.character = r:read_char()
@ -277,7 +294,7 @@ function rm.basexp(r)
return res return res
end end
if r:match"[" then if r:match"[" then
local type = r:match_str"[a-z]" local type = r:match_str"%a"
local gen_reader = gr[type] local gen_reader = gr[type]
if not gen_reader then if not gen_reader then
error("invalid texture modifier: " .. type) error("invalid texture modifier: " .. type)
@ -288,17 +305,25 @@ function rm.basexp(r)
end end
function rm.colorspec(r) function rm.colorspec(r)
-- Leave exact validation up to colorspec, only do a rough greedy charset matching -- Leave exact validation up to colorspec, only do a rough greedy charset matching
return assert(colorspec.from_string(r:match_str"[#%xa-z]")) return assert(colorspec.from_string(r:match_str"[#%x%a]"))
end end
function rm.texp(r) function rm.texp(r)
local base = r:basexp() local base = r:basexp()
while r:hat() do while r:hat() do
if r:match"[" then if r:match"[" then
local type = r:match_str"[a-z]" local reader_subtrie = texmod_reader_trie
local param_reader, gen_reader = pr[type], gr[type] while true do
if not (param_reader or gen_reader) then local next_subtrie = reader_subtrie[r:peek()]
error("invalid texture modifier: " .. type) if next_subtrie then
reader_subtrie = next_subtrie
r:pop()
else
break
end end
end
local type = assert(reader_subtrie.type, "invalid texture modifier")
local param_reader, gen_reader = pr[type], gr[type]
assert(param_reader or gen_reader)
if param_reader then if param_reader then
base = base[type](base, param_reader(r)) base = base[type](base, param_reader(r))
elseif gen_reader then elseif gen_reader then