refactor(ffi-linkage): Phase 9.2a — rename runtime-class TYPE names → Runtime* (Decision 5)

Mechanical, collision-free PascalCase renames (object-model axis, not linkage):
ForeignClassDecl→RuntimeClassDecl, ForeignMethodDecl→RuntimeMethodDecl,
ForeignClassMember→RuntimeClassMember, ForeignFieldDecl→RuntimeFieldDecl,
ForeignRuntime→RuntimeKind, ForeignClassPrefix→RuntimeClassPrefix. Snapshot-neutral;
suite green (646/444). Remaining 9.2: snake_case state (foreign_class_map,
current_foreign_class, foreign_path [coupled to .sx hooks], the foreign_class_decl
union variant) + the parse/lower/resolve fn names + ForeignClassDecl.is_foreign flag.
This commit is contained in:
agra
2026-06-15 08:57:53 +03:00
parent 7ffdc7d2a2
commit 3354446412
16 changed files with 129 additions and 129 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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 = &.{} } });

View File

@@ -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;

View File

@@ -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" },

View File

@@ -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

View File

@@ -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,

View File

@@ -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.<method>(...)`
@@ -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| {

View File

@@ -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.

View File

@@ -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.<same_name>(...)` 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.<same_name>(...)` 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

View File

@@ -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 `<ClassName>.<methodName>`. Lazy lowering
/// then handles the body via the standard path; `*Self` is
/// substituted to `*<ClassName>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 `<ClassName>.<methodName>`, 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 (`<ClassName>.<methodName>`), 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);

View File

@@ -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 *<sx-defined-class>
@@ -190,7 +190,7 @@ pub fn lowerObjcDefinedStateFieldRead(
/// `state = object_getIvar(obj, load(__<Cls>_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_<fieldName>)`. 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<Field>:, 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 <result>
///
/// 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;

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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),

View File

@@ -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) {