diff options
Diffstat (limited to 'biblio/citation-style-language/citeproc-node-choose.lua')
-rw-r--r-- | biblio/citation-style-language/citeproc-node-choose.lua | 330 |
1 files changed, 253 insertions, 77 deletions
diff --git a/biblio/citation-style-language/citeproc-node-choose.lua b/biblio/citation-style-language/citeproc-node-choose.lua index e48731406c..3a4fc3f79e 100644 --- a/biblio/citation-style-language/citeproc-node-choose.lua +++ b/biblio/citation-style-language/citeproc-node-choose.lua @@ -6,123 +6,299 @@ local choose = {} -local element = require("citeproc-element") +local Element = require("citeproc-element").Element +local SeqIr = require("citeproc-ir-node").SeqIr local util = require("citeproc-util") +-- [Choose](https://docs.citationstyles.org/en/stable/specification.html#choose) +local Choose = Element:derive("choose") -local Choose = element.Element:new() +function Choose:from_node(node) + local o = Choose:new() + o.children = {} + o:process_children_nodes(node) + if #o.children == 0 then + return nil + end + return o +end + +function Choose:build_ir(engine, state, context) + local branch + local branch_ir + for _, child in ipairs(self.children) do + if child:evaluate_conditions(engine, state, context) then + branch = child + branch_ir = child:build_ir(engine, state, context) + break + end + end + + if not branch_ir then + branch_ir = SeqIr:new({}, self) + branch_ir.group_var = "missing" + end + + local ir = SeqIr:new({branch_ir}, self) + ir.group_var = branch_ir.group_var + ir.name_count = branch_ir.name_count + ir.sort_key = branch_ir.sort_key + + if not context.disambiguate then + context.disambiguate = true -function Choose:render (item, context) - self:debug_info(context) - context = self:process_context(context) - for i, child in ipairs(self:get_children()) do - if child:is_element() then - local result, status = child:render(item, context) - if status then - return result + for _, child in ipairs(self.children) do + if child:evaluate_conditions(engine, state, context) then + if child ~= branch then + ir.disambiguate_branch_ir = child:build_ir(engine, state, context) + end + break end end + + context.disambiguate = false end - return nil + + return ir end -local If = element.Element:new() +local Condition = { + condition = nil, + value = nil, + match_type = "all", +} + +function Condition:new(condition, value, match_type) + local o = { + condition = condition, + value = value, + match_type = match_type or "all" + } + setmetatable(o, self) + self.__index = self + return o +end -If.render = function (self, item, context) - self:debug_info(context) - context = self:process_context(context) - local results = {} - local variable_names = context.options["is-numeric"] - if variable_names then - for _, variable_name in ipairs(util.split(variable_names)) do - local variable = self:get_variable(item, variable_name, context) - table.insert(results, util.is_numeric(variable)) - end +local If = Element:derive("if", { + conditions = nil, + match = "all" +}) + +function If:new() + local o = Element.new(self) + o.conditions = {} + o.match = "all" + return o +end + +function If:from_node(node) + local o = If:new() + -- TODO: disambiguate + -- o:set_bool_attribute(node, "disambiguate") + + o:add_conditions(node, "disambiguate") + o:add_conditions(node, "is-numeric") + o:add_conditions(node, "is-uncertain-date") + o:add_conditions(node, "locator") + o:add_conditions(node, "position") + o:add_conditions(node, "type") + o:add_conditions(node, "variable") + + o.match = node:get_attribute("match") + + o:process_children_nodes(node) + + return o +end + +function If:add_conditions(node, attribute) + local values = node:get_attribute(attribute) + if not values then + return + end + for _, value in ipairs(util.split(values)) do + local condition = Condition:new(attribute, value, self.match) + table.insert(self.conditions, condition) end +end - variable_names = context.options["is-uncertain-date"] - if variable_names then - for _, variable_name in ipairs(util.split(variable_names)) do - local variable = self:get_variable(item, variable_name, context) - table.insert(results, util.is_uncertain_date(variable)) - end +function If:build_children_ir(engine, state, context) + if not self.children then + return nil end + local irs = {} + local name_count + local ir_sort_key + local group_var = "plain" - local locator_types = context.options["locator"] - if locator_types then - for _, locator_type in ipairs(util.split(locator_types)) do - local locator_label = item.label or "page" - local res = locator_label == locator_type - if locator_type == "sub-verbo" then - res = locator_label == "sub-verbo" or locator_label == "sub verbo" + for _, child_element in ipairs(self.children) do + local child_ir = child_element:build_ir(engine, state, context) + + if child_ir then + local child_group_var = child_ir.group_var + if child_group_var == "important" then + group_var = "important" + elseif child_group_var == "missing" and child_ir._type ~= "YearSuffix" then + if group_var == "plain" then + group_var = "missing" + end end - table.insert(results, res) - end - end - local positions = context.options["position"] - if positions then - for _, position in ipairs(util.split(positions)) do - local res = false - if context.mode == "citation" then - if position == "first" then - res = (item.position == util.position_map["first"]) - elseif position == "near-note" then - res = item["near-note"] ~= nil and item["near-note"] ~= false - else - res = (item.position >= util.position_map[position]) + if child_ir.name_count then + if not name_count then + name_count = 0 end + name_count = name_count + child_ir.name_count + end + + if child_ir.sort_key ~= nil then + ir_sort_key = child_ir.sort_key end - table.insert(results, res) + + -- The condition can be simplified + table.insert(irs, child_ir) end end - local type_names = context.options["type"] - if type_names then - for _, type_name in ipairs(util.split(type_names)) do - table.insert(results, item["type"] == type_name) + if #irs == 0 then + group_var = "missing" + end + + local ir = SeqIr:new(irs, self) + ir.name_count = name_count + ir.sort_key = ir_sort_key + ir.group_var = group_var + return ir +end + +function If:build_ir(engine, state, context) + if not self:evaluate_conditions(engine, state, context) then + return nil + end + + local ir = self:build_children_ir(engine, state, context) + if not ir then + return nil + end + + ir.should_inherit_delim = true + return ir +end + +function If:evaluate_conditions(engine, state, context) + local res = false + -- util.debug(self.conditions) + for _, condition in ipairs(self.conditions) do + if self:evaluate_condition(condition, state, context) then + if self.match == "any" then + return true + elseif self.match == "none" then + return false + end + else + if self.match == "all" then + return false + end end end + if self.match == "any" then + return false + else + return true + end +end + +function If:evaluate_condition(condition, state, context) + -- util.debug(context.cite) + -- util.debug(condition) + if condition.condition == "disambiguate" then + return context.disambiguate or (context.in_bibliography and context.reference.disambiguate) - variable_names = context.options["variable"] - if variable_names then - for _, variable_name in ipairs(util.split(variable_names)) do - local variable = self:get_variable(item, variable_name, context) - local res = (variable ~= nil and variable ~= "") - table.insert(results, res) + elseif condition.condition == "is-numeric" then + local variable = context:get_variable(condition.value) + return util.is_numeric(variable) + + elseif condition.condition == "is-uncertain-date" then + local variable = context:get_variable(condition.value) + -- TODO + return self:is_uncertain_date(variable) + + elseif condition.condition == "locator" then + local locator_label = context:get_variable("label") + if locator_label == "sub verbo" then + locator_label = "sub-verbo" + end + return locator_label == condition.value + + elseif condition.condition == "position" then + return self:check_position(condition.value, context) + + elseif condition.condition == "type" then + local item_type = context:get_variable("type") + return item_type == condition.value + + elseif condition.condition == "variable" then + local var = condition.value + if var == "locator" or var == "label" then + if context.in_bibliography then + return false + else + return context.cite[var] ~= nil + end + else + local res = context.reference[var] ~= nil + return res end end +end + +function If:is_uncertain_date(variable) + if variable == nil then + return false + end + local circa = variable["circa"] + return circa and circa ~= "" +end - local match = context.options["match"] or "all" - local status = false - if match == "any" then - status = util.any(results) - elseif match == "none" then - status = not util.any(results) - else - status = util.all(results) +function If:check_position(position, context) + -- util.debug(context.cite) + if context.in_bibliography then + return false end - if status then - return self:render_children(item, context), status + + local position_level = context.cite.position or context.cite.position_level or 0 + -- context.cite.position is for hacking in debugging + -- bugreports_DemoPageFullCiteCruftOnSubsequent.txt + if position == "first" then + return (position_level == util.position_map["first"]) + elseif position == "near-note" then + return context.cite["near-note"] or context.cite.near_note else - return nil, false + return (position_level >= util.position_map[position]) end end -local ElseIf = If:new() +local ElseIf = If:derive("else-if") + +local Else = Element:derive("else") -local Else = element.Element:new() +function Else:from_node(node) + local o = Else:new() + o:process_children_nodes(node) + return o +end -Else.render = function (self, item, context) - self:debug_info(context) - context = self:process_context(context) - return self:render_children(item, context), true +function Else:evaluate_conditions(engine, state, context) + return true end +Else.build_children_ir = If.build_children_ir +Else.build_ir = If.build_ir + choose.Choose = Choose choose.If = If |