Restore drop-in compatibility: make 'Release' a contextual keyword#83
Merged
Merged
Conversation
'Release' is a BlitzForge addition (the GC release operator `Release.Type <obj>`); stock Blitz3D had no such keyword and freely used `release` as an ordinary variable. Reserving it globally broke drop-in source compatibility (INTENT #1) -- e.g. spindisc.bb's `If release = 1` failed with "Expecting identifier". This is the Phase 2 explicitly deferred by the contextual-'Test' work (PR #77). The operator form always has a type identifier immediately after the keyword (with an optional '.'): `Release.Type operand` / `Release Type operand`. So 'Release' is the keyword iff the next token is '.' or an identifier; otherwise it is a plain identifier. Apply that disambiguator at the three sites #77 used for 'Test': - parseIdent() accepts RELEASE (so `release` works as a parameter / Local / Global / Field name and type-instance var); - statement dispatch routes `release =`/`release(`/`release\f` through the IDENT path, keeping `Release.Type` as the operator; - the expression primary handles `Release.Type operand` when a '.'/ident follows, else falls through to the IDENT case. No tokenizer change; ReleaseNode semantics and the `Release.Type` grammar are untouched. Scope is 'Release' only -- 'Object' is a base Blitz3D keyword, a separate problem class, left deferred. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extend LegacyKeywordIdentifierTest.bb with `release` in every identifier position (local, assignment, If-condition operand, parameter, field-typed var) plus a positive test that the `Release.Type` GC operator still releases an object (RefCount 1 -> 0). Remove spindisc.bb from the corpus allowlist (it compiles now); the sweep goes 325 -> 326 compiled with 0 new failures. Record the working note. Co-Authored-By: Claude Opus 4.8 (1M context) <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 (non-technical)
Classic Blitz3D programs freely used
releaseas an ordinary variable name. BlitzForge added aReleasekeyword (the GC release operator) and reserved it globally, so any legacy program with areleasevariable failed to compile with a baffling "Expecting identifier" — a direct hit to the project's #1 promise: compile their old game on day one, no source changes. This makesReleasea contextual keyword: it's the GC operator only where it actually is one (Release.Type <obj>), and an ordinary identifier everywhere else. This is Phase 2 of the contextual-keyword work that #77 began withTest.Technical summary
The
Release.Type operandoperator always has a type identifier immediately after the keyword (with an optional.). SoReleaseis the keyword iff the next token is.or an identifier; otherwise it's a plain identifier (release=,release\f,release(,release[,If release=1). Applied at the same threeparser.cppsites #77 used forTest:parseIdent()now acceptsRELEASE→releaseworks as a parameter /Local/Global/Fieldname and type-instance var.release = …/release(…)/release\fieldthrough theIDENTstatement path;Release.Type xkeepsstmtTok==RELEASE.Release[.]Type operandwhen a./identifier follows, else falls through to theIDENTcase.No tokenizer change;
ReleaseNodesemantics and theRelease.Typegrammar are untouched.Scope is
Releaseonly. The other deferred token,Object, is a base Blitz3D keyword (Object.Type(handle)), soobject-as-identifier wouldn't have compiled in stock Blitz3D either — a different problem class, left deferred with an explanatory allowlist note.No breaking changes.
Acceptance criteria & results
releasecompiles as Local, assignment target, If-condition operand, function parameter, and field-typed var — pinned intests/LegacyKeywordIdentifierTest.bb;blitzcc -tpasses (5 new blocks).Release.Type objGC operator still parses and works — positive test assertsRefCountgoes1 → 0after release.samples/Blitz 2D Samples/spindisc.bbcompiles; its allowlist line is removed.test.batgreen ("Tests passed").Trade-offs / deferred
Objectcontextual-identifier handling (base-keyword problem class — needs separate investigation).Recast/Referenceshare the same expression-position grammar shape; no corpus collision today, but the same pattern now applies if ever needed.🤖 Generated with Claude Code