RFC: formal DBML spec, layer 1 grammar and conformance harness - #979
Draft
MFornander wants to merge 10 commits into
Draft
MFornander wants to merge 10 commits into
MFornander wants to merge 10 commits into
Conversation
Add peggy as a devDependency of @dbml/parse only, plus a `test:conformance` script backed by vitest.conformance.config.ts. The default `vitest run` excludes __tests__/conformance so the spec tests can be non-blocking in CI. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ntax Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A peggy grammar restating packages/dbml-parse's lexer and recursive-descent parser: tokens, trivia-sensitive rules (index vs argument, call vs new line, argument spacing), Pratt precedence, comma expressions, attribute lists, use declarations and element declarations, producing the SyntaxNodeKind tree. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Run the reference parser and the peggy-generated spec parser over every snapshot input and over the fast-check arbitraries, asserting agreement on accept/reject and on the normalised node-kind tree. Known disagreements are pinned so that a change on either side fails a test. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Express the same Layer 1 specification as a two-stage ANTLR 4 grammar (DbmlLexer.g4 + DbmlParser.g4) so that the notation question raised in the RFC can be judged on the same conformance corpus. Trivia lives on the hidden channel; predicates carry the trivia-sensitive rules and the one-token commitments the reference parser makes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Generate the ANTLR parser at test time with antlr-ng (no Java) for the antlr4 JavaScript runtime, convert its parse tree to the shared spec node shape, and run the snapshot corpus, pinned disagreements and property tests against the peggy and ANTLR parsers alike. Generated code is ignored by git. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Also replace a stray NUL byte in DISAGREEMENTS.md that made git treat the file as binary. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
DBML has no formal specification.
packages/dbml-parseis the de facto definition,CONTRIBUTING.mdstill points at PEG.js, and the only PEG grammar in the repo (packages/dbml-core/src/parse/deprecated/dbml/parser.pegjs) carries a header saying it is deprecated and should not be maintained.This PR proposes a layered spec that mirrors the parser's own layers, and lands the first layer in two notations so the notation choice can be judged on evidence:
spec/README.md: the layered design (generic syntax, per-element semantics, interpreted model), the authority rule, a one-page summary of the generic syntax, and a side-by-side comparison of the two notations.spec/dbml-syntax.peggy: an executable PEG grammar for Layer 1. It reproduces theSyntaxTokenKindandSyntaxNodeKindsets exactly, including the three trivia-sensitive rules (index vs new argument, call vs new line, argument spacing), the Pratt binding powers, comma expressions with empty slots, attribute lists, use declarations, and the function-application to nested-element reinterpretation. Element keywords are plain identifiers at this layer.spec/antlr/DbmlLexer.g4andspec/antlr/DbmlParser.g4: the same specification as a two-stage ANTLR 4 grammar, generated withantlr-ng(a Node port of the ANTLR tool, no Java) for theantlr4JavaScript runtime that@dbml/corealready uses for its SQL importers.packages/dbml-parse/__tests__/conformance/: the authority mechanism.syntax.test.tsruns the reference lexer+parser and each spec parser over every__tests__/snapshots/**/input/*.dbmland asserts agreement on accept/reject and on the normalised node-kind tree.properties.test.tsdoes the same over the existing fast-check arbitraries. Both grammars are compiled at test time; no generated code is committed.spec/DISAGREEMENTS.md: every case where spec and parser disagree, each with a verdict. Every entry is pinned by a test for each notation, so a fix on any side fails a test and forces the document to change.Nothing under
packages/dbml-parse/srcchanges. The spec restates behaviour; it does not alter it.Conformance results on this branch
@dbml/parsesuiteThe five recorded disagreements are all lexer edge cases (
Note: 12.at end of file is rejected;1aand1.aat end of file lex as numbers;\uaccepts non-hex alphanumerics; letters outside the Basic Multilingual Plane are rejected). Both notations reproduce them identically. Details and verdicts are inspec/DISAGREEMENTS.md.Open questions
spec/README.md):antlr-ngandantlr4as dev dependencies and a generation step. It is the toolchaindbml-corealready uses.Which one should the spec standardise on? Keeping both long-term doubles the maintenance cost and is not proposed.
spec/directory with tests inpackages/dbml-parse. Should they instead live insidepackages/dbml-parse, or become a new@dbml/specpackage that downstream tools can depend on?Planned follow-ups (separate PRs)
spec/output/database.schema.json: JSON Schema of the interpretedDatabasemodel, validated againstsnapshots/interpreter/output/*.out.json.spec/elements/<element>.schema.json: one per element, starting with Table, Ref, Enum, then Dep, each with a conformance test against the correspondingvalidate.ts.DISAGREEMENTS.mdis empty, and generatedbml-homepage/docs/syntax/formal-grammar.mdfromspec/.Issue
None yet. Happy to open one if you would rather track the discussion there.
Lasting Changes (Technical)
peggy,antlr-ngandantlr4as devDependencies of@dbml/parseonly. peggy 5 requires Node 20 or newer; bothpackage.jsonfiles declare>=18. CI runs Node 22, and consumers are unaffected since these are dev-only, but flagging it.test:conformancescript andvitest.conformance.config.tsin@dbml/parse, with a global setup that compilesspec/antlr/*.g4into__tests__/conformance/generated/(git-ignored). The defaultvitest runnow excludes__tests__/conformance/**.spec-conformancejob to.github/workflows/test.yml(continue-on-error: true).CONTRIBUTING.mdto point atpackages/dbml-parse,spec/, and the ANTLR importers. Not touched here, but noticed: the label table inCONTRIBUTING.mdis missingPR: InternalandPR: Dependencies Update, and lists the Refactor emoji as:poop:where the repo label uses:broom:.Labels
I do not have triage rights on this repo. Suggested labels:
PR: New Feature :rocket:(orPR: Internal :house_with_garden:if you consider the spec internal tooling) andpkg: parse.Checklist
dbml-homepage/static/llms.txt(not applicable: no user-facing syntax or docs changed)🤖 Generated with Claude Code