mdl: language header mdl <n>; with version-gated semantics (#710) - #726
Conversation
An optional first statement declares the MDL language version a script is written in (ADR-0011 decision 2). No header is mdl 0, the alpha meaning. - grammar: `program : languageHeader? statement* EOF`; the word is an IDENTIFIER checked by the visitor, so `mdl` stays usable as a name (e.g. `describe contract entity X format mdl`). - mdl/langver: Version, Latest, and Frozen, the single preview/frozen switch. Before beta mdl 1 is a preview: it warns MDL-LANG01 "preview: may still change" and HeaderLine() (what describe/fmt emit) is "". - langver.Change + Builder.gate: the helper every change of meaning goes through; under an older version the old meaning is kept and a warning is recorded on the Program, reported by ValidateProgram. - executor: ExecContext.LanguageVersion carries the program's header to handlers; nested EXECUTE SCRIPT runs under its own header. - unknown versions are refused; a header after the first statement gets a hint; a header-only script counts as empty for exec/check/fmt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…der (#710) ExecuteProgramContinueOnError enters the header's version separately from ExecuteProgram, and nothing covered it: removing its enterLanguage call left the suite green. The new test fails with handlers seeing mdl 0 throughout. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#710) `mdl 99999999999999999999;` said the version "must be a whole number", which it is. strconv.ErrRange now reports the unknown-version error with the number as written. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Independent review (automated reviewer). Verified: both done-when criteria hold (header parses; Pushed two commits:
Minor, left for the maintainer: no make build / make lint pass. make test: the failures in cmd/mxcli, tui, docker and tunnelhub came only from TMPDIR sitting inside the repo, and those packages pass with TMPDIR outside it. marketplace and backend/modelsdk hit the 10m timeout on the loaded machine and were re-run with -timeout 40m. |
Closes #710. Part of the MDL alpha->beta program (#714), plan item 1.5 of
PROPOSAL_mdl_beta_syntax_freeze.md; implements ADR-0011 decision 2.What
program : languageHeader? statement* EOF,languageHeader : IDENTIFIER NUMBER_LITERAL SEMICOLON. The visitor requires the word to bemdl(case-insensitive). A script with no header ismdl 0.mdl/langver(new):Version,Latest(= 1),Default(= 0) andFrozen, the single preview/frozen switch (currentlyV0). Everything aboveFrozenis a preview:mdl 1;parses but warnsMDL-LANG01"mdl 1 is a preview: may still change", andHeaderLine()(what describe/fmt should emit) returns"". At beta, setFrozen = V1: the warning stops andHeaderLine()returnsmdl 1;.langver.Change{Code, Since, Old, New}plusBuilder.gate(change, ctx)in the visitor. It returns true under the new version. Under an older version the caller keeps the old meaning, and gate records anast.LanguageNotethatValidateProgramreports as a warning under the change's own rule ID. Handlers in the executor readExecContext.LanguageVersionand branch onChange.Applies.ExecuteProgramandExecuteProgramContinueOnErrorrun their statements under the program's header and then restore the previous version, so a nestedEXECUTE SCRIPTuses its own header. A statement run outside a program (REPL,-c) ismdl 0.mdl 2;) is a parse-level error.mdl 1.5;) is refused.exec/check/fmt(the A file of zero recognised statements passescheckand is silently applied byexec#618 guard).mxcli syntax language-header,docs-site/src/language/basics.md,MDL_QUICK_REFERENCE.md.describe and fmt do not emit the header.
fmtis line-based and keeps an existing header in place without adding one; a test pins this.fmt --upgradedoes not exist yet.Design choices the ADRs did not settle
mdlis not a lexer keyword. I first added anMDLtoken (listed inkeyword). That brokedescribe contract entity X format mdl, because that position accepts only anIDENTIFIER, andTestExamplesParse/odata.showcaught it. Matching an IDENTIFIER and checking the word in the visitor leaves every existing use ofmdlas a name unchanged. A test covers both a module/attribute namedmdlandformat mdl.mdl 0;is accepted without comment. The ADR says nobody writes it, but it is harmless.MDL-LANG01is the preview warning. Each gated change carries its ownCode.langver.Changeattached toshowthrough the realBuilder.gate, observed via a listener wrapper (build(input, listen)).langver.Changeis the declaration for changes of meaning. The Deprecation registry for MDL aliases (MDL-DEPRnnn), generalising MDL065 #709 registry is for respellings/aliases, and alias removal at a version boundary can useChange.Applies.Test plan
go test ./mdl/langver/: preview state; the frozen switch (isPreview/headerLinewithfrozen = V1);Known;Change.Applies;IsHeaderLine.go test ./mdl/visitor/ -run LanguageHeader:mdlis still a namego test ./mdl/executor/ -run 'LanguageVersion|UnderTheHeader':mdl 1;, and mdl 0 outside the programgo test ./mdl/formatter/: fmt keeps the header, is idempotent, and adds none while in preview.go test ./cmd/mxcli/ -run 'EmptyInput|Garbage': a header-only script is not refused as unparsable.Parses/HeaderOnlyScriptfail with "got version 0"gatealways true ->GatedConstructDiffersByVersionfails with "got [true true]"PreviewWarnsfails with "got []"enterLanguageremoved fromExecuteProgram->UnderTheHeaderfails with "handlers saw [mdl 0 mdl 0 mdl 0 mdl 0]"ExecContextCarriesLanguageVersionfails./bin/mxcli:checkonmdl 1;prints the MDL-LANG01 warning and passesmdl 3;gives a syntax error (exit 1)fmtkeepsmdl 1;make buildpassed.make lintpassed.make testpassed exceptmdl/backend/modelsdk, which hit the 10-minute go test timeout on a heavily loaded shared machine. Run alone with-timeout 40mit passed (392s). This PR does not touch that package.make testattempt failed on "no space left on device" in the shared /tmp. It was re-run withTMPDIR/GOTMPDIRon the main disk.Follow-ups
langver.Changein its own issue:limit 1/first, mandatoryset, list operations as statements, strict keys, required;, no\escapes.fmt --upgradeadds the header and rewrites the gated constructs, once they exist.langver.FrozentoV1and wirelangver.HeaderLine()into describe/fmt output.🤖 Generated with Claude Code