@@ -969,6 +969,11 @@ fn is_type_prefix(toks: read List<Tok>, j: read Int) -> Bool {
969969 return is_kw_text(toks: read toks, i: read j, word: read "read") || is_kw_text(toks: read toks, i: read j, word: read "mut") || is_kw_text(toks: read toks, i: read j, word: read "take") || is_kw_text(toks: read toks, i: read j, word: read "fresh") || is_kw_text(toks: read toks, i: read j, word: read "handle") || is_kw_text(toks: read toks, i: read j, word: read "weak") || is_kw_text(toks: read toks, i: read j, word: read "noescape") || is_kw_text(toks: read toks, i: read j, word: read "owned")
970970}
971971
972+ // Tokens that end a type ref (used to bound the name search).
973+ fn is_type_terminator(toks: read List<Tok >, j: read Int) -> Bool {
974+ return tk_kind(toks: read toks, i: read j) == TOK_EOF || at_symbol(toks: read toks, i: read j, code: read SYM_COMMA) || at_symbol(toks: read toks, i: read j, code: read SYM_RPAREN) || at_symbol(toks: read toks, i: read j, code: read SYM_RANGLE) || at_symbol(toks: read toks, i: read j, code: read SYM_RBRACE) || at_symbol(toks: read toks, i: read j, code: read SYM_LBRACE) || at_symbol(toks: read toks, i: read j, code: read SYM_SEMI) || at_symbol(toks: read toks, i: read j, code: read SYM_EQ)
975+ }
976+
972977fn emit_type_ref(toks: read List<Tok >, i: read Int, tag: read String, eff: read String, d: read Int) -> Int {
973978 // Prefix flags reflect ONLY the token at `i` (matching parse_type_ref, which
974979 // reads is_fresh/is_noescape/is_owned from tokens[start]).
@@ -978,9 +983,20 @@ fn emit_type_ref(toks: read List<Tok>, i: read Int, tag: read String, eff: read
978983 if at_ident(toks: read toks, i: read i, wid: read WORD_FRESH) { isFresh = true }
979984 else if is_kw_text(toks: read toks, i: read i, word: read "noescape") { isNoescape = true }
980985 else if is_kw_text(toks: read toks, i: read i, word: read "owned") { isOwned = true }
981- // Name is the first non-prefix token.
986+ // Name is the first non-prefix IDENT (parse_type_ref's name_index skips both
987+ // prefix keywords AND non-ident tokens like a leading `& `), bounded by a type
988+ // terminator so a malformed type never scans away.
982989 let mut j = i
983- while is_type_prefix(toks: read toks, j: read j) { j = j + 1 }
990+ let mut scanning = true
991+ while scanning {
992+ if is_ident_tok(toks: read toks, i: read j) && is_type_prefix(toks: read toks, j: read j) == false {
993+ scanning = false
994+ } else if is_type_terminator(toks: read toks, j: read j) {
995+ scanning = false
996+ } else {
997+ j = j + 1
998+ }
999+ }
9841000 let name = tk_text(toks: read toks, i: read j)
9851001 j = j + 1
9861002 local sb = StringBuilder.new()
@@ -1825,7 +1841,12 @@ fn emit_params(toks: read List<Tok>, open: read Int, close: read Int, d: read In
18251841 line = String.concat(left: read l2, right: read effStr)
18261842 }
18271843 emit(depth: read d, s: read line)
1828- emit_type_ref(toks: read toks, i: read k, tag: read "type", eff: read "", d: read (d + 1))
1844+ let afterType = emit_type_ref(toks: read toks, i: read k, tag: read "type", eff: read "", d: read (d + 1))
1845+ // Default value: `name: Type = <expr >` (dump_param emits it after type).
1846+ if at_symbol(toks: read toks, i: read afterType, code: read SYM_EQ) {
1847+ emit(depth: read (d + 1), s: read "default")
1848+ emit_expr(toks: read toks, start: read (afterType + 1), end: read segEnd, d: read (d + 2))
1849+ }
18291850 }
18301851 }
18311852 if comma < 0 { i = close } else { i = comma + 1 }
@@ -2615,8 +2636,7 @@ fn main() -> Unit {
26152636 // A fn whose name won't parse (`fn (…)`) is a program-level malformed
26162637 // declaration (parse_function_decl returns None) — counted for the
26172638 // section-5 marker, not emitted as a fn.
2618- let ns = fn_name_start(toks: read toks, start: read i)
2619- if ns >= 0 && take_function_name(toks: read toks, i: read ns) < 0 {
2639+ if fn_malformed(toks: read toks, start: read i) {
26202640 malDecl = malDecl + 1
26212641 i = advance(toks: read toks, i: read i, r: read next_decl_skip(toks: read toks, start: read i))
26222642 } else {
@@ -2659,6 +2679,29 @@ fn fn_name_start(toks: read List<Tok>, start: read Int) -> Int {
26592679 return j + 1
26602680}
26612681
2682+ // True if a fn head at `start` fails to parse (parse_function_decl returns None):
2683+ // no name, unclosed params `(`, or a body `{` with no matching `}`.
2684+ fn fn_malformed(toks: read List<Tok >, start: read Int) -> Bool {
2685+ let ns = fn_name_start(toks: read toks, start: read start)
2686+ if ns < 0 { return false }
2687+ let nameEnd = take_function_name(toks: read toks, i: read ns)
2688+ if nameEnd < 0 { return true }
2689+ let popen = parse_generic_params(toks: read toks, i: read nameEnd)
2690+ let mut sigStart = popen
2691+ if at_symbol(toks: read toks, i: read popen, code: read SYM_LPAREN) {
2692+ let pclose = find_matching(toks: read toks, open: read popen, openSym: read SYM_LPAREN, closeSym: read SYM_RPAREN)
2693+ if pclose < 0 { return true }
2694+ sigStart = pclose + 1
2695+ }
2696+ let sigEnd = function_signature_end(toks: read toks, start: read sigStart)
2697+ if at_symbol(toks: read toks, i: read sigEnd, code: read SYM_LBRACE) {
2698+ if find_matching(toks: read toks, open: read sigEnd, openSym: read SYM_LBRACE, closeSym: read SYM_RBRACE) < 0 {
2699+ return true
2700+ }
2701+ }
2702+ return false
2703+ }
2704+
26622705// True if token i begins a top-level `features:` header (depth checked by caller).
26632706fn is_features_header(toks: read List<Tok >, i: read Int) -> Bool {
26642707 return is_kw_text(toks: read toks, i: read i, word: read "features") && at_symbol(toks: read toks, i: read (i + 1), code: read SYM_COLON)
@@ -2760,12 +2803,18 @@ fn is_feature_word(toks: read List<Tok>, i: read Int) -> Bool {
27602803}
27612804
27622805// Skip an unsupported top-level item: to its block end if it has one, else its line end.
2806+ // Skip an unknown/malformed top-level declaration (mirrors skip_unknown_top_level):
2807+ // if the declaration line opens a `{`, skip to its matching `}` (or to EOF when it
2808+ // never closes); otherwise skip to the declaration line end.
27632809fn next_decl_skip(toks: read List<Tok >, start: read Int) -> Int {
27642810 let n = List.len(list: read toks)
2765- let openb = find_block_open(toks: read toks, start: read start, limit: read n)
2766- if openb >= 0 && tk_line(toks: read toks, i: read openb) == tk_line(toks: read toks, i: read start) {
2811+ let lineEnd = declaration_line_end(toks: read toks, start: read start)
2812+ let openb = find_block_open(toks: read toks, start: read start, limit: read lineEnd)
2813+ let mut r = lineEnd
2814+ if openb >= 0 {
27672815 let close = find_matching(toks: read toks, open: read openb, openSym: read SYM_LBRACE, closeSym: read SYM_RBRACE)
2768- if close > openb { return close + 1 }
2816+ if close < 0 { r = n } else { r = close + 1 }
27692817 }
2770- return declaration_line_end(toks: read toks, start: read start)
2818+ if r > start { return r }
2819+ return start + 1
27712820}
0 commit comments