Lua filters: iterate over AST element fields when using pairs
This makes it possible to iterate over all field names of an AST element by using a generic `for` loop with `pairs`: for field_name, field_content in pairs(element) do … end Raw table fields of AST elements should be considered an implementation detail and might change in the future. Accessing element properties should always happen through the fields listed in the Lua filter docs. Note that the iterator currently excludes the `t`/`tag` field.
This commit is contained in:
parent
8d4027da4d
commit
916db81ade
1 changed files with 58 additions and 0 deletions
|
@ -73,6 +73,39 @@ local function create_accessor_functions (fn_template, accessors)
|
|||
return res
|
||||
end
|
||||
|
||||
--- Get list of top-level fields from field descriptor table.
|
||||
-- E.g.: `top_level_fields{'foo', {bar='baz'}, {'qux', 'quux'}}`
|
||||
-- gives {'foo, 'bar', 'qux', 'quux'}
|
||||
-- @local
|
||||
local function top_level_fields (fields)
|
||||
local result = List:new{}
|
||||
for _, v in ipairs(fields) do
|
||||
if type(v) == 'string' then
|
||||
table.insert(result, v)
|
||||
elseif type(v) == 'table' and #v == 0 and next(v) then
|
||||
table.insert(result, (next(v)))
|
||||
else
|
||||
result:extend(top_level_fields(v))
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
--- Creates a function which behaves like next, but respects field names.
|
||||
-- @local
|
||||
local function make_next_function (fields)
|
||||
local field_indices = {}
|
||||
for i, f in ipairs(fields) do
|
||||
field_indices[f] = i
|
||||
end
|
||||
|
||||
return function (t, field)
|
||||
local raw_idx = field == nil and 0 or field_indices[field]
|
||||
local next_field = fields[raw_idx + 1]
|
||||
return next_field, t[next_field]
|
||||
end
|
||||
end
|
||||
|
||||
--- Create a new table which allows to access numerical indices via accessor
|
||||
-- functions.
|
||||
-- @local
|
||||
|
@ -102,6 +135,15 @@ local function create_accessor_behavior (tag, accessors)
|
|||
rawset(t, k, v)
|
||||
end
|
||||
end
|
||||
behavior.__pairs = function (t)
|
||||
if accessors == nil then
|
||||
return next, t
|
||||
end
|
||||
local iterable_fields = type(accessors) == 'string'
|
||||
and {accessors}
|
||||
or top_level_fields(accessors)
|
||||
return make_next_function(iterable_fields), t
|
||||
end
|
||||
return behavior
|
||||
end
|
||||
|
||||
|
@ -842,6 +884,14 @@ M.Attr.behavior.__newindex = function(t, k, v)
|
|||
rawset(t, k, v)
|
||||
end
|
||||
end
|
||||
M.Attr.behavior.__pairs = function(t)
|
||||
local field_names = M.Attr.behavior._field_names
|
||||
local fields = {}
|
||||
for name, i in pairs(field_names) do
|
||||
fields[i] = name
|
||||
end
|
||||
return make_next_function(fields), t, nil
|
||||
end
|
||||
|
||||
-- Citation
|
||||
M.Citation = AstElement:make_subtype'Citation'
|
||||
|
@ -892,6 +942,14 @@ M.ListAttributes.behavior.__newindex = function (t, k, v)
|
|||
rawset(t, k, v)
|
||||
end
|
||||
end
|
||||
M.ListAttributes.behavior.__pairs = function(t)
|
||||
local field_names = M.ListAttributes.behavior._field_names
|
||||
local fields = {}
|
||||
for name, i in pairs(field_names) do
|
||||
fields[i] = name
|
||||
end
|
||||
return make_next_function(fields), t, nil
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in a new issue