diff --git a/src/ast.zig b/src/ast.zig index cbeee35..aaa4281 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -93,7 +93,7 @@ pub const Node = struct { protocol_decl: ProtocolDecl, impl_block: ImplBlock, ffi_intrinsic_call: FfiIntrinsicCall, - foreign_class_decl: ForeignClassDecl, + foreign_class_decl: RuntimeClassDecl, jni_env_block: JniEnvBlock, pub fn declName(self: Data) ?[]const u8 { @@ -836,7 +836,7 @@ pub const ProtocolDecl = struct { source_file: ?[]const u8 = null, }; -pub const ForeignRuntime = enum { +pub const RuntimeKind = enum { jni_class, jni_interface, objc_class, @@ -846,7 +846,7 @@ pub const ForeignRuntime = enum { swift_protocol, }; -pub const ForeignMethodDecl = struct { +pub const RuntimeMethodDecl = struct { name: []const u8, params: []const *Node, // type_expr nodes — first is `*Self` for instance methods param_names: []const []const u8, @@ -862,7 +862,7 @@ pub const ForeignMethodDecl = struct { body: ?*Node = null, // sx-side implementation (defined-class only). null = `;`-terminated decl referencing inherited / external method. }; -pub const ForeignFieldDecl = struct { +pub const RuntimeFieldDecl = struct { name: []const u8, field_type: *Node, // type_expr node /// True iff the declaration carries a `#property[(...)]` directive @@ -876,18 +876,18 @@ pub const ForeignFieldDecl = struct { property_modifiers: []const []const u8 = &.{}, }; -pub const ForeignClassMember = union(enum) { - method: ForeignMethodDecl, - field: ForeignFieldDecl, // JNI runtime only (sema-checked in later step) +pub const RuntimeClassMember = union(enum) { + method: RuntimeMethodDecl, + field: RuntimeFieldDecl, // JNI runtime only (sema-checked in later step) extends: []const u8, // sx-side alias name (right of `#extends`) implements: []const u8, // sx-side alias name (right of `#implements`) }; -pub const ForeignClassDecl = struct { +pub const RuntimeClassDecl = struct { name: []const u8, // sx-side alias (left of `::`) foreign_path: []const u8, // directive arg: "java/path/Foo" / "NSString" / "Foundation.URL" - runtime: ForeignRuntime, - members: []const ForeignClassMember = &.{}, + runtime: RuntimeKind, + members: []const RuntimeClassMember = &.{}, is_foreign: bool = false, // `#foreign #...` prefix — class is provided by the foreign runtime; we only reference it is_main: bool = false, // `#jni_main` / `#objc_main` — class is the launchable entry (Activity / UIApplicationDelegate / ...) /// True when the sx-side alias NAME was a backtick raw identifier — exempt diff --git a/src/imports.zig b/src/imports.zig index c9215c0..8d353c2 100644 --- a/src/imports.zig +++ b/src/imports.zig @@ -463,7 +463,7 @@ pub const RawDeclRef = union(enum) { union_decl: *const ast.UnionDecl, error_set_decl: *const ast.ErrorSetDecl, protocol_decl: *const ast.ProtocolDecl, - foreign_class_decl: *const ast.ForeignClassDecl, + foreign_class_decl: *const ast.RuntimeClassDecl, namespace_decl: *const ast.NamespaceDecl, }; @@ -853,7 +853,7 @@ fn stampStructMethodSources(sd: ast.StructDecl, file_path: []const u8) void { /// Stamp the defining module path onto every bodied method of an sx-defined /// foreign class, so the method's sx body lowers in the class's own module. -fn stampForeignClassMethodSources(fcd: ast.ForeignClassDecl, file_path: []const u8) void { +fn stampForeignClassMethodSources(fcd: ast.RuntimeClassDecl, file_path: []const u8) void { for (fcd.members) |m| { if (m == .method) { if (m.method.body) |b| b.source_file = file_path; diff --git a/src/ir/calls.test.zig b/src/ir/calls.test.zig index 0ef9856..3a27612 100644 --- a/src/ir/calls.test.zig +++ b/src/ir/calls.test.zig @@ -355,11 +355,11 @@ test "plan: foreign-class instance vs static dispatch" { var l = Lowering.init(&module); const cr = CallResolver{ .l = &l }; - const members = [_]ast.ForeignClassMember{ + const members = [_]ast.RuntimeClassMember{ .{ .method = .{ .name = "length", .params = &.{}, .param_names = &.{}, .return_type = typeExpr(alloc, "i64"), .is_static = false } }, .{ .method = .{ .name = "stringWithUTF8String", .params = &.{}, .param_names = &.{}, .return_type = typeExpr(alloc, "i64"), .is_static = true } }, }; - var fcd = ast.ForeignClassDecl{ .name = "NSString", .foreign_path = "NSString", .runtime = .objc_class, .members = &members }; + var fcd = ast.RuntimeClassDecl{ .name = "NSString", .foreign_path = "NSString", .runtime = .objc_class, .members = &members }; l.program_index.foreign_class_map.put("NSString", &fcd) catch unreachable; _ = module.types.intern(.{ .@"struct" = .{ .name = module.types.internString("NSString"), .fields = &.{} } }); diff --git a/src/ir/ffi_objc.zig b/src/ir/ffi_objc.zig index 9912ce6..c02a665 100644 --- a/src/ir/ffi_objc.zig +++ b/src/ir/ffi_objc.zig @@ -64,7 +64,7 @@ const ObjcPropertyKind = enum { pub const ObjcLowering = struct { l: *Lowering, - pub fn deriveObjcSelector(self: ObjcLowering, method: ast.ForeignMethodDecl, arity: usize) struct { sel: []const u8, keyword_count: usize, is_override: bool } { + pub fn deriveObjcSelector(self: ObjcLowering, method: ast.RuntimeMethodDecl, arity: usize) struct { sel: []const u8, keyword_count: usize, is_override: bool } { if (method.selector_override) |sel| { var colons: usize = 0; for (sel) |ch| { @@ -263,7 +263,7 @@ pub const ObjcLowering = struct { /// Foreign-class members other than `.field` are ignored here — /// methods / `#extends` / `#implements` don't contribute to the /// state layout. - pub fn objcDefinedStateStructType(self: ObjcLowering, fcd: *const ast.ForeignClassDecl) TypeId { + pub fn objcDefinedStateStructType(self: ObjcLowering, fcd: *const ast.RuntimeClassDecl) TypeId { const state_name = std.fmt.allocPrint(self.l.alloc, "__{s}State", .{fcd.name}) catch unreachable; defer self.l.alloc.free(state_name); // internString copies; the temp isn't needed after. const name_id = self.l.module.types.internString(state_name); @@ -329,7 +329,7 @@ pub const ObjcLowering = struct { /// - `weak` on a non-object field type → diagnostic /// - `strong` (explicit or defaulted) on `*void` (ambiguous: Obj-C /// object vs raw memory) → require explicit modifier - pub fn objcPropertyKind(self: ObjcLowering, field: ast.ForeignFieldDecl) ObjcPropertyKind { + pub fn objcPropertyKind(self: ObjcLowering, field: ast.RuntimeFieldDecl) ObjcPropertyKind { // Survey the modifier list. var has_strong = false; var has_weak = false; diff --git a/src/ir/jni_descriptor.test.zig b/src/ir/jni_descriptor.test.zig index b265764..e42a823 100644 --- a/src/ir/jni_descriptor.test.zig +++ b/src/ir/jni_descriptor.test.zig @@ -187,7 +187,7 @@ test "deriveMethod respects #jni_method_descriptor override verbatim" { const self_ptr = try makePointer(aa, self_te); const ret = try makeTypeExpr(aa, "i32"); - const method: ast.ForeignMethodDecl = .{ + const method: ast.RuntimeMethodDecl = .{ .name = "weirdMethod", .params = &.{self_ptr}, .param_names = &.{"self"}, @@ -214,7 +214,7 @@ test "deriveMethod override bypasses unresolvable cross-class refs" { const unknown = try makeTypeExpr(aa, "UnknownClass"); const unknown_ptr = try makePointer(aa, unknown); - const method: ast.ForeignMethodDecl = .{ + const method: ast.RuntimeMethodDecl = .{ .name = "weirdMethod", .params = &.{self_ptr}, .param_names = &.{"self"}, @@ -245,7 +245,7 @@ test "deriveMethod chains *Foo returns and params" { const view_te = try makeTypeExpr(aa, "View"); const view_ptr = try makePointer(aa, view_te); - const method: ast.ForeignMethodDecl = .{ + const method: ast.RuntimeMethodDecl = .{ .name = "getDecorView", .params = &.{self_ptr}, .param_names = &.{"self"}, @@ -271,7 +271,7 @@ test "deriveMethod skips implicit self for instance methods" { const self_ptr = try makePointer(aa, self_te); const ret = try makeTypeExpr(aa, "i32"); - const method: ast.ForeignMethodDecl = .{ + const method: ast.RuntimeMethodDecl = .{ .name = "getId", .params = &.{self_ptr}, .param_names = &.{"self"}, @@ -293,7 +293,7 @@ test "deriveMethod for static method emits all params" { const n_ty = try makeTypeExpr(aa, "i32"); const ret = try makeTypeExpr(aa, "i32"); - const method: ast.ForeignMethodDecl = .{ + const method: ast.RuntimeMethodDecl = .{ .name = "abs", .params = &.{n_ty}, .param_names = &.{"n"}, @@ -316,7 +316,7 @@ test "deriveMethod with multiple primitive params and void return" { const self_ptr = try makePointer(aa, self_te); const s = try makeTypeExpr(aa, "i32"); - const method: ast.ForeignMethodDecl = .{ + const method: ast.RuntimeMethodDecl = .{ .name = "setBounds", .params = &.{ self_ptr, s, s, s, s }, .param_names = &.{ "self", "x", "y", "w", "h" }, @@ -341,7 +341,7 @@ test "deriveMethod with slice param" { const src_slice = try makeSlice(aa, i8_te); const ret = try makeTypeExpr(aa, "i32"); - const method: ast.ForeignMethodDecl = .{ + const method: ast.RuntimeMethodDecl = .{ .name = "copy", .params = &.{ self_ptr, src_slice }, .param_names = &.{ "self", "src" }, diff --git a/src/ir/jni_descriptor.zig b/src/ir/jni_descriptor.zig index 42e652f..4358740 100644 --- a/src/ir/jni_descriptor.zig +++ b/src/ir/jni_descriptor.zig @@ -103,13 +103,13 @@ pub fn writeType( } } -/// Derives the full `(args)ret` method descriptor for a `ForeignMethodDecl`. +/// Derives the full `(args)ret` method descriptor for a `RuntimeMethodDecl`. /// The first param is skipped when `is_static == false` (it's the implicit /// `self: *Self` receiver, which doesn't appear in the JNI descriptor). pub fn deriveMethod( allocator: std.mem.Allocator, ctx: Context, - method: ast.ForeignMethodDecl, + method: ast.RuntimeMethodDecl, ) DeriveError![]u8 { // `#jni_method_descriptor("(Sig)Ret")` short-circuits derivation // entirely. Allocate a copy so the caller has uniform ownership diff --git a/src/ir/jni_java_emit.test.zig b/src/ir/jni_java_emit.test.zig index f912f50..894a471 100644 --- a/src/ir/jni_java_emit.test.zig +++ b/src/ir/jni_java_emit.test.zig @@ -1,5 +1,5 @@ // Tests for jni_java_emit.zig — #jni_main pipeline slice 1. -// Locks in the Java source emitted from `ForeignClassDecl` AST nodes: +// Locks in the Java source emitted from `RuntimeClassDecl` AST nodes: // package split, class header, @Override delegate pattern, primitive // type mapping, cross-class refs through the foreign_class registry. @@ -40,7 +40,7 @@ fn makeBodyMarker(allocator: std.mem.Allocator) !*Node { test "rejects non-main decl" { const a = std.testing.allocator; - const fcd: ast.ForeignClassDecl = .{ + const fcd: ast.RuntimeClassDecl = .{ .name = "Foo", .foreign_path = "co/example/Foo", .runtime = .jni_class, @@ -64,14 +64,14 @@ test "void onCreate(Bundle) with default Activity superclass" { defer registry.deinit(); try registry.put("Bundle", "android/os/Bundle"); - const member: ast.ForeignClassMember = .{ .method = .{ + const member: ast.RuntimeClassMember = .{ .method = .{ .name = "onCreate", .params = &.{ self_ty, bundle_ty }, .param_names = &.{ "self", "b" }, .return_type = null, .body = body, } }; - const fcd: ast.ForeignClassDecl = .{ + const fcd: ast.RuntimeClassDecl = .{ .name = "SxApp", .foreign_path = "co/swipelab/sx_runtime/SxNativeActivity", .runtime = .jni_class, @@ -107,14 +107,14 @@ test "primitive params" { const bool_ty = try makeTypeExpr(aa, "bool"); const body = try makeBodyMarker(aa); - const member: ast.ForeignClassMember = .{ .method = .{ + const member: ast.RuntimeClassMember = .{ .method = .{ .name = "onWindowFocusChanged", .params = &.{ self_ty, bool_ty }, .param_names = &.{ "self", "hasFocus" }, .return_type = null, .body = body, } }; - const fcd: ast.ForeignClassDecl = .{ + const fcd: ast.RuntimeClassDecl = .{ .name = "Sx", .foreign_path = "co/sample/Sx", .runtime = .jni_class, @@ -140,14 +140,14 @@ test "declaration-only methods are skipped" { const body = try makeBodyMarker(aa); // One bodied (override), one declaration-only (calls inherited). - const bodied: ast.ForeignClassMember = .{ .method = .{ + const bodied: ast.RuntimeClassMember = .{ .method = .{ .name = "onCreate", .params = &.{self_ty}, .param_names = &.{"self"}, .return_type = null, .body = body, } }; - const decl_only: ast.ForeignClassMember = .{ .method = .{ + const decl_only: ast.RuntimeClassMember = .{ .method = .{ .name = "finish", .params = &.{self_ty}, .param_names = &.{"self"}, @@ -155,7 +155,7 @@ test "declaration-only methods are skipped" { .body = null, // sx-side just *calls* this; Java's NativeActivity.finish() provides it } }; - const fcd: ast.ForeignClassDecl = .{ + const fcd: ast.RuntimeClassDecl = .{ .name = "Sx", .foreign_path = "co/example/Sx", .runtime = .jni_class, @@ -179,8 +179,8 @@ test "#extends Alias resolves through class registry" { const self_ty = try makePointer(aa, try makeTypeExpr(aa, "Self")); const body = try makeBodyMarker(aa); - const extends_member: ast.ForeignClassMember = .{ .extends = "MyParent" }; - const method_member: ast.ForeignClassMember = .{ .method = .{ + const extends_member: ast.RuntimeClassMember = .{ .extends = "MyParent" }; + const method_member: ast.RuntimeClassMember = .{ .method = .{ .name = "onCreate", .params = &.{self_ty}, .param_names = &.{"self"}, @@ -192,7 +192,7 @@ test "#extends Alias resolves through class registry" { defer registry.deinit(); try registry.put("MyParent", "co/example/MyParentActivity"); - const fcd: ast.ForeignClassDecl = .{ + const fcd: ast.RuntimeClassDecl = .{ .name = "Sx", .foreign_path = "co/example/Sx", .runtime = .jni_class, @@ -213,14 +213,14 @@ test "default-package class (no slash in foreign_path)" { const self_ty = try makePointer(aa, try makeTypeExpr(aa, "Self")); const body = try makeBodyMarker(aa); - const member: ast.ForeignClassMember = .{ .method = .{ + const member: ast.RuntimeClassMember = .{ .method = .{ .name = "onCreate", .params = &.{self_ty}, .param_names = &.{"self"}, .return_type = null, .body = body, } }; - const fcd: ast.ForeignClassDecl = .{ + const fcd: ast.RuntimeClassDecl = .{ .name = "Sx", .foreign_path = "SxNoPackage", .runtime = .jni_class, @@ -243,7 +243,7 @@ test "lib_name renders System.loadLibrary static init block" { const self_ty = try makePointer(aa, try makeTypeExpr(aa, "Self")); const body = try makeBodyMarker(aa); - const method: ast.ForeignClassMember = .{ .method = .{ + const method: ast.RuntimeClassMember = .{ .method = .{ .name = "onCreate", .params = &.{self_ty}, .param_names = &.{"self"}, @@ -251,7 +251,7 @@ test "lib_name renders System.loadLibrary static init block" { .body = body, } }; - const fcd: ast.ForeignClassDecl = .{ + const fcd: ast.RuntimeClassDecl = .{ .name = "SxApp", .foreign_path = "co/example/SxApp", .runtime = .jni_class, @@ -280,9 +280,9 @@ test "field declarations render as private Java fields" { const self_ty = try makePointer(aa, try makeTypeExpr(aa, "Self")); const body = try makeBodyMarker(aa); - const view_field: ast.ForeignClassMember = .{ .field = .{ .name = "view", .field_type = surface_view_ty } }; - const w_field: ast.ForeignClassMember = .{ .field = .{ .name = "viewport_w", .field_type = int_ty } }; - const method: ast.ForeignClassMember = .{ .method = .{ + const view_field: ast.RuntimeClassMember = .{ .field = .{ .name = "view", .field_type = surface_view_ty } }; + const w_field: ast.RuntimeClassMember = .{ .field = .{ .name = "viewport_w", .field_type = int_ty } }; + const method: ast.RuntimeClassMember = .{ .method = .{ .name = "onCreate", .params = &.{self_ty}, .param_names = &.{"self"}, @@ -294,7 +294,7 @@ test "field declarations render as private Java fields" { defer registry.deinit(); try registry.put("SurfaceView", "android/view/SurfaceView"); - const fcd: ast.ForeignClassDecl = .{ + const fcd: ast.RuntimeClassDecl = .{ .name = "SxApp", .foreign_path = "co/example/SxApp", .runtime = .jni_class, @@ -318,9 +318,9 @@ test "#implements clauses on the class header" { const body = try makeBodyMarker(aa); // Two interfaces: one resolvable via the registry, one passed through verbatim. - const impl_a: ast.ForeignClassMember = .{ .implements = "Callback" }; - const impl_b: ast.ForeignClassMember = .{ .implements = "java.lang.Runnable" }; - const method: ast.ForeignClassMember = .{ .method = .{ + const impl_a: ast.RuntimeClassMember = .{ .implements = "Callback" }; + const impl_b: ast.RuntimeClassMember = .{ .implements = "java.lang.Runnable" }; + const method: ast.RuntimeClassMember = .{ .method = .{ .name = "onCreate", .params = &.{self_ty}, .param_names = &.{"self"}, @@ -332,7 +332,7 @@ test "#implements clauses on the class header" { defer registry.deinit(); try registry.put("Callback", "android/view/SurfaceHolder$Callback"); - const fcd: ast.ForeignClassDecl = .{ + const fcd: ast.RuntimeClassDecl = .{ .name = "SxApp", .foreign_path = "co/example/SxApp", .runtime = .jni_class, diff --git a/src/ir/jni_java_emit.zig b/src/ir/jni_java_emit.zig index 487b198..41f4f4f 100644 --- a/src/ir/jni_java_emit.zig +++ b/src/ir/jni_java_emit.zig @@ -1,7 +1,7 @@ // Java source emission for `#jni_main #jni_class("...") { ... }` decls // (FFI plan, #jni_main pipeline slice 1). // -// Given a `ForeignClassDecl` whose `is_main` flag is set, emit a `.java` +// Given a `RuntimeClassDecl` whose `is_main` flag is set, emit a `.java` // source file that: // // - declares a `public class` at the foreign_path's package + simple @@ -83,7 +83,7 @@ pub fn injectLoadLibrary(allocator: Allocator, java_source: []const u8, lib_name /// heap-allocated through `allocator`; caller owns it. pub fn emitJavaSource( allocator: Allocator, - fcd: *const ast.ForeignClassDecl, + fcd: *const ast.RuntimeClassDecl, opts: Options, ) EmitError![]u8 { if (!fcd.is_main) return EmitError.NotAJniMainClass; @@ -221,7 +221,7 @@ fn foreignPathToJavaName(allocator: Allocator, slash_path: []const u8) EmitError fn emitOverride( allocator: Allocator, buf: *std.ArrayList(u8), - md: ast.ForeignMethodDecl, + md: ast.RuntimeMethodDecl, opts: Options, ) EmitError!void { // The Java @Override only calls the native delegate. `super.(...)` @@ -253,7 +253,7 @@ fn emitOverride( fn emitNativeDecl( allocator: Allocator, buf: *std.ArrayList(u8), - md: ast.ForeignMethodDecl, + md: ast.RuntimeMethodDecl, opts: Options, ) EmitError!void { try buf.appendSlice(allocator, " private native "); @@ -281,7 +281,7 @@ fn emitJavaReturnType( fn emitJavaParamList( allocator: Allocator, buf: *std.ArrayList(u8), - md: ast.ForeignMethodDecl, + md: ast.RuntimeMethodDecl, opts: Options, ) EmitError!void { const start: usize = if (md.is_static) 0 else 1; // skip self @@ -296,7 +296,7 @@ fn emitJavaParamList( fn emitJavaArgList( allocator: Allocator, buf: *std.ArrayList(u8), - md: ast.ForeignMethodDecl, + md: ast.RuntimeMethodDecl, ) EmitError!void { const start: usize = if (md.is_static) 0 else 1; for (md.param_names[start..], 0..) |name, i| { diff --git a/src/ir/lower.test.zig b/src/ir/lower.test.zig index b2dacfe..003e91a 100644 --- a/src/ir/lower.test.zig +++ b/src/ir/lower.test.zig @@ -380,11 +380,11 @@ test "lower: objcDefinedStateStructType collects user-declared fields" { defer alloc.destroy(ticks_type); ticks_type.* = .{ .span = span, .data = .{ .type_expr = .{ .name = "i64", .is_generic = false } } }; - const members = [_]ast.ForeignClassMember{ + const members = [_]ast.RuntimeClassMember{ .{ .field = .{ .name = "counter", .field_type = counter_type } }, .{ .field = .{ .name = "ticks", .field_type = ticks_type } }, }; - const fcd = ast.ForeignClassDecl{ + const fcd = ast.RuntimeClassDecl{ .name = "SxFoo", .foreign_path = "SxFoo", .runtime = .objc_class, @@ -416,7 +416,7 @@ test "lower: objcDefinedStateStructType handles empty field set" { defer module.deinit(); var lowering = Lowering.init(&module); - const fcd = ast.ForeignClassDecl{ + const fcd = ast.RuntimeClassDecl{ .name = "SxEmpty", .foreign_path = "SxEmpty", .runtime = .objc_class, @@ -443,12 +443,12 @@ test "lower: objcDefinedStateStructType skips non-field members" { defer alloc.destroy(counter_type); counter_type.* = .{ .span = span, .data = .{ .type_expr = .{ .name = "i32", .is_generic = false } } }; - const members = [_]ast.ForeignClassMember{ + const members = [_]ast.RuntimeClassMember{ .{ .extends = "NSObject" }, .{ .field = .{ .name = "counter", .field_type = counter_type } }, .{ .implements = "UIApplicationDelegate" }, }; - const fcd = ast.ForeignClassDecl{ + const fcd = ast.RuntimeClassDecl{ .name = "SxMixed", .foreign_path = "SxMixed", .runtime = .objc_class, @@ -476,7 +476,7 @@ test "lower: objcTypeEncodingFromSignature emits @ for Obj-C class pointers" { const ns_name = module.types.internString("NSString"); const ns_struct = module.types.intern(.{ .@"struct" = .{ .name = ns_name, .fields = &.{} } }); const ns_ptr = module.types.ptrTo(ns_struct); - var ns_fcd = ast.ForeignClassDecl{ + var ns_fcd = ast.RuntimeClassDecl{ .name = "NSString", .foreign_path = "NSString", .runtime = .objc_class, @@ -509,7 +509,7 @@ test "lower: objcTypeEncodingFromSignature unwraps optional to wire type" { const ns_name = module.types.internString("NSString"); const ns_struct = module.types.intern(.{ .@"struct" = .{ .name = ns_name, .fields = &.{} } }); const ns_ptr = module.types.ptrTo(ns_struct); - var ns_fcd = ast.ForeignClassDecl{ + var ns_fcd = ast.RuntimeClassDecl{ .name = "NSString", .foreign_path = "NSString", .runtime = .objc_class, @@ -627,7 +627,7 @@ test "lower: objcTypeEncodingFromSignature emits nested structs (CGRect)" { // Lock selector derivation, property-kind classification, and Obj-C // class-pointer recognition before they move to `ffi_objc.zig`. -fn objcMethod(name: []const u8) ast.ForeignMethodDecl { +fn objcMethod(name: []const u8) ast.RuntimeMethodDecl { return .{ .name = name, .params = &.{}, .param_names = &.{}, .return_type = null }; } @@ -678,7 +678,7 @@ test "lower: isObjcClassPointer recognises pointer-to-foreign-Obj-C-class" { const ns_name = module.types.internString("NSString"); const ns_struct = module.types.intern(.{ .@"struct" = .{ .name = ns_name, .fields = &.{} } }); const ns_ptr = module.types.ptrTo(ns_struct); - var ns_fcd = ast.ForeignClassDecl{ + var ns_fcd = ast.RuntimeClassDecl{ .name = "NSString", .foreign_path = "NSString", .runtime = .objc_class, @@ -694,7 +694,7 @@ test "lower: isObjcClassPointer recognises pointer-to-foreign-Obj-C-class" { const proto_name = module.types.internString("NSCopying"); const proto_struct = module.types.intern(.{ .@"struct" = .{ .name = proto_name, .fields = &.{} } }); const proto_ptr = module.types.ptrTo(proto_struct); - var proto_fcd = ast.ForeignClassDecl{ + var proto_fcd = ast.RuntimeClassDecl{ .name = "NSCopying", .foreign_path = "NSCopying", .runtime = .objc_protocol, @@ -726,7 +726,7 @@ test "lower: objcPropertyKind defaults + explicit ARC modifiers" { // Register NSString so `*NSString` resolves to an object pointer. const ns_name = module.types.internString("NSString"); _ = module.types.intern(.{ .@"struct" = .{ .name = ns_name, .fields = &.{} } }); - var ns_fcd = ast.ForeignClassDecl{ + var ns_fcd = ast.RuntimeClassDecl{ .name = "NSString", .foreign_path = "NSString", .runtime = .objc_class, @@ -737,21 +737,21 @@ test "lower: objcPropertyKind defaults + explicit ARC modifiers" { try lowering.program_index.foreign_class_map.put("NSString", &ns_fcd); // Primitive field, no modifiers → assign (the non-object default). - const prim = ast.ForeignFieldDecl{ .name = "count", .field_type = typeKeyword(alloc, "i32"), .is_property = true }; + const prim = ast.RuntimeFieldDecl{ .name = "count", .field_type = typeKeyword(alloc, "i32"), .is_property = true }; defer alloc.destroy(prim.field_type); try std.testing.expect(lowering.objc().objcPropertyKind(prim) == .assign); // Object-pointer field, no modifiers → strong (the object default). const obj_ty = typeKeyword(alloc, "*NSString"); defer alloc.destroy(obj_ty); - const obj_default = ast.ForeignFieldDecl{ .name = "title", .field_type = obj_ty, .is_property = true }; + const obj_default = ast.RuntimeFieldDecl{ .name = "title", .field_type = obj_ty, .is_property = true }; try std.testing.expect(lowering.objc().objcPropertyKind(obj_default) == .strong); // Protocol-pointer field → also strong by default (same object-pointer // predicate accepts .objc_protocol). const proto_name = module.types.internString("NSCoding"); _ = module.types.intern(.{ .@"struct" = .{ .name = proto_name, .fields = &.{} } }); - var proto_fcd = ast.ForeignClassDecl{ + var proto_fcd = ast.RuntimeClassDecl{ .name = "NSCoding", .foreign_path = "NSCoding", .runtime = .objc_protocol, @@ -762,7 +762,7 @@ test "lower: objcPropertyKind defaults + explicit ARC modifiers" { try lowering.program_index.foreign_class_map.put("NSCoding", &proto_fcd); const proto_ty = typeKeyword(alloc, "*NSCoding"); defer alloc.destroy(proto_ty); - const proto_default = ast.ForeignFieldDecl{ .name = "coder", .field_type = proto_ty, .is_property = true }; + const proto_default = ast.RuntimeFieldDecl{ .name = "coder", .field_type = proto_ty, .is_property = true }; try std.testing.expect(lowering.objc().objcPropertyKind(proto_default) == .strong); // Explicit modifiers on an object pointer win over the default. diff --git a/src/ir/lower.zig b/src/ir/lower.zig index 3c47556..86da672 100644 --- a/src/ir/lower.zig +++ b/src/ir/lower.zig @@ -275,8 +275,8 @@ pub const Lowering = struct { trace_clear_fid: ?FuncId = null, // extern `sx_trace_clear` needs_trace_runtime: bool = false, // set when lowering emits a trace push/clear; signals Compilation to auto-link sx_trace.c chain_fail_target: ?ChainFailTarget = null, // ERR E2.4: when set, a failable `or` chain routes its TOTAL failure here (an absorbing consumer like `catch`) instead of propagating to the function - current_foreign_class: ?*const ast.ForeignClassDecl = null, // set while lowering a `#jni_main` (or any sx-defined `#jni_class`) bodied method — `super.method(args)` dispatch resolves the parent class against this fcd's `#extends` - current_foreign_method: ?ast.ForeignMethodDecl = null, // the specific method whose body is being lowered; `super.(...)` reuses its signature + current_foreign_class: ?*const ast.RuntimeClassDecl = null, // set while lowering a `#jni_main` (or any sx-defined `#jni_class`) bodied method — `super.method(args)` dispatch resolves the parent class against this fcd's `#extends` + current_foreign_method: ?ast.RuntimeMethodDecl = null, // the specific method whose body is being lowered; `super.(...)` reuses its signature type_bindings: ?std.StringHashMap(TypeId) = null, // generic type param bindings ($T → concrete TypeId) current_match_tags: ?[]const u64 = null, // type tags for current match arm (for runtime dispatch) force_block_value: bool = false, // set by lowerBlockValue to extract if-else values diff --git a/src/ir/lower/ffi.zig b/src/ir/lower/ffi.zig index 05eb1ee..20d29c2 100644 --- a/src/ir/lower/ffi.zig +++ b/src/ir/lower/ffi.zig @@ -235,7 +235,7 @@ pub fn lowerJniCall(self: *Lowering, fic: *const ast.FfiIntrinsicCall) Ref { /// Phase 3/4 and currently surface a clear diagnostic. pub fn lowerForeignMethodCall( self: *Lowering, - fcd: *const ast.ForeignClassDecl, + fcd: *const ast.RuntimeClassDecl, method_name: []const u8, target: Ref, method_args: []const Ref, @@ -359,7 +359,7 @@ pub fn lowerForeignMethodCall( /// fictitious `Self` struct and the next dispatch lookup fails. pub fn resolveForeignClassMemberType( self: *Lowering, - fcd: *const ast.ForeignClassDecl, + fcd: *const ast.RuntimeClassDecl, type_node: *const ast.Node, ) TypeId { if (type_node.data == .type_expr and std.mem.eql(u8, type_node.data.type_expr.name, "Self")) { @@ -376,14 +376,14 @@ pub fn resolveForeignClassMemberType( pub fn resolveForeignMethodReturnType( self: *Lowering, - fcd: *const ast.ForeignClassDecl, - method: ast.ForeignMethodDecl, + fcd: *const ast.RuntimeClassDecl, + method: ast.RuntimeMethodDecl, ) TypeId { const rt = method.return_type orelse return .void; return self.resolveForeignClassMemberType(fcd, rt); } -pub fn foreignClassStructType(self: *Lowering, fcd: *const ast.ForeignClassDecl) TypeId { +pub fn foreignClassStructType(self: *Lowering, fcd: *const ast.RuntimeClassDecl) TypeId { const name_id = self.module.types.internString(fcd.name); if (self.module.types.findByName(name_id)) |existing| return existing; return self.module.types.intern(.{ .@"struct" = .{ .name = name_id, .fields = &.{} } }); @@ -396,8 +396,8 @@ pub fn foreignClassStructType(self: *Lowering, fcd: *const ast.ForeignClassDecl) /// sharing the cached-SEL slot path with explicit `#objc_call`. pub fn lowerObjcMethodCall( self: *Lowering, - fcd: *const ast.ForeignClassDecl, - method: ast.ForeignMethodDecl, + fcd: *const ast.RuntimeClassDecl, + method: ast.RuntimeMethodDecl, target: Ref, method_args: []const Ref, span: ast.Span, @@ -460,8 +460,8 @@ pub fn lowerObjcMethodCall( /// selector mangling as instance methods (Phase 3.0). pub fn lowerObjcStaticCall( self: *Lowering, - fcd: *const ast.ForeignClassDecl, - method: ast.ForeignMethodDecl, + fcd: *const ast.RuntimeClassDecl, + method: ast.RuntimeMethodDecl, method_args: []const Ref, span: ast.Span, ) Ref { @@ -570,8 +570,8 @@ pub fn lowerObjcStaticCall( /// that need to instantiate Android classes (SurfaceView, etc.). pub fn lowerForeignStaticCall( self: *Lowering, - fcd: *const ast.ForeignClassDecl, - method: ast.ForeignMethodDecl, + fcd: *const ast.RuntimeClassDecl, + method: ast.RuntimeMethodDecl, method_args: []const Ref, span: ast.Span, ) Ref { @@ -609,7 +609,7 @@ pub fn lowerForeignStaticCall( // constructor returns void; the new jobject comes back from // `NewObject` itself). Patch the AST by overriding return_type // to null during derivation. - const m_for_desc: ast.ForeignMethodDecl = .{ + const m_for_desc: ast.RuntimeMethodDecl = .{ .name = method.name, .params = method.params, .param_names = method.param_names, @@ -703,7 +703,7 @@ pub fn lowerSuperCall( // enclosing method's descriptor; cross-method super calls require // the parent class to be declared via `#foreign #jni_class`. var descriptor: []const u8 = ""; - var resolved_method: ?ast.ForeignMethodDecl = null; + var resolved_method: ?ast.RuntimeMethodDecl = null; if (self.current_foreign_method) |em| { if (std.mem.eql(u8, em.name, method_name)) { resolved_method = em; @@ -792,7 +792,7 @@ pub fn lowerSuperCall( /// under qualified names `.`. Lazy lowering /// then handles the body via the standard path; `*Self` is /// substituted to `*State` during body lowering (M1.2 A.2b). -pub fn registerForeignClassDecl(self: *Lowering, fcd: *const ast.ForeignClassDecl) void { +pub fn registerForeignClassDecl(self: *Lowering, fcd: *const ast.RuntimeClassDecl) void { self.program_index.foreign_class_map.put(fcd.name, fcd) catch {}; if (!fcd.is_foreign and fcd.runtime == .objc_class) { if (self.module.lookupObjcDefinedClass(fcd.name) == null) { @@ -825,7 +825,7 @@ pub fn registerForeignClassDecl(self: *Lowering, fcd: *const ast.ForeignClassDec /// foreign_path; aliases for OTHER sx-defined classes use the /// alias name directly (which equals the Obj-C class name for /// sx-defined classes). -pub fn resolveObjcParentName(self: *Lowering, fcd: *const ast.ForeignClassDecl) []const u8 { +pub fn resolveObjcParentName(self: *Lowering, fcd: *const ast.RuntimeClassDecl) []const u8 { for (fcd.members) |m| switch (m) { .extends => |alias| { if (self.program_index.foreign_class_map.get(alias)) |parent_fcd| { @@ -875,14 +875,14 @@ pub fn declareObjcDefinedClassGlobal(self: *Lowering, class_name: []const u8) vo } /// For each bodied instance method on an sx-defined `#objc_class`, -/// synthesize an `FnDecl` from the `ForeignMethodDecl`, register it +/// synthesize an `FnDecl` from the `RuntimeMethodDecl`, register it /// in `fn_ast_map` under `.`, declare the IR /// function, AND collect per-method registration data (selector /// mangling + type encoding + IMP symbol name) into the class's /// cache entry so emit_llvm can wire up `class_addMethod` calls /// (M1.2 A.4b.iii). Bodyless declarations are skipped — they /// reference inherited / external methods, not sx-side bodies. -pub fn registerObjcDefinedClassMethods(self: *Lowering, fcd: *const ast.ForeignClassDecl) void { +pub fn registerObjcDefinedClassMethods(self: *Lowering, fcd: *const ast.RuntimeClassDecl) void { // Set current_foreign_class so `*Self` substitutions in // declareFunction's type resolution find the state struct. const saved = self.current_foreign_class; @@ -942,11 +942,11 @@ pub fn registerObjcDefinedClassMethods(self: *Lowering, fcd: *const ast.ForeignC } /// Build an `FnDecl` whose params are zipped from the -/// `ForeignMethodDecl.params` (type nodes) and `param_names`. Used +/// `RuntimeMethodDecl.params` (type nodes) and `param_names`. Used /// to feed sx-defined class methods through the standard /// fn-lowering pipeline. Allocator-owned; lives for the duration /// of the Lowering pass. -pub fn synthesizeFnDeclFromObjcMethod(self: *Lowering, method: ast.ForeignMethodDecl, body: *ast.Node) ?*ast.FnDecl { +pub fn synthesizeFnDeclFromObjcMethod(self: *Lowering, method: ast.RuntimeMethodDecl, body: *ast.Node) ?*ast.FnDecl { if (method.params.len != method.param_names.len) return null; var params = std.ArrayList(ast.Param).empty; for (method.params, method.param_names) |type_node, p_name| { @@ -968,10 +968,10 @@ pub fn synthesizeFnDeclFromObjcMethod(self: *Lowering, method: ast.ForeignMethod /// If `name` matches an sx-defined `#objc_class`'s qualified-method /// pattern (`.`), return the class's -/// ForeignClassDecl. Used by `lowerFunction` to set +/// RuntimeClassDecl. Used by `lowerFunction` to set /// `current_foreign_class` so `*Self` resolves to the state struct /// during body lowering. -pub fn lookupObjcDefinedClassForMethod(self: *Lowering, name: []const u8) ?*const ast.ForeignClassDecl { +pub fn lookupObjcDefinedClassForMethod(self: *Lowering, name: []const u8) ?*const ast.RuntimeClassDecl { const dot = std.mem.indexOf(u8, name, ".") orelse return null; return self.module.lookupObjcDefinedClass(name[0..dot]); } @@ -1053,7 +1053,7 @@ pub fn synthesizeJniMainStubs(self: *Lowering) void { } } -pub fn synthesizeJniMainStub(self: *Lowering, fcd: *const ast.ForeignClassDecl, md: ast.ForeignMethodDecl) void { +pub fn synthesizeJniMainStub(self: *Lowering, fcd: *const ast.RuntimeClassDecl, md: ast.RuntimeMethodDecl) void { const mangled = jni_descriptor.jniMangleNativeName(self.alloc, fcd.foreign_path, md.name) catch return; const name_id = self.module.types.internString(mangled); diff --git a/src/ir/lower/objc_class.zig b/src/ir/lower/objc_class.zig index 4e4a8de..24856c7 100644 --- a/src/ir/lower/objc_class.zig +++ b/src/ir/lower/objc_class.zig @@ -56,8 +56,8 @@ pub fn lowerObjcDefinedClassMethods(self: *Lowering) void { /// If `obj_expr` is typed as a pointer to a foreign Obj-C class /// and that class (or any of its `#extends` ancestors) declares a /// `#property` field with the given name, return the -/// `ForeignFieldDecl`. M2.2 + M2.3. -pub fn lookupObjcPropertyOnPointer(self: *Lowering, obj_expr: *const ast.Node, field_name: []const u8) ?ast.ForeignFieldDecl { +/// `RuntimeFieldDecl`. M2.2 + M2.3. +pub fn lookupObjcPropertyOnPointer(self: *Lowering, obj_expr: *const ast.Node, field_name: []const u8) ?ast.RuntimeFieldDecl { const obj_ty = self.inferExprType(obj_expr); if (obj_ty.isBuiltin()) return null; const ptr_info = self.module.types.get(obj_ty); @@ -74,8 +74,8 @@ pub fn lookupObjcPropertyOnPointer(self: *Lowering, obj_expr: *const ast.Node, f /// Returns the owning fcd + the method decl, or null if no ancestor /// declares it. Depth-capped at 16 to break accidental cycles /// (real Obj-C class chains rarely exceed 6 levels). -pub fn findForeignMethodInChain(self: *Lowering, fcd: *const ast.ForeignClassDecl, method_name: []const u8) ?struct { fcd: *const ast.ForeignClassDecl, method: ast.ForeignMethodDecl } { - var current: *const ast.ForeignClassDecl = fcd; +pub fn findForeignMethodInChain(self: *Lowering, fcd: *const ast.RuntimeClassDecl, method_name: []const u8) ?struct { fcd: *const ast.RuntimeClassDecl, method: ast.RuntimeMethodDecl } { + var current: *const ast.RuntimeClassDecl = fcd; var depth: u32 = 0; while (depth < 16) : (depth += 1) { for (current.members) |m| switch (m) { @@ -97,8 +97,8 @@ pub fn findForeignMethodInChain(self: *Lowering, fcd: *const ast.ForeignClassDec /// Walk the `#extends` chain looking for a `#property` field by /// name. M2.3 companion to findForeignMethodInChain. -pub fn findForeignPropertyInChain(self: *Lowering, fcd: *const ast.ForeignClassDecl, field_name: []const u8) ?ast.ForeignFieldDecl { - var current: *const ast.ForeignClassDecl = fcd; +pub fn findForeignPropertyInChain(self: *Lowering, fcd: *const ast.RuntimeClassDecl, field_name: []const u8) ?ast.RuntimeFieldDecl { + var current: *const ast.RuntimeClassDecl = fcd; var depth: u32 = 0; while (depth < 16) : (depth += 1) { for (current.members) |m| switch (m) { @@ -121,7 +121,7 @@ const ObjcDefinedStateField = struct { field_ty: TypeId, state_ty: TypeId, field_idx: u32, - fcd: *const ast.ForeignClassDecl, + fcd: *const ast.RuntimeClassDecl, }; /// State-field-access info: if obj_expr is * @@ -190,7 +190,7 @@ pub fn lowerObjcDefinedStateFieldRead( /// `state = object_getIvar(obj, load(___state_ivar))`. Shared /// helper for state-field read + write (M1.2 A.3). -pub fn lowerObjcDefinedStateForObj(self: *Lowering, obj_ref: Ref, fcd: *const ast.ForeignClassDecl) ?Ref { +pub fn lowerObjcDefinedStateForObj(self: *Lowering, obj_ref: Ref, fcd: *const ast.RuntimeClassDecl) ?Ref { const ptr_void = self.module.types.ptrTo(.void); const ivar_global_name = std.fmt.allocPrint(self.alloc, "__{s}_state_ivar", .{fcd.name}) catch return null; defer self.alloc.free(ivar_global_name); @@ -207,7 +207,7 @@ pub fn lowerObjcDefinedStateForObj(self: *Lowering, obj_ref: Ref, fcd: *const as /// Lower `obj.field` for an Obj-C `#property` field as /// `objc_msg_send(obj, sel_)`. M2.2 — getter side. /// The setter side lives in the assignment-statement lowering. -pub fn lowerObjcPropertyGetter(self: *Lowering, obj_expr: *const ast.Node, field: ast.ForeignFieldDecl, _: []const u8, _: ast.Span) Ref { +pub fn lowerObjcPropertyGetter(self: *Lowering, obj_expr: *const ast.Node, field: ast.RuntimeFieldDecl, _: []const u8, _: ast.Span) Ref { const obj_ref = self.lowerExpr(obj_expr); const ret_ty = self.resolveType(field.field_type); const vptr_ty = self.module.types.ptrTo(.void); @@ -228,7 +228,7 @@ pub fn lowerObjcPropertyGetter(self: *Lowering, obj_expr: *const ast.Node, field /// `objc_msg_send(obj, sel_set:, val)`. M2.2 — setter side. /// Selector: prepend "set", capitalize the first letter of the /// field name, append ":". `backgroundColor` → `setBackgroundColor:`. -pub fn lowerObjcPropertySetter(self: *Lowering, obj_expr: *const ast.Node, field: ast.ForeignFieldDecl, val: Ref) void { +pub fn lowerObjcPropertySetter(self: *Lowering, obj_expr: *const ast.Node, field: ast.RuntimeFieldDecl, val: Ref) void { const obj_ref = self.lowerExpr(obj_expr); const vptr_ty = self.module.types.ptrTo(.void); @@ -361,7 +361,7 @@ pub fn ensureArcRuntimeDecls(self: *Lowering) void { /// Both IMPs land in the cache's methods slice with appropriate /// selectors + encodings; emit_llvm's class_addMethod loop wires /// them up like any other instance method. -pub fn emitObjcDefinedClassPropertyImps(self: *Lowering, fcd: *const ast.ForeignClassDecl, field: ast.ForeignFieldDecl) void { +pub fn emitObjcDefinedClassPropertyImps(self: *Lowering, fcd: *const ast.RuntimeClassDecl, field: ast.RuntimeFieldDecl) void { const state_ty = self.objc().objcDefinedStateStructType(fcd); const state_info = self.module.types.get(state_ty); if (state_info != .@"struct") return; @@ -404,7 +404,7 @@ pub fn emitObjcDefinedClassPropertyImps(self: *Lowering, fcd: *const ast.Foreign self.registerObjcDefinedPropertyMethodEntries(fcd, field, field_ty, is_readonly); } -pub fn emitObjcDefinedPropertyGetter(self: *Lowering, fcd: *const ast.ForeignClassDecl, field: ast.ForeignFieldDecl, state_ty: TypeId, fidx: u32, field_ty: TypeId) void { +pub fn emitObjcDefinedPropertyGetter(self: *Lowering, fcd: *const ast.RuntimeClassDecl, field: ast.RuntimeFieldDecl, state_ty: TypeId, fidx: u32, field_ty: TypeId) void { const saved_func = self.builder.func; const saved_block = self.builder.current_block; const saved_counter = self.builder.inst_counter; @@ -484,7 +484,7 @@ pub fn emitObjcDefinedPropertyGetter(self: *Lowering, fcd: *const ast.ForeignCla self.builder.finalize(); } -pub fn emitObjcDefinedPropertySetter(self: *Lowering, fcd: *const ast.ForeignClassDecl, field: ast.ForeignFieldDecl, state_ty: TypeId, fidx: u32, field_ty: TypeId) void { +pub fn emitObjcDefinedPropertySetter(self: *Lowering, fcd: *const ast.RuntimeClassDecl, field: ast.RuntimeFieldDecl, state_ty: TypeId, fidx: u32, field_ty: TypeId) void { const saved_func = self.builder.func; const saved_block = self.builder.current_block; const saved_counter = self.builder.inst_counter; @@ -610,7 +610,7 @@ pub fn emitObjcDefinedPropertySetter(self: *Lowering, fcd: *const ast.ForeignCla /// entries to the class's method-registration slice so emit_llvm /// calls class_addMethod on each. Selectors + encodings derived /// from the field type. -pub fn registerObjcDefinedPropertyMethodEntries(self: *Lowering, fcd: *const ast.ForeignClassDecl, field: ast.ForeignFieldDecl, field_ty: TypeId, is_readonly: bool) void { +pub fn registerObjcDefinedPropertyMethodEntries(self: *Lowering, fcd: *const ast.RuntimeClassDecl, field: ast.RuntimeFieldDecl, field_ty: TypeId, is_readonly: bool) void { const cur = self.module.lookupObjcDefinedClass(fcd.name) orelse return; _ = cur; // Find the existing entry and grow its methods slice. @@ -665,7 +665,7 @@ pub fn registerObjcDefinedPropertyMethodEntries(self: *Lowering, fcd: *const ast self.module.setObjcDefinedClassMethods(fcd.name, slice); } -pub fn emitObjcDefinedClassImp(self: *Lowering, fcd: *const ast.ForeignClassDecl, md: ast.ForeignMethodDecl) void { +pub fn emitObjcDefinedClassImp(self: *Lowering, fcd: *const ast.RuntimeClassDecl, md: ast.RuntimeMethodDecl) void { // Class methods (no `*Self` first param) skip the ivar read — // they have no instance state to thread through. if (md.is_static) { @@ -800,7 +800,7 @@ pub fn emitObjcDefinedClassImp(self: *Lowering, fcd: *const ast.ForeignClassDecl /// `current_ctx_ref` as the ctx — so `push Context.{ allocator = ... }` /// flows through to per-instance allocator capture without going via /// the IMP. -pub fn emitObjcDefinedClassAllocImp(self: *Lowering, fcd: *const ast.ForeignClassDecl) void { +pub fn emitObjcDefinedClassAllocImp(self: *Lowering, fcd: *const ast.RuntimeClassDecl) void { const saved_func = self.builder.func; const saved_block = self.builder.current_block; const saved_counter = self.builder.inst_counter; @@ -858,7 +858,7 @@ pub fn emitObjcDefinedClassAllocImp(self: *Lowering, fcd: *const ast.ForeignClas /// missing (compiler bug — should be impossible after scan pass). pub fn emitObjcDefinedAllocAndInit( self: *Lowering, - fcd: *const ast.ForeignClassDecl, + fcd: *const ast.RuntimeClassDecl, cls_ref: Ref, ctx_addr: Ref, ) ?Ref { @@ -953,7 +953,7 @@ pub fn emitObjcDefinedAllocAndInit( /// ret /// /// No ivar read — class methods have no per-instance state. -pub fn emitObjcDefinedClassStaticImp(self: *Lowering, fcd: *const ast.ForeignClassDecl, md: ast.ForeignMethodDecl) void { +pub fn emitObjcDefinedClassStaticImp(self: *Lowering, fcd: *const ast.RuntimeClassDecl, md: ast.RuntimeMethodDecl) void { const saved_func = self.builder.func; const saved_block = self.builder.current_block; const saved_counter = self.builder.inst_counter; @@ -1050,7 +1050,7 @@ pub fn emitObjcDefinedClassStaticImp(self: *Lowering, fcd: *const ast.ForeignCla /// +alloc time (M4.0a + M4.0b). Reading it back lets -dealloc free /// through the same allocator the instance was constructed with — /// the per-instance allocator design from M1.2 A.5, now realised. -pub fn emitObjcDefinedClassDeallocImp(self: *Lowering, fcd: *const ast.ForeignClassDecl) void { +pub fn emitObjcDefinedClassDeallocImp(self: *Lowering, fcd: *const ast.RuntimeClassDecl) void { const saved_func = self.builder.func; const saved_block = self.builder.current_block; const saved_counter = self.builder.inst_counter; diff --git a/src/ir/module.zig b/src/ir/module.zig index 0e3fb40..c8d3fb6 100644 --- a/src/ir/module.zig +++ b/src/ir/module.zig @@ -74,7 +74,7 @@ pub const Module = struct { /// instance method without re-resolving types from the AST. pub const ObjcDefinedClassEntry = struct { name: []const u8, - decl: *const ast.ForeignClassDecl, + decl: *const ast.RuntimeClassDecl, methods: []const ObjcDefinedMethodEntry = &.{}, /// Pre-resolved Obj-C runtime name of the parent class, so /// emit_llvm can pass it to `objc_getClass(parent)` / @@ -146,14 +146,14 @@ pub const Module = struct { } /// Linear scan over sx-defined Obj-C classes. - pub fn lookupObjcDefinedClass(self: *const Module, name: []const u8) ?*const ast.ForeignClassDecl { + pub fn lookupObjcDefinedClass(self: *const Module, name: []const u8) ?*const ast.RuntimeClassDecl { for (self.objc_defined_class_cache.items) |entry| { if (std.mem.eql(u8, entry.name, name)) return entry.decl; } return null; } - pub fn appendObjcDefinedClass(self: *Module, name: []const u8, decl: *const ast.ForeignClassDecl) void { + pub fn appendObjcDefinedClass(self: *Module, name: []const u8, decl: *const ast.RuntimeClassDecl) void { self.objc_defined_class_cache.append(self.alloc, .{ .name = name, .decl = decl }) catch unreachable; } diff --git a/src/ir/program_index.test.zig b/src/ir/program_index.test.zig index 8354057..3b3b197 100644 --- a/src/ir/program_index.test.zig +++ b/src/ir/program_index.test.zig @@ -67,8 +67,8 @@ test "ProgramIndex declaration maps round-trip (A1.1b)" { try idx.module_const_map.put("AF_INET", .{ .value = &blk, .ty = .i32 }); try std.testing.expect(idx.module_const_map.get("AF_INET").?.value == &blk); - // foreign_class_map: sx alias → ForeignClassDecl. - const fcd = ast.ForeignClassDecl{ + // foreign_class_map: sx alias → RuntimeClassDecl. + const fcd = ast.RuntimeClassDecl{ .name = "NSString", .foreign_path = "NSString", .runtime = .objc_class, diff --git a/src/ir/program_index.zig b/src/ir/program_index.zig index 6a0ce0b..26c92a6 100644 --- a/src/ir/program_index.zig +++ b/src/ir/program_index.zig @@ -664,8 +664,8 @@ pub const ProgramIndex = struct { /// in the right visibility context — its intra-module / own-import callees /// resolve. Keyed/allocated with the lowering allocator. qualified_fn_source: std.StringHashMap([]const u8), - /// sx alias → ForeignClassDecl (jni_class / objc_class / swift_class / ... — registered in scan pass). - foreign_class_map: std.StringHashMap(*const ast.ForeignClassDecl), + /// sx alias → RuntimeClassDecl (jni_class / objc_class / swift_class / ... — registered in scan pass). + foreign_class_map: std.StringHashMap(*const ast.RuntimeClassDecl), /// `#run` global name → GlobalId. global_names: std.StringHashMap(GlobalInfo), /// Type alias name → target TypeId. The single-source alias table; passed @@ -708,7 +708,7 @@ pub const ProgramIndex = struct { .fn_ast_map = std.StringHashMap(*const ast.FnDecl).init(alloc), .qualified_fn_source = std.StringHashMap([]const u8).init(alloc), .global_names = std.StringHashMap(GlobalInfo).init(alloc), - .foreign_class_map = std.StringHashMap(*const ast.ForeignClassDecl).init(alloc), + .foreign_class_map = std.StringHashMap(*const ast.RuntimeClassDecl).init(alloc), .type_alias_map = std.StringHashMap(TypeId).init(alloc), .struct_template_map = std.StringHashMap(StructTemplate).init(alloc), .struct_template_by_decl = std.AutoHashMap(imports.DeclId, StructTemplate).init(alloc), diff --git a/src/parser.zig b/src/parser.zig index b2e158b..daf05b4 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -1280,7 +1280,7 @@ pub const Parser = struct { } }); } - fn foreignRuntimeForCurrent(self: *Parser) ?ast.ForeignRuntime { + fn foreignRuntimeForCurrent(self: *Parser) ?ast.RuntimeKind { return switch (self.current.tag) { .hash_jni_class => .jni_class, .hash_jni_interface => .jni_interface, @@ -1293,8 +1293,8 @@ pub const Parser = struct { }; } - const ForeignClassPrefix = struct { - runtime: ast.ForeignRuntime, + const RuntimeClassPrefix = struct { + runtime: ast.RuntimeKind, is_foreign: bool, is_main: bool, }; @@ -1305,7 +1305,7 @@ pub const Parser = struct { /// directive (possibly after modifiers). Consumes the modifier tokens /// only when a runtime directive follows; otherwise leaves the parser /// state untouched. - fn tryParseForeignClassPrefix(self: *Parser) ?ForeignClassPrefix { + fn tryParseForeignClassPrefix(self: *Parser) ?RuntimeClassPrefix { // Peek ahead through modifier tokens to confirm a directive follows. var lookahead_idx: usize = 0; var is_foreign = false; @@ -1349,7 +1349,7 @@ pub const Parser = struct { return self.peekTag(1) == .identifier and self.peekTag(2) == .r_paren; } - fn foreignRuntimeForOffset(self: *Parser, offset: usize) ?ast.ForeignRuntime { + fn foreignRuntimeForOffset(self: *Parser, offset: usize) ?ast.RuntimeKind { const tag = self.peekTag(offset); return switch (tag) { .hash_jni_class => .jni_class, @@ -1363,7 +1363,7 @@ pub const Parser = struct { }; } - fn parseForeignClassDecl(self: *Parser, name: []const u8, start_pos: u32, runtime: ast.ForeignRuntime, is_foreign: bool, is_main: bool, name_is_raw: bool) anyerror!*Node { + fn parseForeignClassDecl(self: *Parser, name: []const u8, start_pos: u32, runtime: ast.RuntimeKind, is_foreign: bool, is_main: bool, name_is_raw: bool) anyerror!*Node { self.advance(); // skip directive token try self.expect(.l_paren); @@ -1399,7 +1399,7 @@ pub const Parser = struct { try self.expect(.l_brace); - var members = std.ArrayList(ast.ForeignClassMember).empty; + var members = std.ArrayList(ast.RuntimeClassMember).empty; while (self.current.tag != .r_brace and self.current.tag != .eof) { // #extends Alias; or #implements Alias; if (self.current.tag == .hash_extends or self.current.tag == .hash_implements) {