diff --git a/current/CHECKPOINT-FFI.md b/current/CHECKPOINT-FFI.md index 43cc87e..6b44c16 100644 --- a/current/CHECKPOINT-FFI.md +++ b/current/CHECKPOINT-FFI.md @@ -543,8 +543,18 @@ one fixture. Both `.txt` and `.ir` snapshots locked — a change to `deriveObjcSelector` produces one diff that surfaces every affected case at once via the `OBJC_METH_VAR_NAME_*` constants in the IR. -Open work, in roughly the order they make sense: -- **Phase 3 step 3.2 — C1..C5** — uikit.sx migration, one cluster +Phase 3.2 C1 landed: Foundation utility cluster in uikit.sx +migrated to declarative `#objc_class` bodies. Five classes declared +near the top of the file (NSValue, NSNumber, NSDictionary, +NSMutableDictionary, NSSet). Call sites rewritten from +`#objc_call(T)(recv, "sel:", args)` to `recv.method(args)` / +`Cls.method(args)`. Receivers cast from `*void` to the typed +foreign-class pointer at the dispatch site. The `objc_getClass(...)` +calls for these classes are gone — the class slot is now populated +by emit_llvm's `__sx_objc_class_init` constructor (Phase 3.1). + +Open work: +- **Phase 3 step 3.2 — C2..C5** — uikit.sx migration, one cluster per commit, chess regression after each. test for the default-mangling table. Escape hatch for selectors that don't fit the underscore-split rule (e.g. `tableView_ diff --git a/library/modules/platform/uikit.sx b/library/modules/platform/uikit.sx index 6afe3d6..2b0df77 100644 --- a/library/modules/platform/uikit.sx +++ b/library/modules/platform/uikit.sx @@ -52,6 +52,38 @@ CGRect :: struct { height: f64; } +// ── Foundation utility classes (Phase 3.2 C1) ───────────────────────── +// Declarative `#objc_class` bindings replace the previous +// `objc_getClass(...) + #objc_call(T)(...)` pattern. Each method's sx- +// side name maps to its Obj-C selector via the default mangling rule +// (split on `_`; each piece becomes a keyword with `:`). + +NSValue :: #foreign #objc_class("NSValue") { + // CGRect unboxing — returns by value via the sret/HFA path. + CGRectValue :: (self: *Self) -> CGRect; +} + +NSNumber :: #foreign #objc_class("NSNumber") { + // Class method (no `self: *Self` first param → static dispatch). + numberWithBool :: (b: s8) -> *NSNumber; + // Instance value extractors. + doubleValue :: (self: *Self) -> f64; + unsignedLongValue :: (self: *Self) -> u64; +} + +NSDictionary :: #foreign #objc_class("NSDictionary") { + objectForKey :: (self: *Self, key: *void) -> *void; +} + +NSMutableDictionary :: #foreign #objc_class("NSMutableDictionary") { + dictionary :: () -> *NSMutableDictionary; + setObject_forKey :: (self: *Self, obj: *void, key: *void); +} + +NSSet :: #foreign #objc_class("NSSet") { + anyObject :: (self: *Self) -> *void; +} + // GLenum constants for renderbuffer/framebuffer setup that aren't in opengl.sx's // loader path (they live on the framework's symbol table directly). GL_RENDERBUFFER :u32: 0x8D41; @@ -356,23 +388,28 @@ uikit_keyboard_will_change_frame :: (self: *void, _cmd: *void, notification: *vo if g_uikit_plat == null { return; } plat := g_uikit_plat; - user_info := #objc_call(*void)(notification, "userInfo"); - if user_info == null { return; } + user_info_raw := #objc_call(*void)(notification, "userInfo"); + if user_info_raw == null { return; } + user_info : *NSDictionary = xx user_info_raw; - end_value := #objc_call(*void)(user_info, "objectForKey:", - ns_string("UIKeyboardFrameEndUserInfoKey".ptr)); - if end_value == null { return; } - end_rect := #objc_call(CGRect)(end_value, "CGRectValue"); + end_value_raw := user_info.objectForKey(ns_string("UIKeyboardFrameEndUserInfoKey".ptr)); + if end_value_raw == null { return; } + end_value : *NSValue = xx end_value_raw; + end_rect := end_value.CGRectValue(); - dur_value := #objc_call(*void)(user_info, "objectForKey:", - ns_string("UIKeyboardAnimationDurationUserInfoKey".ptr)); + dur_value_raw := user_info.objectForKey(ns_string("UIKeyboardAnimationDurationUserInfoKey".ptr)); anim_dur : f64 = 0.0; - if dur_value != null { anim_dur = #objc_call(f64)(dur_value, "doubleValue"); } + if dur_value_raw != null { + dur_value : *NSNumber = xx dur_value_raw; + anim_dur = dur_value.doubleValue(); + } - curve_value := #objc_call(*void)(user_info, "objectForKey:", - ns_string("UIKeyboardAnimationCurveUserInfoKey".ptr)); + curve_value_raw := user_info.objectForKey(ns_string("UIKeyboardAnimationCurveUserInfoKey".ptr)); curve_int : u64 = 0; - if curve_value != null { curve_int = #objc_call(u64)(curve_value, "unsignedLongValue"); } + if curve_value_raw != null { + curve_value : *NSNumber = xx curve_value_raw; + curve_int = curve_value.unsignedLongValue(); + } // Screen height in points. The window lives on the connected scene's screen. if plat.window == null { return; } @@ -520,10 +557,7 @@ uikit_scene_will_connect_ios :: (delegate: *void, scene: *void) { // EAGLContext.renderbufferStorage:fromDrawable: (color format, // non-retained backing). Without this dict the renderbuffer // allocation silently fails and the framebuffer reports INCOMPLETE. - NSMutableDictionary := objc_getClass("NSMutableDictionary".ptr); - NSNumber := objc_getClass("NSNumber".ptr); - - ns_no := #objc_call(*void)(NSNumber, "numberWithBool:", xx 0); + ns_no := NSNumber.numberWithBool(0); // The EAGL dict keys/values must be the framework-provided NSString // constants (pointer identity is checked) — dlsym them from OpenGLES. @@ -531,10 +565,10 @@ uikit_scene_will_connect_ios :: (delegate: *void, scene: *void) { colorformat_key := uikit_extern_nsstring("kEAGLDrawablePropertyColorFormat".ptr); rgba8_value := uikit_extern_nsstring("kEAGLColorFormatRGBA8".ptr); - dict := #objc_call(*void)(NSMutableDictionary, "dictionary"); - #objc_call(void)(dict, "setObject:forKey:", ns_no, retained_key); - #objc_call(void)(dict, "setObject:forKey:", rgba8_value, colorformat_key); - #objc_call(void)(plat.gl_layer, "setDrawableProperties:", dict); + dict := NSMutableDictionary.dictionary(); + dict.setObject_forKey(xx ns_no, retained_key); + dict.setObject_forKey(rgba8_value, colorformat_key); + #objc_call(void)(plat.gl_layer, "setDrawableProperties:", xx dict); } // EAGLContext + load_gl were already done in uikit_create_gl_context() @@ -732,7 +766,8 @@ uikit_touch_location :: (touch: *void, view: *void) -> Point { } uikit_first_touch :: (touches: *void) -> *void { - #objc_call(*void)(touches, "anyObject"); + touches_set : *NSSet = xx touches; + touches_set.anyObject(); } uikit_gl_view_touches_began :: (self: *void, _cmd: *void, touches: *void, event: *void) callconv(.c) {