Skip to content

Restore drop-in compatibility: make 'Release' a contextual keyword#83

Merged
CoreyRDean merged 2 commits into
developfrom
align/legacy-release-keyword-identifier
May 30, 2026
Merged

Restore drop-in compatibility: make 'Release' a contextual keyword#83
CoreyRDean merged 2 commits into
developfrom
align/legacy-release-keyword-identifier

Conversation

@CoreyRDean

Copy link
Copy Markdown
Collaborator

Summary (non-technical)

Classic Blitz3D programs freely used release as an ordinary variable name. BlitzForge added a Release keyword (the GC release operator) and reserved it globally, so any legacy program with a release variable 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 makes Release a 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 with Test.

Technical summary

The Release.Type operand operator always has a type identifier immediately after the keyword (with an optional .). So Release is 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 three parser.cpp sites #77 used for Test:

  • parseIdent() now accepts RELEASErelease works as a parameter / Local / Global / Field name and type-instance var.
  • Statement dispatch routes release = … / release(…) / release\field through the IDENT statement path; Release.Type x keeps stmtTok==RELEASE.
  • Expression primary handles Release[.]Type operand when a ./identifier follows, else falls through to the IDENT case.

No tokenizer change; ReleaseNode semantics and the Release.Type grammar are untouched.

Scope is Release only. The other deferred token, Object, is a base Blitz3D keyword (Object.Type(handle)), so object-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

  • release compiles as Local, assignment target, If-condition operand, function parameter, and field-typed var — pinned in tests/LegacyKeywordIdentifierTest.bb; blitzcc -t passes (5 new blocks).
  • The Release.Type obj GC operator still parses and works — positive test asserts RefCount goes 1 → 0 after release.
  • samples/Blitz 2D Samples/spindisc.bb compiles; its allowlist line is removed.
  • Corpus sweep: 352 files, 326 compiled (was 325), 26 known-fail (was 27), 0 new-fail.
  • Full test.bat green ("Tests passed").

Trade-offs / deferred

  • Object contextual-identifier handling (base-keyword problem class — needs separate investigation).
  • Recast/Reference share the same expression-position grammar shape; no corpus collision today, but the same pattern now applies if ever needed.
  • Strongest next-iteration candidate: modern-features docs as a CI-gated executable contract + BBList documentation.

🤖 Generated with Claude Code

CoreyRDean and others added 2 commits May 30, 2026 05:44
'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>
@CoreyRDean CoreyRDean requested a review from a team as a code owner May 30, 2026 10:45
@CoreyRDean CoreyRDean merged commit 701cd23 into develop May 30, 2026
4 checks passed
@CoreyRDean CoreyRDean deleted the align/legacy-release-keyword-identifier branch May 30, 2026 10:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant