@@ -982,23 +982,56 @@ fn emit_type_ref(toks: read List<Tok>, i: read Int, tag: read String, eff: read
982982
983983// Statement end: first token on a strictly-later line at bracket depth 0 (simple
984984// line model; operator-continuation and postfix chains are a documented gap).
985+ // Statement boundary, mirroring parser/scan.rs statement_end. A statement ends at
986+ // the first token on a strictly-later line at bracket+angle depth 0, EXCEPT: a
987+ // top-level `;` terminates immediately; a line starting with `.`/`?` (postfix) or
988+ // with/after a continuation operator (`| & + * / % ^`) continues the statement.
985989fn stmt_end(toks: read List<Tok >, start: read Int, limit: read Int) -> Int {
986- let ln = tk_line(toks: read toks, i: read start)
990+ let mut line = tk_line(toks: read toks, i: read start)
987991 let mut depth = 0
992+ let mut angle = 0
993+ let mut postfixLine = -1
988994 let mut i = start + 1
989995 while i < limit {
996+ if depth == 0 && angle == 0 && at_symbol(toks: read toks, i: read i, code: read SYM_SEMI) {
997+ return i
998+ }
999+ if depth == 0 && angle == 0 && tk_line(toks: read toks, i: read i) > line {
1000+ if postfixLine == tk_line(toks: read toks, i: read i) {
1001+ // still on a postfix-continuation line — keep scanning.
1002+ } else if is_stmt_postfix(toks: read toks, i: read i) {
1003+ postfixLine = tk_line(toks: read toks, i: read i)
1004+ } else if is_cont_op(toks: read toks, i: read i) || is_cont_op(toks: read toks, i: read (i - 1)) {
1005+ line = tk_line(toks: read toks, i: read i)
1006+ } else {
1007+ return i
1008+ }
1009+ }
9901010 if at_symbol(toks: read toks, i: read i, code: read SYM_LPAREN) || at_symbol(toks: read toks, i: read i, code: read SYM_LBRACE) || at_symbol(toks: read toks, i: read i, code: read SYM_LBRACKET) {
9911011 depth = depth + 1
9921012 } else if at_symbol(toks: read toks, i: read i, code: read SYM_RPAREN) || at_symbol(toks: read toks, i: read i, code: read SYM_RBRACE) || at_symbol(toks: read toks, i: read i, code: read SYM_RBRACKET) {
993- depth = depth - 1
994- } else if depth == 0 && tk_line(toks: read toks, i: read i) > ln {
995- return i
1013+ if depth > 0 { depth = depth - 1 }
1014+ } else if depth == 0 && at_symbol(toks: read toks, i: read i, code: read SYM_LANGLE) && is_generic_angle(toks: read toks, start: read start, end: read limit, open: read i) {
1015+ angle = angle + 1
1016+ } else if depth == 0 && angle > 0 && at_symbol(toks: read toks, i: read i, code: read SYM_RANGLE) {
1017+ angle = angle - 1
9961018 }
9971019 i = i + 1
9981020 }
9991021 return limit
10001022}
10011023
1024+ fn is_stmt_postfix(toks: read List<Tok >, i: read Int) -> Bool {
1025+ return at_symbol(toks: read toks, i: read i, code: read SYM_QUESTION) || at_symbol(toks: read toks, i: read i, code: read SYM_DOT)
1026+ }
1027+
1028+ // Continuation operators (SH-017): `| & + * / % ^` — a statement-level expression
1029+ // wraps across a newline when a line begins with, or ends before, one of these.
1030+ // `< > - = !` are deliberately excluded (see scan.rs).
1031+ fn is_cont_op(toks: read List<Tok >, i: read Int) -> Bool {
1032+ return at_symbol(toks: read toks, i: read i, code: read SYM_PIPE) || at_symbol(toks: read toks, i: read i, code: read SYM_AMP) || at_symbol(toks: read toks, i: read i, code: read SYM_PLUS) || at_symbol(toks: read toks, i: read i, code: read SYM_STAR) || at_symbol(toks: read toks, i: read i, code: read SYM_SLASH) || at_symbol(toks: read toks, i: read i, code: read SYM_PERCENT) || at_symbol(toks: read toks, i: read i, code: read SYM_CARET)
1033+ }
1034+
10021035// First top-level standalone `=` (assignment, not == != <= >=) in [start, end), or -1.
10031036fn top_assign(toks: read List<Tok >, start: read Int, end: read Int) -> Int {
10041037 let mut depth = 0
0 commit comments