Phase 6f: let = immutable, var = mutable (binding-only)
Bindings now signal mutability the way Rust/Swift do, instead of `let` meaning
"local" and `var` meaning "module-level":
- `let x = e` -> immutable binding; a later `x = …` is a compile error
(`cannot assign to immutable 'x' … use var`).
- `var x = e` -> mutable binding, at local OR module scope (position decides
scope; the keyword decides mutability).
- `const` -> unchanged (compile-time).
Immutability is of the *binding*, not the object: `let n = new Node; n.kind = 1`
is fine (mutation through the reference); only rebinding `n` is rejected. The
check lives in emit_assign — a direct `name =` whose target is a `let` local
(loc_mut == 0) errors; field/index targets and `var`/param/loop bindings are
unaffected.
Delivered as three reseeds so the self-hosting compiler never had to compile
source its own rules would reject:
A) add `var` as a local statement + per-local mutability tracking (loc_mut),
no enforcement;
B) migrate every reassigned `let` -> `var` across the compiler, runtime and
examples (337 declarations), driven by a per-function, string/comment-aware
scan (binding targets only, never `x.f =` / `x[i] =`);
C) turn on the check. bootstrap-cfree (compiler vs its own source) and every
golden build (which splices the runtime) then proved zero reassigned `let`
was missed anywhere.
Also folded in: removed leftover debug instrumentation in block() (a `cur=` /
print_int(777…) trace on the separator-error path) and fixed parse.ludic's stale
header comment (no more `struct`). Reseeded (21711 lines); C-free fixpoint holds;
goldens identical; 17/17; vocab + doc-fences clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
573813609c
commit
e1d7797e29
38 changed files with 2909 additions and 2778 deletions
|
|
@ -5,7 +5,7 @@
|
|||
fn parse_component() -> Node {
|
||||
pi = pi + 1; let n = node(N_COMP); n.s = eat_id(); skipnl(); eat_op("{")
|
||||
while true { skipnl(); if is_op("}") { break }
|
||||
let is_computed = false
|
||||
var is_computed = false
|
||||
if is_op("@") { pi = pi + 1; let ann = eat_id(); if streq(ann, "Computed") { is_computed = true }; skipnl() }
|
||||
let f = node(N_FIELD); f.s = eat_id(); eat_op(":"); f.ty = ptype()
|
||||
if is_op("=") { pi = pi + 1; f.a = expr() }
|
||||
|
|
@ -23,7 +23,7 @@ fn parse_system() -> Node {
|
|||
# in a signature clause.
|
||||
while true {
|
||||
skipnl() # clauses may span several lines
|
||||
if is_op("@") { pi = pi + 1; let a = eat_id(); if is_op("(") { let d = 0 # @anno, one per turn so a
|
||||
if is_op("@") { pi = pi + 1; let a = eat_id(); if is_op("(") { var d = 0 # @anno, one per turn so a
|
||||
while true { if is_op("(") { d = d + 1 }; if is_op(")") { d = d - 1 }; pi = pi + 1; if d == 0 { break } } }
|
||||
continue } # newline-separated @anno re-skips at the loop top
|
||||
if is_id("phase") { pi = pi + 1; n.ty = eat_id(); continue }
|
||||
|
|
@ -99,7 +99,7 @@ fn parse_queries_anno() -> Node {
|
|||
eat_op("(")
|
||||
let qn = node(S_QUERY)
|
||||
let terms = node(N_BLOCK)
|
||||
let wh: Node = ptr_null()
|
||||
var wh: Node = ptr_null()
|
||||
while not is_op(")") {
|
||||
skipnl()
|
||||
if is_op(")") { break }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue