ffi 2.2 green: parser collects #jni_class instance method body items
New `JniMethodDecl` AST struct (name, params, param_names, return_type — no body, foreign declaration). `JniClassDecl.body` becomes `methods: []const JniMethodDecl`. parseJniClassDecl loops over body items, parsing each `name :: (self: *Self, args...) -> Ret;` similarly to parseProtocolDecl but requiring `;` (no body brace). `static`, fields, `#extends`, `#implements`, and the other six directive forms land in 2.3–2.7. Sema/lower still treat the decl as an opaque type alias — descriptor derivation arrives in 2.8+. 121/121 examples green.
This commit is contained in:
@@ -533,10 +533,17 @@ pub const ProtocolDecl = struct {
|
|||||||
type_params: []const StructTypeParam = &.{}, // for `protocol(Target: Type) { ... }`
|
type_params: []const StructTypeParam = &.{}, // for `protocol(Target: Type) { ... }`
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const JniMethodDecl = struct {
|
||||||
|
name: []const u8,
|
||||||
|
params: []const *Node, // type_expr nodes — first is `*Self` for instance methods
|
||||||
|
param_names: []const []const u8,
|
||||||
|
return_type: ?*Node, // null = void
|
||||||
|
};
|
||||||
|
|
||||||
pub const JniClassDecl = struct {
|
pub const JniClassDecl = struct {
|
||||||
name: []const u8, // sx-side alias (left of `::`)
|
name: []const u8, // sx-side alias (left of `::`)
|
||||||
java_path: []const u8, // directive arg, e.g. "java/path/Foo"
|
java_path: []const u8, // directive arg, e.g. "java/path/Foo"
|
||||||
body: []const *Node = &.{}, // body items (methods, fields, #extends, ...) — empty in 2.1
|
methods: []const JniMethodDecl = &.{}, // instance methods (static/fields/extends land in later steps)
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ImplBlock = struct {
|
pub const ImplBlock = struct {
|
||||||
|
|||||||
@@ -1040,16 +1040,59 @@ pub const Parser = struct {
|
|||||||
try self.expect(.r_paren);
|
try self.expect(.r_paren);
|
||||||
|
|
||||||
try self.expect(.l_brace);
|
try self.expect(.l_brace);
|
||||||
// Body items (methods, fields, #extends, #implements, ...) land in steps
|
|
||||||
// 2.2 onward. Step 2.1 accepts only the empty body (opaque forward decl).
|
var methods = std.ArrayList(ast.JniMethodDecl).empty;
|
||||||
if (self.current.tag != .r_brace) {
|
while (self.current.tag != .r_brace and self.current.tag != .eof) {
|
||||||
return self.fail("non-empty `#jni_class` body not yet supported (Phase 2.1 accepts only the empty/opaque form)");
|
// Instance method: name :: (self: *Self, args...) -> Ret;
|
||||||
|
// (`static`, fields, #extends, #implements land in later steps.)
|
||||||
|
if (self.current.tag != .identifier) {
|
||||||
|
return self.fail("expected method name in '#jni_class' body");
|
||||||
|
}
|
||||||
|
const method_name = self.tokenSlice(self.current);
|
||||||
|
self.advance();
|
||||||
|
try self.expect(.colon_colon);
|
||||||
|
try self.expect(.l_paren);
|
||||||
|
|
||||||
|
var param_types = std.ArrayList(*Node).empty;
|
||||||
|
var param_names = std.ArrayList([]const u8).empty;
|
||||||
|
while (self.current.tag != .r_paren and self.current.tag != .eof) {
|
||||||
|
if (param_types.items.len > 0) {
|
||||||
|
try self.expect(.comma);
|
||||||
|
if (self.current.tag == .r_paren) break;
|
||||||
|
}
|
||||||
|
if (self.current.tag != .identifier and self.current.tag != .kw_Self) {
|
||||||
|
return self.fail("expected parameter name in '#jni_class' method");
|
||||||
|
}
|
||||||
|
const pname = self.tokenSlice(self.current);
|
||||||
|
self.advance();
|
||||||
|
try self.expect(.colon);
|
||||||
|
const ptype = try self.parseTypeExpr();
|
||||||
|
try param_names.append(self.allocator, pname);
|
||||||
|
try param_types.append(self.allocator, ptype);
|
||||||
|
}
|
||||||
|
try self.expect(.r_paren);
|
||||||
|
|
||||||
|
var return_type: ?*Node = null;
|
||||||
|
if (self.current.tag == .arrow) {
|
||||||
|
self.advance();
|
||||||
|
return_type = try self.parseTypeExpr();
|
||||||
|
}
|
||||||
|
|
||||||
|
try self.expect(.semicolon);
|
||||||
|
|
||||||
|
try methods.append(self.allocator, .{
|
||||||
|
.name = method_name,
|
||||||
|
.params = try param_types.toOwnedSlice(self.allocator),
|
||||||
|
.param_names = try param_names.toOwnedSlice(self.allocator),
|
||||||
|
.return_type = return_type,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
try self.expect(.r_brace);
|
try self.expect(.r_brace);
|
||||||
|
|
||||||
return try self.createNode(start_pos, .{ .jni_class_decl = .{
|
return try self.createNode(start_pos, .{ .jni_class_decl = .{
|
||||||
.name = name,
|
.name = name,
|
||||||
.java_path = java_path,
|
.java_path = java_path,
|
||||||
|
.methods = try methods.toOwnedSlice(self.allocator),
|
||||||
} });
|
} });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1
|
0
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/Users/agra/projects/sx/examples/ffi-jni-class-02-method.sx:14:5: error: non-empty `#jni_class` body not yet supported (Phase 2.1 accepts only the empty/opaque form)
|
parse-only ok
|
||||||
|
|||||||
Reference in New Issue
Block a user