@@ -1350,6 +1350,12 @@ fn emit_with(toks: read List<Tok>, start: read Int, limit: read Int, d: read Int
13501350 return stmt_end(toks: read toks, start: read start, limit: read limit)
13511351 }
13521352 let close = find_matching(toks: read toks, open: read open, openSym: read SYM_LBRACE, closeSym: read SYM_RBRACE)
1353+ // The binding after `as` must be an ident immediately before the block `{`
1354+ // (`as {` with no binding is malformed) — mirrors parse_with_stmt.
1355+ if is_ident_tok(toks: read toks, i: read (asIdx + 1)) == false || (asIdx + 2) != open {
1356+ emit(depth: read d, s: read "malformed-with")
1357+ return close + 1
1358+ }
13531359 let binding = tk_text(toks: read toks, i: read (asIdx + 1))
13541360 emit(depth: read d, s: read String.concat(left: read "with binding=", right: read binding))
13551361 emit(depth: read (d + 1), s: read "resource")
@@ -1534,7 +1540,10 @@ fn emit_function(toks: read List<Tok>, start: read Int, d: read Int) -> Int {
15341540 let sigEnd = function_signature_end(toks: read toks, start: read (pclose + 1))
15351541 let mut bodyOpen = -1
15361542 if at_symbol(toks: read toks, i: read sigEnd, code: read SYM_LBRACE) { bodyOpen = sigEnd }
1537- let hasBody = bodyOpen >= 0 && (isNative == false || same_stmt_line(toks: read toks, a: read start, b: read bodyOpen))
1543+ // A body exists iff sigEnd lands on `{` — including native fns, whose body may
1544+ // sit on a line after the `effects(native)` clause (parse_function_decl treats
1545+ // it as a normal body; the earlier same_stmt_line guard wrongly dropped it).
1546+ let hasBody = bodyOpen >= 0
15381547 let effPos = find_effects_kw(toks: read toks, start: read (pclose + 1), end: read sigEnd)
15391548 let defaultImpl = has_default_impl(toks: read toks, start: read (pclose + 1), end: read sigEnd)
15401549 // A `fresh` anywhere in the return-type region (e.g. `-> Result<fresh String, E>`)
@@ -2560,6 +2569,7 @@ fn main() -> Unit {
25602569 emit_all_features(toks: read toks, ntok: read ntok)
25612570 let mut i = 0
25622571 let mut malDecl = 0
2572+ let mut unknownTop = 0
25632573 let mut running = true
25642574 while running {
25652575 if i >= ntok {
@@ -2574,9 +2584,19 @@ fn main() -> Unit {
25742584 // Already emitted in the pre-pass; skip the header line.
25752585 i = declaration_line_end(toks: read toks, start: read (i + 2))
25762586 } else if cls.isProfile {
2587+ // `profile …` is no longer a recognized top-level item → the oracle
2588+ // records it as unknown-top-level (section 5).
2589+ unknownTop = unknownTop + 1
25772590 i = declaration_line_end(toks: read toks, start: read i)
25782591 } else if starts_type_decl(toks: read toks, i: read i, isPub: read cls.isPub) {
2579- i = advance(toks: read toks, i: read i, r: read emit_type_decl(toks: read toks, start: read i, d: read 1))
2592+ // A struct/class/resource with no name (`struct {`) fails to parse →
2593+ // program-level malformed-declaration.
2594+ if type_decl_malformed(toks: read toks, start: read i) {
2595+ malDecl = malDecl + 1
2596+ i = advance(toks: read toks, i: read i, r: read next_decl_skip(toks: read toks, start: read i))
2597+ } else {
2598+ i = advance(toks: read toks, i: read i, r: read emit_type_decl(toks: read toks, start: read i, d: read 1))
2599+ }
25802600 } else if cls.isSum {
25812601 i = advance(toks: read toks, i: read i, r: read emit_sum(toks: read toks, start: read i, d: read 1))
25822602 } else if cls.isTypeAlias {
@@ -2603,17 +2623,30 @@ fn main() -> Unit {
26032623 i = advance(toks: read toks, i: read i, r: read emit_function(toks: read toks, start: read i, d: read 1))
26042624 }
26052625 } else {
2626+ // Unrecognized top-level token (e.g. `namespace …`) → unknown-top-level.
2627+ unknownTop = unknownTop + 1
26062628 i = advance(toks: read toks, i: read i, r: read next_decl_skip(toks: read toks, start: read i))
26072629 }
26082630 }
26092631 }
2610- // Section 5: feature diagnostics ( unknown-feature then duplicate-feature),
2611- // then malformed-declaration, emitted AFTER all items — matching ast_oracle_dump .
2632+ // Section 5, in ast_oracle_dump order: unknown-feature, duplicate-feature (both
2633+ // in emit_feature_diags), then unknown-top-level, then malformed-declaration .
26122634 emit_feature_diags(toks: read toks, ntok: read ntok)
2635+ emit_repeat(marker: read "unknown-top-level", n: read unknownTop, d: read 1)
26132636 emit_repeat(marker: read "malformed-declaration", n: read malDecl, d: read 1)
26142637 return Unit
26152638}
26162639
2640+ // True if a struct/class/resource declaration at `start` has no name (`struct {`),
2641+ // which parse_type_decl rejects → program-level malformed-declaration.
2642+ fn type_decl_malformed(toks: read List<Tok >, start: read Int) -> Bool {
2643+ let mut j = start
2644+ if is_kw_text(toks: read toks, i: read j, word: read "pub") { j = j + 1 }
2645+ if is_kw_text(toks: read toks, i: read j, word: read "opaque") { j = j + 1 }
2646+ j = j + 1
2647+ return is_ident_tok(toks: read toks, i: read j) == false
2648+ }
2649+
26172650// Position of the function name (just past `fn`) after skipping #attrs and
26182651// pub/async/native, or -1 if this isn't a fn-like head.
26192652fn fn_name_start(toks: read List<Tok >, start: read Int) -> Int {
0 commit comments