feat(walk_inner): provide parent info
This commit is contained in:
parent
4836cb2fb1
commit
61e91d483d
51
helpers.lua
51
helpers.lua
|
@ -46,26 +46,47 @@ function formspec_ast.interpret(spec, custom_handlers)
|
|||
end
|
||||
|
||||
local function walk_inner(tree, container_elems)
|
||||
local parents = {}
|
||||
local i = 1
|
||||
-- Use two tables to store values so that a new table doesn't have to be
|
||||
-- created every time a container is entered
|
||||
local parent_trees = {}
|
||||
local parent_indexes = {}
|
||||
|
||||
local parent_idx = 0
|
||||
local i = 0
|
||||
return function()
|
||||
local res = tree[i]
|
||||
while not res do
|
||||
local n = table.remove(parents)
|
||||
if not n then
|
||||
return
|
||||
end
|
||||
tree, i = n[1], n[2]
|
||||
res = tree[i]
|
||||
-- If the previously yielded element has children
|
||||
if i > 0 and container_elems[tree[i].type] then
|
||||
-- Save the parent element and the next index
|
||||
parent_idx = parent_idx + 1
|
||||
parent_trees[parent_idx] = tree
|
||||
parent_indexes[parent_idx] = i + 1
|
||||
|
||||
-- Set the new tree
|
||||
tree = tree[i]
|
||||
|
||||
-- Reset I to initial value (zero)
|
||||
i = 0
|
||||
end
|
||||
|
||||
-- Point index to next child
|
||||
i = i + 1
|
||||
|
||||
if container_elems[res.type] then
|
||||
table.insert(parents, {tree, i})
|
||||
tree = res
|
||||
i = 1
|
||||
-- Get child at index
|
||||
local elem = tree[i]
|
||||
while not elem do -- current child is invalid
|
||||
if parent_idx < 1 then
|
||||
return
|
||||
end
|
||||
|
||||
-- Restore parent's relative index
|
||||
tree, i = parent_trees[parent_idx], parent_indexes[parent_idx]
|
||||
parent_idx = parent_idx - 1
|
||||
|
||||
-- Get child at index
|
||||
elem = tree[i]
|
||||
end
|
||||
return res
|
||||
|
||||
return elem, tree, i
|
||||
end
|
||||
end
|
||||
|
||||
|
|
156
test.lua
156
test.lua
|
@ -620,3 +620,159 @@ it("does not parse invalid tabheader elements", function()
|
|||
assert.is_nil(formspec_ast.parse("tabheader[1,2;name;a,b,c;1;false]"))
|
||||
assert.is_nil(formspec_ast.parse("tabheader[1,2;3,4;name;a,b,c;1]"))
|
||||
end)
|
||||
|
||||
describe("helpers", function ()
|
||||
describe("walk", function ()
|
||||
it("walks over every element", function ()
|
||||
local tree = {
|
||||
{ type = "box", color = "green" },
|
||||
{ type = "label", label = "the text" },
|
||||
{
|
||||
type = "container",
|
||||
{ type = "label", label = "the text" }
|
||||
}
|
||||
}
|
||||
for node in formspec_ast.walk(tree) do
|
||||
node.visited = true
|
||||
end
|
||||
assert.same({
|
||||
{ type = "box", color = "green", visited = true },
|
||||
{ type = "label", label = "the text", visited = true },
|
||||
{
|
||||
type = "container",
|
||||
visited = true,
|
||||
{ type = "label", label = "the text", visited = true }
|
||||
}
|
||||
}, tree)
|
||||
end)
|
||||
it("can be stopped", function ()
|
||||
local tree = {
|
||||
{ type = "box", color = "green" },
|
||||
{ type = "label", label = "the text" },
|
||||
{
|
||||
type = "container",
|
||||
{ type = "label", label = "the text" }
|
||||
},
|
||||
{ type = "label", label = "the text" }
|
||||
}
|
||||
local count = 0
|
||||
for node in formspec_ast.walk(tree) do
|
||||
count = count + 1
|
||||
node.visited = true
|
||||
if count == 3 then break end
|
||||
end
|
||||
assert.same({
|
||||
{ type = "box", color = "green", visited = true },
|
||||
{ type = "label", label = "the text", visited = true },
|
||||
{
|
||||
type = "container",
|
||||
visited = true,
|
||||
{ type = "label", label = "the text" }
|
||||
},
|
||||
{ type = "label", label = "the text" }
|
||||
}, tree)
|
||||
end)
|
||||
it("can accept custom element list", function ()
|
||||
local tree = {
|
||||
{ type = "box", color = "green" },
|
||||
{ type = "label", label = "the text" },
|
||||
{
|
||||
type = "nonsensewordhere",
|
||||
{ type = "label", label = "the text" }
|
||||
},
|
||||
{
|
||||
type = "container",
|
||||
{ type = "label", label = "the text" }
|
||||
},
|
||||
{ type = "label", label = "the text" }
|
||||
}
|
||||
for node in formspec_ast.walk(tree, {nonsensewordhere = true}) do
|
||||
node.visited = true
|
||||
end
|
||||
assert.same({
|
||||
{ type = "box", color = "green", visited = true },
|
||||
{ type = "label", label = "the text", visited = true },
|
||||
{
|
||||
type = "nonsensewordhere",
|
||||
visited = true,
|
||||
{ type = "label", label = "the text", visited = true }
|
||||
},
|
||||
{
|
||||
type = "container",
|
||||
visited = true,
|
||||
{ type = "label", label = "the text" }
|
||||
},
|
||||
{ type = "label", label = "the text", visited = true }
|
||||
}, tree)
|
||||
end)
|
||||
it("can provide parent info when walking", function ()
|
||||
local tree = {
|
||||
{ type = "box", color = "green" },
|
||||
{ type = "label", label = "the text" },
|
||||
{
|
||||
type = "container",
|
||||
{ type = "label", label = "the text" }
|
||||
},
|
||||
{ type = "label", label = "the text" }
|
||||
}
|
||||
local logged_indexes = {}
|
||||
for node, parent, index in formspec_ast.walk(tree) do
|
||||
node.visited = true
|
||||
parent.parent_of = (parent.parent_of or 0) + 1
|
||||
logged_indexes[#logged_indexes+1] = index
|
||||
end
|
||||
assert.same({
|
||||
parent_of = 4,
|
||||
{ type = "box", color = "green", visited = true },
|
||||
{ type = "label", label = "the text", visited = true },
|
||||
{
|
||||
type = "container",
|
||||
visited = true,
|
||||
parent_of = 1,
|
||||
{ type = "label", label = "the text", visited = true }
|
||||
},
|
||||
{ type = "label", label = "the text", visited = true },
|
||||
}, tree)
|
||||
-- NOTE: this is, in effect, asserting the order of the crawl
|
||||
assert.same({ 1, 2, 3, 1, 4}, logged_indexes)
|
||||
end)
|
||||
it("parent info can be modified without failure", function ()
|
||||
-- INFO: This test is a regression test.
|
||||
local tree = {
|
||||
{ type = "box", color = "green" },
|
||||
{ type = "label", label = "the text" },
|
||||
{
|
||||
type = "container",
|
||||
{ type = "label", label = "the text" }
|
||||
}
|
||||
}
|
||||
local found_child = false
|
||||
for node, parent in formspec_ast.walk(tree) do
|
||||
if node.type == "container" then
|
||||
node[#node+1] = { type = "label", label = "the new text" }
|
||||
elseif parent.type == "container" then
|
||||
node.is_child_thingy = true
|
||||
if not found_child then
|
||||
found_child = true
|
||||
node.type = "container"
|
||||
node[1] = { type = "box", color = "red" }
|
||||
node.label = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
assert.same({
|
||||
{ type = "box", color = "green" },
|
||||
{ type = "label", label = "the text" },
|
||||
{
|
||||
type = "container",
|
||||
{
|
||||
type = "container",
|
||||
is_child_thingy = true,
|
||||
{ type = "box", color = "red", is_child_thingy = true }
|
||||
},
|
||||
{ type = "label", label = "the new text", is_child_thingy = true }
|
||||
}
|
||||
}, tree)
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
|
Loading…
Reference in New Issue