@@ -277,6 +277,17 @@ fn emit_expr(toks: read List<Tok>, start: read Int, end: read Int, d: read Int)
277277 emit_explicit_fn(toks: read toks, start: read s, end: read e, d: read d)
278278 return Unit
279279 }
280+ // Effect-annotated closure `read || { … }` / `mut |x| …`: handled BEFORE the
281+ // binary split so the closure `|` pipes aren't read as logical-or / bit-or.
282+ // (parse_expr special-cases ONLY effect+closure here; a general `read <expr >`
283+ // like `read r * read r` still splits at the operator first — effect binds
284+ // tighter than any binary op.)
285+ let effClosure = effect_kw(toks: read toks, i: read s)
286+ if String.len(value: read effClosure) > 0 && at_symbol(toks: read toks, i: read (s + 1), code: read SYM_PIPE) {
287+ emit(depth: read d, s: read String.concat(left: read "effect kind=", right: read effClosure))
288+ emit_closure(toks: read toks, start: read (s + 1), end: read e, d: read (d + 1))
289+ return Unit
290+ }
280291 // Binary split (lowest precedence, last top-level occurrence).
281292 let opIdx = find_binop(toks: read toks, start: read s, end: read e)
282293 if opIdx >= 0 {
@@ -315,10 +326,10 @@ fn emit_expr(toks: read List<Tok>, start: read Int, end: read Int, d: read Int)
315326 return Unit
316327 }
317328 }
318- // Effect prefix: read/mut/take <value >. The receiver-call shorthand
319- // `< effect > recv.method(args)` (lowercase receiver) parses as a ReceiverCall,
320- // NOT an Effect wrapper; an uppercase namespace (`read Cache.put()`) stays a
321- // qualified call under the effect .
329+ // General effect prefix: read/mut/take <value >, handled AFTER the binary split
330+ // ( effect binds tighter than any operator). The receiver-call shorthand
331+ // `< effect > recv.method(args)` (lowercase receiver) parses as a ReceiverCall;
332+ // an uppercase namespace (`read Cache.put()`) stays a qualified call under it .
322333 let effWord = effect_kw(toks: read toks, i: read s)
323334 if String.len(value: read effWord) > 0 {
324335 let recvStart = s + 1
@@ -1694,13 +1705,39 @@ fn find_block_open(toks: read List<Tok>, start: read Int, limit: read Int) -> In
16941705// Emit a `block` node and its statements for the braces [open, close].
16951706fn emit_block(toks: read List<Tok >, open: read Int, close: read Int, d: read Int) -> Unit {
16961707 emit(depth: read d, s: read "block")
1697- let mut i = open + 1
1708+ emit_stmts(toks: read toks, from: read (open + 1), close: read close, d: read (d + 1))
1709+ return Unit
1710+ }
1711+
1712+ // True if a scoped-view binding `view <ident > = …` begins at i (is_view_binding).
1713+ fn is_view_binding(toks: read List<Tok >, i: read Int, close: read Int) -> Bool {
1714+ return is_kw_text(toks: read toks, i: read i, word: read "view") && is_ident_tok(toks: read toks, i: read (i + 1)) && at_symbol(toks: read toks, i: read (i + 2), code: read SYM_EQ) && (i + 2) < close
1715+ }
1716+
1717+ // Emit statements in [from, close) at depth d. A `view name = expr` desugars to a
1718+ // `with expr as name { <rest of block> }` that captures the remaining statements
1719+ // (collect_statements' scoped-view desugar).
1720+ fn emit_stmts(toks: read List<Tok >, from: read Int, close: read Int, d: read Int) -> Unit {
1721+ let mut i = from
16981722 while i < close {
1699- // Skip stray semicolons/commas that are statement trivia.
17001723 if at_symbol(toks: read toks, i: read i, code: read SYM_SEMI) {
17011724 i = i + 1
1725+ } else if is_view_binding(toks: read toks, i: read i, close: read close) {
1726+ let name = tk_text(toks: read toks, i: read (i + 1))
1727+ let stEnd = stmt_end(toks: read toks, start: read i, limit: read close)
1728+ let eqPos = first_eq(toks: read toks, start: read (i + 2), end: read stEnd)
1729+ emit(depth: read d, s: read String.concat(left: read "with binding=", right: read name))
1730+ emit(depth: read (d + 1), s: read "resource")
1731+ if eqPos >= 0 {
1732+ emit_expr(toks: read toks, start: read (eqPos + 1), end: read stEnd, d: read (d + 2))
1733+ } else {
1734+ emit(depth: read (d + 2), s: read "unknown-expr")
1735+ }
1736+ emit(depth: read (d + 1), s: read "block")
1737+ emit_stmts(toks: read toks, from: read stEnd, close: read close, d: read (d + 2))
1738+ i = close
17021739 } else {
1703- let next = emit_stmt(toks: read toks, start: read i, limit: read close, d: read (d + 1) )
1740+ let next = emit_stmt(toks: read toks, start: read i, limit: read close, d: read d )
17041741 if next > i { i = next } else { i = i + 1 }
17051742 }
17061743 }
@@ -2495,7 +2532,9 @@ fn emit_match_arms(toks: read List<Tok>, start: read Int, end: read Int, d: read
24952532 let mut i = start
24962533 let mut mal = 0
24972534 while i < end {
2498- if at_symbol(toks: read toks, i: read i, code: read SYM_SEMI) {
2535+ // Skip separators between arms (`,`/`;`) so a trailing comma after an arm's
2536+ // `{ }` block isn't misread as an arm with no `=>`.
2537+ if at_symbol(toks: read toks, i: read i, code: read SYM_SEMI) || at_symbol(toks: read toks, i: read i, code: read SYM_COMMA) {
24992538 i = i + 1
25002539 } else {
25012540 let lineEnd = next_line_or_block_end(toks: read toks, start: read i, end: read end)
0 commit comments