diff --git a/examples/ffi-jni-class-06-desc.sx b/examples/ffi-jni-class-06-desc.sx index 6ea385d..d989a47 100644 --- a/examples/ffi-jni-class-06-desc.sx +++ b/examples/ffi-jni-class-06-desc.sx @@ -1,17 +1,17 @@ // Phase 2 step 2.6 (PLAN-FFI.md): xfail then green for the -// `#desc("(Sig)Ret")` per-method JNI-descriptor override. +// `#jni_method_descriptor("(Sig)Ret")` per-method JNI-descriptor +// override. // -// The default descriptor is derived from sx types (Phase 2.8); `#desc` -// is the escape hatch when the auto-derived signature doesn't match -// (e.g., synthetic methods, ambiguous overloads, accessing JNI -// internals). It appears trailing the method's return type, before -// the terminating `;`. Today the parser expects `;` immediately after -// the return type and errors at the `#desc` token. +// The default descriptor is derived from sx types (Phase 2.8); this +// directive is the escape hatch when the auto-derived signature +// doesn't match (e.g., synthetic methods, ambiguous overloads, +// accessing JNI internals). It appears trailing the method's return +// type, before the terminating `;`. #import "modules/std.sx"; Foo :: #jni_class("com/example/Foo") { - weirdMethod :: (self: *Self) -> s32 #desc("()I"); + weirdMethod :: (self: *Self) -> s32 #jni_method_descriptor("()I"); } main :: () -> s32 { diff --git a/src/ast.zig b/src/ast.zig index 36cabe0..67dd2eb 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -539,6 +539,7 @@ pub const JniMethodDecl = struct { param_names: []const []const u8, return_type: ?*Node, // null = void is_static: bool = false, // true for `static name :: ...` + desc_override: ?[]const u8 = null, // `#desc("(Sig)Ret")` — skips auto-derivation in 2.8+ }; pub const JniFieldDecl = struct { diff --git a/src/lexer.zig b/src/lexer.zig index 4aabf86..a68e717 100644 --- a/src/lexer.zig +++ b/src/lexer.zig @@ -85,6 +85,7 @@ pub const Lexer = struct { .{ "#jni_class", Tag.hash_jni_class }, .{ "#extends", Tag.hash_extends }, .{ "#implements", Tag.hash_implements }, + .{ "#jni_method_descriptor", Tag.hash_jni_method_descriptor }, }; inline for (directives) |d| { const keyword = d[0]; diff --git a/src/lsp/server.zig b/src/lsp/server.zig index f17d30a..828f699 100644 --- a/src/lsp/server.zig +++ b/src/lsp/server.zig @@ -1501,6 +1501,7 @@ pub const Server = struct { .hash_jni_class, .hash_extends, .hash_implements, + .hash_jni_method_descriptor, => ST.keyword, .kw_f32, .kw_f64, .kw_Type, .kw_Self => ST.type_, diff --git a/src/parser.zig b/src/parser.zig index e6d4282..bbeec05 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -1121,6 +1121,20 @@ pub const Parser = struct { return_type = try self.parseTypeExpr(); } + // Optional `#jni_method_descriptor("(Sig)Ret")` — explicit JNI descriptor override. + var desc_override: ?[]const u8 = null; + if (self.current.tag == .hash_jni_method_descriptor) { + self.advance(); // skip `#jni_method_descriptor` + try self.expect(.l_paren); + if (self.current.tag != .string_literal) { + return self.fail("expected string literal JNI descriptor after '#jni_method_descriptor('"); + } + const raw_desc = self.tokenSlice(self.current); + desc_override = raw_desc[1 .. raw_desc.len - 1]; + self.advance(); + try self.expect(.r_paren); + } + try self.expect(.semicolon); try members.append(self.allocator, .{ .method = .{ @@ -1129,6 +1143,7 @@ pub const Parser = struct { .param_names = try param_names.toOwnedSlice(self.allocator), .return_type = return_type, .is_static = is_static, + .desc_override = desc_override, } }); } try self.expect(.r_brace); diff --git a/src/token.zig b/src/token.zig index d2d4b4c..e2da850 100644 --- a/src/token.zig +++ b/src/token.zig @@ -118,6 +118,7 @@ pub const Tag = enum { hash_jni_class, // Foo :: #jni_class("java/path/Foo") { ...body... } hash_extends, // `#extends Alias;` inside a #jni_class / #objc_class body hash_implements, // `#implements Alias;` inside a #jni_class / #objc_class body + hash_jni_method_descriptor, // `#jni_method_descriptor("(Sig)Ret")` per-method JNI descriptor override triple_minus, // --- // Special diff --git a/tests/expected/ffi-jni-class-06-desc.exit b/tests/expected/ffi-jni-class-06-desc.exit index d00491f..573541a 100644 --- a/tests/expected/ffi-jni-class-06-desc.exit +++ b/tests/expected/ffi-jni-class-06-desc.exit @@ -1 +1 @@ -1 +0 diff --git a/tests/expected/ffi-jni-class-06-desc.txt b/tests/expected/ffi-jni-class-06-desc.txt index 2ac0d36..2ef3b99 100644 --- a/tests/expected/ffi-jni-class-06-desc.txt +++ b/tests/expected/ffi-jni-class-06-desc.txt @@ -1 +1 @@ -/Users/agra/projects/sx/examples/ffi-jni-class-06-desc.sx:14:41: error: expected ';' +parse-only ok