ffi 2.16a green: parser + AST + sema for #jni_env(env) { body }

New `hash_jni_env` lexer token; `parsePrimary` dispatches to a small
`parseJniEnvBlock` that consumes `(env) { body }` and returns a new
`JniEnvBlock` AST node (env_expr + body block).

Sema's analyzeNode arm recurses into env + body inside a pushed
scope; findNodeAtOffset descends through both children for go-to-
definition.

Lowering treats it as a syntactic wrapper around the block: env is
evaluated for side effects, body lowers as a normal block. The TL
push/pop semantics (synthesizing the env stack so `#jni_call`'s env
arg can become optional) land in 2.16b.

`expectSemicolonAfter` recognises `jni_env_block` as block-form so
statement-position uses don't need a trailing `;` — matches `if` /
`while` / `for` / bare blocks.

Test runs through the block body and prints expected output; xfail
snapshot flips to green. 127/127 examples green.
This commit is contained in:
agra
2026-05-20 10:41:24 +03:00
parent 93adde5a3d
commit 5bd2c84bb6
9 changed files with 53 additions and 2 deletions

View File

@@ -1050,6 +1050,13 @@ pub const Lowering = struct {
.destructure_decl => |dd| self.lowerDestructureDecl(&dd),
.insert_expr => |ins| self.lowerInsertExpr(ins.expr),
.block => self.lowerBlock(node),
.jni_env_block => |eb| {
// 2.16a: evaluate env for side effects, lower body as a normal block.
// TL push/pop semantics land in 2.16b; until then `#jni_env` is a
// syntactic marker that doesn't affect codegen.
_ = self.lowerExpr(eb.env);
self.lowerBlock(eb.body);
},
// Block-local type declarations
.struct_decl => |sd| self.registerStructDecl(&sd),
.enum_decl, .union_decl => {