ffi 2.7 green: parser accepts all seven type-introducer directive forms
Six new lexer tokens (`hash_jni_interface`, `hash_objc_class`, `hash_objc_protocol`, `hash_swift_class`, `hash_swift_struct`, `hash_swift_protocol`) join the existing `hash_jni_class`. All seven share the body grammar from Phases 2.1–2.6. AST refactored: `JniClassDecl` → `ForeignClassDecl` with a `runtime: ForeignRuntime` enum discriminator; `JniMethodDecl` → `ForeignMethodDecl` (with `jni_descriptor_override` renamed for clarity since it's JNI-only); `JniFieldDecl` → `ForeignFieldDecl`; `JniClassMember` → `ForeignClassMember`. AST variant renamed `jni_class_decl` → `foreign_class_decl`. `parseForeignClassDecl` takes the runtime as a parameter; the `parseConstBinding` dispatch table now maps each of the seven directive tokens to its `ForeignRuntime` variant via `foreignRuntimeForCurrent`. No codegen yet — Phase 3 picks up Obj-C runtime, Phase 4 picks up Swift. Runtime-specific body items (fields, descriptor override) are validated at sema time in later steps. 126/126 examples green.
This commit is contained in:
33
src/ast.zig
33
src/ast.zig
@@ -81,7 +81,7 @@ pub const Node = struct {
|
|||||||
protocol_decl: ProtocolDecl,
|
protocol_decl: ProtocolDecl,
|
||||||
impl_block: ImplBlock,
|
impl_block: ImplBlock,
|
||||||
ffi_intrinsic_call: FfiIntrinsicCall,
|
ffi_intrinsic_call: FfiIntrinsicCall,
|
||||||
jni_class_decl: JniClassDecl,
|
foreign_class_decl: ForeignClassDecl,
|
||||||
|
|
||||||
pub fn declName(self: Data) ?[]const u8 {
|
pub fn declName(self: Data) ?[]const u8 {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
@@ -95,7 +95,7 @@ pub const Node = struct {
|
|||||||
.ufcs_alias => |d| d.name,
|
.ufcs_alias => |d| d.name,
|
||||||
.c_import_decl => |d| d.name,
|
.c_import_decl => |d| d.name,
|
||||||
.protocol_decl => |d| d.name,
|
.protocol_decl => |d| d.name,
|
||||||
.jni_class_decl => |d| d.name,
|
.foreign_class_decl => |d| d.name,
|
||||||
else => null,
|
else => null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -533,31 +533,42 @@ pub const ProtocolDecl = struct {
|
|||||||
type_params: []const StructTypeParam = &.{}, // for `protocol(Target: Type) { ... }`
|
type_params: []const StructTypeParam = &.{}, // for `protocol(Target: Type) { ... }`
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const JniMethodDecl = struct {
|
pub const ForeignRuntime = enum {
|
||||||
|
jni_class,
|
||||||
|
jni_interface,
|
||||||
|
objc_class,
|
||||||
|
objc_protocol,
|
||||||
|
swift_class,
|
||||||
|
swift_struct,
|
||||||
|
swift_protocol,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ForeignMethodDecl = struct {
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
params: []const *Node, // type_expr nodes — first is `*Self` for instance methods
|
params: []const *Node, // type_expr nodes — first is `*Self` for instance methods
|
||||||
param_names: []const []const u8,
|
param_names: []const []const u8,
|
||||||
return_type: ?*Node, // null = void
|
return_type: ?*Node, // null = void
|
||||||
is_static: bool = false, // true for `static name :: ...`
|
is_static: bool = false, // true for `static name :: ...`
|
||||||
desc_override: ?[]const u8 = null, // `#desc("(Sig)Ret")` — skips auto-derivation in 2.8+
|
jni_descriptor_override: ?[]const u8 = null, // `#jni_method_descriptor("(Sig)Ret")` — JNI runtime only
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const JniFieldDecl = struct {
|
pub const ForeignFieldDecl = struct {
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
field_type: *Node, // type_expr node
|
field_type: *Node, // type_expr node
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const JniClassMember = union(enum) {
|
pub const ForeignClassMember = union(enum) {
|
||||||
method: JniMethodDecl,
|
method: ForeignMethodDecl,
|
||||||
field: JniFieldDecl,
|
field: ForeignFieldDecl, // JNI runtime only (sema-checked in later step)
|
||||||
extends: []const u8, // sx-side alias name (right of `#extends`)
|
extends: []const u8, // sx-side alias name (right of `#extends`)
|
||||||
implements: []const u8, // sx-side alias name (right of `#implements`)
|
implements: []const u8, // sx-side alias name (right of `#implements`)
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const JniClassDecl = struct {
|
pub const ForeignClassDecl = 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"
|
foreign_path: []const u8, // directive arg: "java/path/Foo" / "NSString" / "Foundation.URL"
|
||||||
members: []const JniClassMember = &.{}, // methods, #extends, #implements (fields/#desc land in 2.5+)
|
runtime: ForeignRuntime,
|
||||||
|
members: []const ForeignClassMember = &.{},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ImplBlock = struct {
|
pub const ImplBlock = struct {
|
||||||
|
|||||||
@@ -83,6 +83,12 @@ pub const Lexer = struct {
|
|||||||
.{ "#jni_call", Tag.hash_jni_call },
|
.{ "#jni_call", Tag.hash_jni_call },
|
||||||
.{ "#jni_static_call", Tag.hash_jni_static_call },
|
.{ "#jni_static_call", Tag.hash_jni_static_call },
|
||||||
.{ "#jni_class", Tag.hash_jni_class },
|
.{ "#jni_class", Tag.hash_jni_class },
|
||||||
|
.{ "#jni_interface", Tag.hash_jni_interface },
|
||||||
|
.{ "#objc_class", Tag.hash_objc_class },
|
||||||
|
.{ "#objc_protocol", Tag.hash_objc_protocol },
|
||||||
|
.{ "#swift_class", Tag.hash_swift_class },
|
||||||
|
.{ "#swift_struct", Tag.hash_swift_struct },
|
||||||
|
.{ "#swift_protocol", Tag.hash_swift_protocol },
|
||||||
.{ "#extends", Tag.hash_extends },
|
.{ "#extends", Tag.hash_extends },
|
||||||
.{ "#implements", Tag.hash_implements },
|
.{ "#implements", Tag.hash_implements },
|
||||||
.{ "#jni_method_descriptor", Tag.hash_jni_method_descriptor },
|
.{ "#jni_method_descriptor", Tag.hash_jni_method_descriptor },
|
||||||
|
|||||||
@@ -1499,6 +1499,12 @@ pub const Server = struct {
|
|||||||
.hash_jni_call,
|
.hash_jni_call,
|
||||||
.hash_jni_static_call,
|
.hash_jni_static_call,
|
||||||
.hash_jni_class,
|
.hash_jni_class,
|
||||||
|
.hash_jni_interface,
|
||||||
|
.hash_objc_class,
|
||||||
|
.hash_objc_protocol,
|
||||||
|
.hash_swift_class,
|
||||||
|
.hash_swift_struct,
|
||||||
|
.hash_swift_protocol,
|
||||||
.hash_extends,
|
.hash_extends,
|
||||||
.hash_implements,
|
.hash_implements,
|
||||||
.hash_jni_method_descriptor,
|
.hash_jni_method_descriptor,
|
||||||
|
|||||||
@@ -209,9 +209,10 @@ pub const Parser = struct {
|
|||||||
return self.parseProtocolDecl(name, start_pos);
|
return self.parseProtocolDecl(name, start_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// JNI class binding: name :: #jni_class("java/path/Foo") { ...body... }
|
// Foreign-type binding: name :: #jni_class / #jni_interface / #objc_class /
|
||||||
if (self.current.tag == .hash_jni_class) {
|
// #objc_protocol / #swift_class / #swift_struct / #swift_protocol ("path") { body }
|
||||||
return self.parseJniClassDecl(name, start_pos);
|
if (self.foreignRuntimeForCurrent()) |runtime| {
|
||||||
|
return self.parseForeignClassDecl(name, start_pos, runtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// C-style union declaration
|
// C-style union declaration
|
||||||
@@ -1027,21 +1028,34 @@ pub const Parser = struct {
|
|||||||
} });
|
} });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseJniClassDecl(self: *Parser, name: []const u8, start_pos: u32) anyerror!*Node {
|
fn foreignRuntimeForCurrent(self: *Parser) ?ast.ForeignRuntime {
|
||||||
self.advance(); // skip '#jni_class'
|
return switch (self.current.tag) {
|
||||||
|
.hash_jni_class => .jni_class,
|
||||||
|
.hash_jni_interface => .jni_interface,
|
||||||
|
.hash_objc_class => .objc_class,
|
||||||
|
.hash_objc_protocol => .objc_protocol,
|
||||||
|
.hash_swift_class => .swift_class,
|
||||||
|
.hash_swift_struct => .swift_struct,
|
||||||
|
.hash_swift_protocol => .swift_protocol,
|
||||||
|
else => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseForeignClassDecl(self: *Parser, name: []const u8, start_pos: u32, runtime: ast.ForeignRuntime) anyerror!*Node {
|
||||||
|
self.advance(); // skip directive token
|
||||||
|
|
||||||
try self.expect(.l_paren);
|
try self.expect(.l_paren);
|
||||||
if (self.current.tag != .string_literal) {
|
if (self.current.tag != .string_literal) {
|
||||||
return self.fail("expected string literal Java class path after '#jni_class('");
|
return self.fail("expected string literal foreign-type path after directive");
|
||||||
}
|
}
|
||||||
const raw = self.tokenSlice(self.current);
|
const raw = self.tokenSlice(self.current);
|
||||||
const java_path = raw[1 .. raw.len - 1];
|
const foreign_path = raw[1 .. raw.len - 1];
|
||||||
self.advance();
|
self.advance();
|
||||||
try self.expect(.r_paren);
|
try self.expect(.r_paren);
|
||||||
|
|
||||||
try self.expect(.l_brace);
|
try self.expect(.l_brace);
|
||||||
|
|
||||||
var members = std.ArrayList(ast.JniClassMember).empty;
|
var members = std.ArrayList(ast.ForeignClassMember).empty;
|
||||||
while (self.current.tag != .r_brace and self.current.tag != .eof) {
|
while (self.current.tag != .r_brace and self.current.tag != .eof) {
|
||||||
// #extends Alias; or #implements Alias;
|
// #extends Alias; or #implements Alias;
|
||||||
if (self.current.tag == .hash_extends or self.current.tag == .hash_implements) {
|
if (self.current.tag == .hash_extends or self.current.tag == .hash_implements) {
|
||||||
@@ -1143,14 +1157,15 @@ pub const Parser = struct {
|
|||||||
.param_names = try param_names.toOwnedSlice(self.allocator),
|
.param_names = try param_names.toOwnedSlice(self.allocator),
|
||||||
.return_type = return_type,
|
.return_type = return_type,
|
||||||
.is_static = is_static,
|
.is_static = is_static,
|
||||||
.desc_override = desc_override,
|
.jni_descriptor_override = desc_override,
|
||||||
} });
|
} });
|
||||||
}
|
}
|
||||||
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, .{ .foreign_class_decl = .{
|
||||||
.name = name,
|
.name = name,
|
||||||
.java_path = java_path,
|
.foreign_path = foreign_path,
|
||||||
|
.runtime = runtime,
|
||||||
.members = try members.toOwnedSlice(self.allocator),
|
.members = try members.toOwnedSlice(self.allocator),
|
||||||
} });
|
} });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -907,8 +907,8 @@ pub const Analyzer = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.jni_class_decl => |jd| {
|
.foreign_class_decl => |fd| {
|
||||||
try self.addSymbol(jd.name, .type_alias, null, node.span);
|
try self.addSymbol(fd.name, .type_alias, null, node.span);
|
||||||
},
|
},
|
||||||
.impl_block => |ib| {
|
.impl_block => |ib| {
|
||||||
// Each impl block gets its own scope so methods don't conflict across impls
|
// Each impl block gets its own scope so methods don't conflict across impls
|
||||||
@@ -1309,7 +1309,7 @@ pub fn findNodeAtOffset(node: *Node, offset: u32) ?*Node {
|
|||||||
.tuple_type_expr,
|
.tuple_type_expr,
|
||||||
.ufcs_alias,
|
.ufcs_alias,
|
||||||
.closure_type_expr,
|
.closure_type_expr,
|
||||||
.jni_class_decl,
|
.foreign_class_decl,
|
||||||
=> {},
|
=> {},
|
||||||
.struct_decl => |sd| {
|
.struct_decl => |sd| {
|
||||||
for (sd.methods) |method_node| {
|
for (sd.methods) |method_node| {
|
||||||
|
|||||||
@@ -116,8 +116,14 @@ pub const Tag = enum {
|
|||||||
hash_jni_call, // #jni_call(T)(env, target, "name", "(Sig)R", args...)
|
hash_jni_call, // #jni_call(T)(env, target, "name", "(Sig)R", args...)
|
||||||
hash_jni_static_call, // #jni_static_call(T)(class, "name", "(Sig)R", args...)
|
hash_jni_static_call, // #jni_static_call(T)(class, "name", "(Sig)R", args...)
|
||||||
hash_jni_class, // Foo :: #jni_class("java/path/Foo") { ...body... }
|
hash_jni_class, // Foo :: #jni_class("java/path/Foo") { ...body... }
|
||||||
hash_extends, // `#extends Alias;` inside a #jni_class / #objc_class body
|
hash_jni_interface, // Foo :: #jni_interface("java/path/IFoo") { ...body... }
|
||||||
hash_implements, // `#implements Alias;` inside a #jni_class / #objc_class body
|
hash_objc_class, // Foo :: #objc_class("ObjcName") { ...body... }
|
||||||
|
hash_objc_protocol, // Foo :: #objc_protocol("ObjcProto") { ...body... }
|
||||||
|
hash_swift_class, // Foo :: #swift_class("Module.Type") { ...body... }
|
||||||
|
hash_swift_struct, // Foo :: #swift_struct("Module.Type") { ...body... }
|
||||||
|
hash_swift_protocol, // Foo :: #swift_protocol("Module.Proto") { ...body... }
|
||||||
|
hash_extends, // `#extends Alias;` inside a foreign-class body
|
||||||
|
hash_implements, // `#implements Alias;` inside a foreign-class body
|
||||||
hash_jni_method_descriptor, // `#jni_method_descriptor("(Sig)Ret")` per-method JNI descriptor override
|
hash_jni_method_descriptor, // `#jni_method_descriptor("(Sig)Ret")` per-method JNI descriptor override
|
||||||
triple_minus, // ---
|
triple_minus, // ---
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
1
|
0
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
/Users/agra/projects/sx/examples/ffi-jni-class-07-all-runtimes.sx:20:9: error: unexpected token in expression
|
parse-only ok
|
||||||
|
|||||||
Reference in New Issue
Block a user