Decision record
AD-0015 A hand-written strict subset parser
Status: accepted. Date: 2026-08-27.
Context
The adapter reads a SysML v2 model from files rather than fronting a repository (AD-0003), so something has to turn the textual notation into elements the projection can serve. The README says the adapter’s coverage of the language is a fraction of the goal and leaves open whether coverage grows as curated projections or as a generated whole (AD-0005). Underneath that sits the question this record answers: what reads the text, and what happens to text it does not understand.
The research set out to confirm that no Go parser for the notation existed,
and that was refuted. Three exist. Open-MBEE/OpenSysML is Apache-2.0, a
hand-written recursive-descent
parser with semantic resolution, an LSP, a REPL and a gRPC server, young and
at v0.2.1 when it was read, with all its library code under
internal/. mycr0ft/gosysml is MIT and ANTLR-based, new at the time of
reading and with a grammar descended from a 2023 release.
dVoo/gosysml2 is GPL-3.0. Beside them sit the antlr/grammars-v4 sysml-v2
grammar, MIT, which would generate a very large parser from a KEBNF that two
downstream projects document as ambiguous, and
nomograph-ai/tree-sitter-sysml, MIT, whose Go binding is cgo and would end the
CGO_ENABLED=0 cross-compilation the image depends on. Syside is
closed source and licence-gated, with air-gapped use needing a Business
plan.
Two more routes read the model without parsing it in Go. The OMG pilot emits
the standard JSON serialisation through a Java 17 tool, the same shape a
conforming repository returns over the API, at the cost of a JVM at build time
and a flat element graph in which even memberships are elements.
OpenSysML’s gRPC server could run as a sidecar and return its own SymbolInfo
tree, which is not the OMG JSON and whose API is pre-1.0.
The repository’s own rules bear on the choice. Product code is Go with no empty interface in a value position, it is test-first, and it has to be readable in an afternoon, at the scale per component SC-06 expects. Edits through the projection patch a literal at its recorded source span (AD-0004), so whatever reads the text has to keep byte ranges. And the example has to be accepted by the reference tools in any case, since a subset parser cannot prove conformance.
Decision
We will write the parser by hand in Go as a strict subset of the textual
notation, with a lexer, a recursive-descent parser and an AST in which every
node carries its byte range in the source. It accepts exactly the constructs
of a listed subset, with ports and connections filled in by a spike, and
refuses anything else with the file, line and column of the
first offending token. The parser has no opinion about meaning. Name
resolution, expression evaluation and the reading of require constraint
belong to the model package above it. The example model is validated
separately with the OMG pilot 2026-07 and the OpenSysML command line before it
becomes a fixture (SR-45), and OpenSysML becomes the replacement when its
maintainers expose a public Go package or freeze the gRPC contract.
Alternatives considered
Consuming the OMG JSON serialisation produced by the pilot, checked into the
example or produced in a build stage. It needs Java 17 at build time, its
output is a
flat element graph the adapter would have to walk in the very metamodel it
exists to hide, and elementId values are tool-assigned UUIDs whose stability
across runs is unverified. The research keeps it as the best second
input path, because its shape is what a real repository returns.
An OpenSysML gRPC sidecar. It delegates
conformance to a maintained implementation, but it adds a second process to
the one-command container, its API is pre-1.0 and its output is its own
SymbolInfo model rather than the OMG JSON.
Importing an existing Go parser. None is importable under a compatible licence
today: OpenSysML’s code is under internal/, gosysml was new with a
grammar from 2023, gosysml2 is GPL-3.0, tree-sitter needs cgo, and a parser
generated from grammars-v4 would be huge and inherit the grammar’s documented
ambiguities. Syside is excluded by its licensing.
Consequences
The adapter stays pure Go with no dependency for parsing, cross-compiles with
CGO_ENABLED=0, fits the empty-interface and test-first rules, and owns a
small AST so the projection is plainly typed. Source spans make
Patch(span, newLiteral) possible, so the served text and the projection are
rebuilt together and never disagree (SR-22). A construct outside the subset is
refused, never skipped, which is what SR-18 requires, and it is the smaller
and more honest first cut of the escape hatch the README leaves open: nothing
is served generically in this phase (AD-0005).
The costs are the research’s and are repeated here. The parser is not
conformant and never will be. Expressions need a real grammar even for the
subset, which is why the adapter evaluates only a literal with an optional
unit, feature reference chains, the four arithmetic operators and parentheses
(SR-23). Name resolution, imports and redefinition are reimplemented in
miniature. Every new language feature is adapter work, and SC-06’s expected
scale for hand-written code under adapter/ is the signal for how far that
goes, though it is a figure to revise rather than a limit to obey.
A silent mis-parse is the main risk and strictness is the mitigation. The
parser fails on an unknown token rather than skipping it, and one fixture per
rejection it distinguishes is the test (SR-18). Conformance of the example is
proven outside the adapter (SR-45). The validation run also settles the plain
numeric binding and the duration literal, the ports and
connect syntax is quoted from OMG training folders 09 and 10 before the
example is written, and the 2.1 Beta 2 change list is read before that run,
since the pilot implements 2.1 Beta 2 and the adapter claims 2.0 formal.
The decision carries its own replacement condition. OpenSysML’s SymbolInfo
tree is already close to what a projection needs, and if its maintainers
expose a package or freeze the gRPC contract the hand-written parser is the
part of the adapter to retire first. Keying the internal model on declared
short names rather than tool-assigned UUIDs (AD-0018) is what the research
says keeps a later swap a source change rather than a schema change.
Requirements affected
SR-16, SR-18, SR-22, SR-23, SR-45
Sources
The public repositories named above, with their licences and their own README statements: Open-MBEE/OpenSysML, mycr0ft/gosysml, dVoo/gosysml2, antlr/grammars-v4 and nomograph-ai/tree-sitter-sysml. Syside’s licence terms. What the research overturned for the claim as it was checked and corrected, and Five views and twenty-six decisions for the adapter view.