Skip to content

Compose the void marker with the readonly glyph: wipe! =! -> - #312

Merged
shreeve merged 1 commit into
mainfrom
void-const
Sep 16, 2026
Merged

shreeve merged 1 commit into
mainfrom
void-const

Conversation

@shreeve

@shreeve shreeve commented Sep 16, 2026

Copy link
Copy Markdown
Owner

Summary

save! = -> defines a void function (no implicit return, no trailing-loop comprehension). x =! v is a readonly binding. They now compose:

wipe! =! (xs) ->
  for x in xs
    x.reset()

export flush! =! -> drain()

emits const wipe = (function(xs) { for (...) {...} return; }); and export const flush = .... Previously both forms were a parse error.

Changes

  • Lexer: DAMMIT directly before =! mints VOID_MARKER, as it already did before =.
  • Grammar: void-readonly rows beside void-assign in Assign and ExportAssign over the same RHS shapes; readonly kind gains the voidMarker role; parser regenerated under the manifest gate, no conflict drift.
  • Emitter: dispatches through the readonly path and registers the value as void. n! =! 5 is rejected with the void-marker error; wipe = 2 after the definition is rejected as a readonly write. TS face declares it readonly.
  • Editor grammars: VS Code and Vim readonly-name rules admit the bang and scope it as the void marker; lockstep test pins captures against compiled output. highlight.js needs no change.
  • Tests: battery rows in assignment.rip and sweep.rip (the wrapped/indented pins reduce the next-line RHS productions the coverage gate requires); void-marker lane and corpus gain the =! case. Corpus: only voidmarker.* regenerate.

Verification

  • bun run test:rip: 3284 pass, 0 fail
  • bun test test/toolchain: 661 pass (production coverage, kinds registry, generated-parser gates)
  • bun run corpus: stable after regeneration
  • bun run test:all: 26 lanes, 9895 tests passed
  • dist/@rip regenerated under Bun 1.4.0

A bang-named definition (`save! = ->`) is void: the implicit return and
the trailing-loop comprehension are suppressed. A readonly binding
(`x =! v`) never changes after its declaration. The two markers now
compose, so `wipe! =! (xs) ->` declares a const void function, and
`export flush! =! ->` its exported form. Both were a parse error.

Lexer: DAMMIT directly before READONLY_ASSIGN mints VOID_MARKER, as it
already did before `=`.

Grammar: `void-readonly` rows beside `void-assign` in Assign and
ExportAssign, over the same RHS shapes (inline, wrapped, indented). The
`readonly` kind gains the `voidMarker` role; the parser regenerates
under the manifest gate with no conflict drift.

Emitter: `void-readonly` dispatches through the readonly path and
registers the value as void, so a non-function value is rejected with
the void-marker error (now listing the `=!` spelling) and a later write
is rejected as a readonly violation. The TS face declares it as a
readonly.

Editor grammars: the VS Code and Vim readonly-name rules admit the
bang between the name and `=!`, scoping it as the void marker; the
lockstep test pins the captures against the compiled output.
highlight.js already reads both glyphs as operators and needs no change.

Tests: battery rows in assignment.rip (undefined return, thin and fat
arrow, const void emission, exported form) and sweep.rip (wrapped and
indented pins, which reduce the next-line RHS productions the grammar
coverage gate requires); the void-marker lane and corpus gain the `=!`
case. Corpus bytes: voidmarker.js/.sexpr.json/.map.json regenerate for
the one added definition; every other snapshot is unchanged.
@shreeve
shreeve merged commit 1e36dfb into main Sep 16, 2026
2 checks passed
@shreeve
shreeve deleted the void-const branch September 16, 2026 07:58
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