git.iko.soy/typeable/pandoc
on master help sign in
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.

commit916db81ade8049ae417350b88bbe08e1a4018c79 authorAlbert Krewinkel <albert@zeitkraut.de> dateSat 20 Oct 2018, 15:06 (8 years ago) parent8d4027d
1 file changed+58
data/pandoc.lua+58
data/pandoc.lua+58
@@ -73,6 +73,39 @@ local function create_accessor_functions (fn_template, accessors)
7373 return res
7474end
7575
76+--- Get list of top-level fields from field descriptor table.
77+-- E.g.: `top_level_fields{'foo', {bar='baz'}, {'qux', 'quux'}}`
78+-- gives {'foo, 'bar', 'qux', 'quux'}
79+-- @local
80+local function top_level_fields (fields)
81+ local result = List:new{}
82+ for _, v in ipairs(fields) do
83+ if type(v) == 'string' then
84+ table.insert(result, v)
85+ elseif type(v) == 'table' and #v == 0 and next(v) then
86+ table.insert(result, (next(v)))
87+ else
88+ result:extend(top_level_fields(v))
89+ end
90+ end
91+ return result
92+end
93+
94+--- Creates a function which behaves like next, but respects field names.
95+-- @local
96+local function make_next_function (fields)
97+ local field_indices = {}
98+ for i, f in ipairs(fields) do
99+ field_indices[f] = i
100+ end
101+
102+ return function (t, field)
103+ local raw_idx = field == nil and 0 or field_indices[field]
104+ local next_field = fields[raw_idx + 1]
105+ return next_field, t[next_field]
106+ end
107+end
108+
76109--- Create a new table which allows to access numerical indices via accessor
77110-- functions.
78111-- @local
@@ -102,6 +135,15 @@ local function create_accessor_behavior (tag, accessors)
102135 rawset(t, k, v)
103136 end
104137 end
138+ behavior.__pairs = function (t)
139+ if accessors == nil then
140+ return next, t
141+ end
142+ local iterable_fields = type(accessors) == 'string'
143+ and {accessors}
144+ or top_level_fields(accessors)
145+ return make_next_function(iterable_fields), t
146+ end
105147 return behavior
106148end
107149
@@ -842,6 +884,14 @@ M.Attr.behavior.__newindex = function(t, k, v)
842884 rawset(t, k, v)
843885 end
844886end
887+M.Attr.behavior.__pairs = function(t)
888+ local field_names = M.Attr.behavior._field_names
889+ local fields = {}
890+ for name, i in pairs(field_names) do
891+ fields[i] = name
892+ end
893+ return make_next_function(fields), t, nil
894+end
845895
846896-- Citation
847897M.Citation = AstElement:make_subtype'Citation'
@@ -892,6 +942,14 @@ M.ListAttributes.behavior.__newindex = function (t, k, v)
892942 rawset(t, k, v)
893943 end
894944end
945+M.ListAttributes.behavior.__pairs = function(t)
946+ local field_names = M.ListAttributes.behavior._field_names
947+ local fields = {}
948+ for name, i in pairs(field_names) do
949+ fields[i] = name
950+ end
951+ return make_next_function(fields), t, nil
952+end
895953
896954
897955------------------------------------------------------------------------