parseInvariantCitations function
Extracts from source every citation of an invariant of
tom_specs_model_rules.md ยง10.2.
A single citation may name several ids โ the routing pair is cited as one
head followed by KIND-EXCLUSIVE + PART-ROUTED โ and may wrap across lines,
so the run after the head is consumed token by token rather than matched as
one value.
A leading ordinal is captured as a citation too, flagged by InvariantCitation.isOrdinal: it is a defect worth naming, not noise to skip. A head followed by ordinary prose ("the one rule enforced here") yields nothing โ it is a reference to the section, not to an invariant.
Implementation
List<InvariantCitation> parseInvariantCitations(
String source, {
String sourceName = 'source',
}) {
final citations = <InvariantCitation>[];
final lineStarts = _lineStarts(source);
for (final head in _citationHead.allMatches(source)) {
final qualified = head.group(1) != null;
var offset = head.end;
while (true) {
final token = _citationToken.firstMatch(source.substring(offset));
if (token == null) break;
final value = token.group(1)!;
final isOrdinal = int.tryParse(value) != null;
if (isOrdinal && !qualified) break;
if (!isOrdinal && !_isInvariantId(value)) break;
if (!qualified && _foreignIdNamespaces.any(value.startsWith)) break;
citations.add(
InvariantCitation(
id: value,
source: sourceName,
line: _lineOf(lineStarts, head.start),
text: _lineAt(source, lineStarts, head.start),
),
);
offset += token.end;
// An ordinal is a defect on its own; do not keep walking a run that the
// scan cannot reliably delimit ("invariants 11 and 12" vs "11 and later").
if (isOrdinal) break;
}
}
return citations;
}