Philosophy: "All properties apply, we need only define the order of precedence."
Note: this algorithm is executed before doing interpretation and vocalization of intent expressions. It linearizes a list of properties for each node in the MathML tree, as well as each term of compound intent expressions.
Legend:
self-property- attached to the node itself (intent=":matrix")ref-property- attached to a reference (intent = "$ref:equation-label")fragment-property- attached to a non-reference head in a compound expressionintent="factorial:function(2:literal)"
leaf-property- attached to a standalone concept, literal or number (intent="plus:prefix")
Idea:
- self-properties are inherited by children, act as defaults (low precedence)
- [FLAW] except when they aren't inherited.
:matrixand:commonhave the same syntax but act very differently.- the group should have split these behaviors to have different syntax.
- for now consider the self-properties that do NOT inherit to be leaf-properties in this Legend. (implementers would need to maintain a hardcoded list of exceptions)
- [FLAW] except when they aren't inherited.
- ref-properties override the target node's properties, they have higher precedence.
- leaf-properties - they only apply to the leaf carrying them
- have higher precedence than ancestor self-properties (and inherit them)
- can be overridden by ref-properties.
- fragment-properties apply only to a fragment in a compound intent expression, otherwise same as leaf-properties
Convention: A priority queue order is last-to-first, the first element has highest priority
function CurrentProperties(node-or-term):
Argument:
- A MathML node or intent term
Returns:
- A priority queue of intent properties
Steps:
1. the current node-or-term's property list is interpreted left-to-right,
2. right-most property having highest priority
- example:lower:higher will return [:lower,:higher]
- <mo intent="example:lower:higher"> will return [:lower,:higher]
- <mo intent="plus:function(2)"> will return []
function LinearizeProperties(P_default, P_override, node):
Arguments:
- a priority queue P_default for ancestor property defaults (self-properties)
- a priority queue P_override for ancestor property overrides (ref-properties)
- a MathML node
Returns:
- nothing, written so as to bookkeep a global ComputedProperties for the tree
(or can annotate the nodes in place, etc)
Steps:
if (node is a leaf in the MathML tree, or carrying a leaf intent annotation):
SET ComputedProperties{node} = appended(P_default, CurrentProperties(node), P_override)
else if (intent is one or more self-properties):
P_inherit = appended(P_default, CurrentProperties(node), P_override)
SET ComputedProperties{node} = P_inherit
recurse LinearizeProperties(P_inherit, [], child) for all children
else if (intent is a reference with properties)
P_inherit_override = appended(CurrentProperties(node), P_override)
# no SET, this is a pass-through node
recurse LinearizeProperties(P_default, P_inherit_override, ref_node) for referenced node only
else if (intent is a compound expression)
# Ignore overrides? Overrides on individual terms would be very confusing,
# lots of possible unintended consequences. This feels weird.
SET ComputedProperties{term} = appended(P_default, CurrentProperties(term)) for each non-ref intent term
recurse LinearizeProperties(P_default, [], ref_term) for each reference term
(reusing notation, terms are not nodes after all)
After the properties are linearized, the tree can be traversed again to interpret and vocalize
(this is similar to using Computed CSS to render HTML).
Gist context: see mathml#449