Chapter 3. Modularity
Modularity is an experimental feature introduced in version 3.3.0. It’s inspired by Modular ixml presented by Steven Pemberton at MarkupUK in 2025, but some of the details are different. It’s likely, if the Community Group continues to work on modularity as a feature of iXML, that the design will change further. Places where this design differs from the design presented in Modular ixml are marked with “👀” to draw your attention.
The idea behind modularity is to enable reuse. As the number and complexity of iXML grammars grows, good software design practice encourages reusablity with a mechanism more reliable than “cut-and-paste” between grammars.
Conceptually, modularity constructs a new (monolithic) grammar that contains all of the necessary productions. It isn’t a textual inclusion of any kind. Grammars can use each other more-or-less arbitrarily.
Modularity extends the iXML grammar by adding uses and
shares elements. These extensions are introduced by a “+”
as shown in this example:
numerics.ixml+uses digit, hexdigit from "digits.ixml" .+shares decimal, hexadecimal .number = decimal | hexadecimal .decimal = digit+ .hexadecimal = hexdigit+ .
The uses clause says that this grammar
uses the rules for digit and
hexdigit from the digits.ixml
grammar. It shares the rules for
decimal and hexadecimal.
A grammar with an explicit shares clause is publishing its interface. Only the explicitly shared symbols may be used by another grammar. If there’s no shares clause, 👀 any symbol may be used by another grammar.
The effect of requesting modularity is to 👀 parse the input grammar against a variant iXML grammar that includes the new features. The relevant productions are:
ixml: s, (prolog, RS)?, ((uses; shares), RS)*, rule++RS, s.uses: -"+uses", RS, mfrom++(-";", s), s, -'.' .shares: -"+shares", RS, entries, s, -'.' .mfrom>from: entries, RS, -"from", RS, source .-entries: share++(-",", s).share: @name.@source: string .
These changes allow optional uses and shares
statements to appear before the first rule. The 👀 grammar URIs are quoted and
👀 each clause ends with a full stop.
It is an error to define a rule for a symobol that is used from another grammar.
It is an error to attempt to use a clause from another grammar if that grammar does not share the symbol (or if no symbols are explicitly shared, if the grammar does not contain a rule the symbol).
To complete the example above, digits.ixml is shown in
Example 3.2, “A modular grammar for digits, digits.ixml” and partno.ixml is show in
Example 3.3, “A modular grammar for part numbers, partno.ixml”.
digits.ixml+shares digit, hexdigit .-digit = ["0"-"9"] .-hexdigit = digit | hexadecimal .-hexadecimal = ["A"-"F" | "a"-"f" ] .
partno.ixml+uses decimal from "numerics.ixml" .partno: -decimal .
Observe that the nonterminal hexadecimal is
used in two grammars and has different definitions. The processor is
responsible for making sure that a correct grammar is constructed. The
renaming feature, introduced recently in Invisible XML, allows the processor to rename
nonterminals while preserving the correct serialization.
The composed grammar is included in the debugging output, if the modularity option is used:
<ixml>
<rule name="partno">
<alt>
<nonterminal name="decimal" mark="-"/>
</alt>
</rule>
<rule name="decimal">
<alt>
<repeat1>
<nonterminal name="digit"/>
</repeat1>
</alt>
</rule>
<rule name="digit" mark="-">
<alt>
<inclusion>
<member from="0" to="9"/>
</inclusion>
</alt>
</rule>
</ixml>