diff options
author | Albert Krewinkel <albert@zeitkraut.de> | 2018-10-20 15:06:16 +0200 |
---|---|---|
committer | Albert Krewinkel <albert@zeitkraut.de> | 2018-10-20 19:14:17 +0200 |
commit | 916db81ade8049ae417350b88bbe08e1a4018c79 (patch) | |
tree | fb7f11df9d37e2f0bcfd09dd740b084b19e9d8f7 /data | |
parent | 8d4027da4dc698cdb13d143bc542977391f4b49b (diff) | |
download | pandoc-916db81ade8049ae417350b88bbe08e1a4018c79.tar.gz |
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.
Diffstat (limited to 'data')
-rw-r--r-- | data/pandoc.lua | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/data/pandoc.lua b/data/pandoc.lua index 370c6a944..e69f8ac9c 100644 --- a/data/pandoc.lua +++ b/data/pandoc.lua @@ -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 ------------------------------------------------------------------------ |