From 17775b27a4a52c06fb7ab9e8b7043478e6d7ee46 Mon Sep 17 00:00:00 2001 From: agra Date: Mon, 25 May 2026 17:12:33 +0300 Subject: [PATCH] ffi 3.2 C2: migrate uikit.sx Notifications + Bundle cluster MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Second cluster: NSNotification, NSBundle, NSNotificationCenter move from `#objc_call(T)(recv, "sel:", args)` to declarative `#foreign #objc_class("Cls") { ... }` blocks. Classes declared (alongside the C1 Foundation utility group): - NSNotification → userInfo (instance, returns *NSDictionary) - NSBundle → mainBundle (class), resourcePath (instance) - NSNotificationCenter → defaultCenter (class), addObserver_selector_name_object (instance) The 4-keyword `addObserver:selector:name:object:` selector derives from the underscore-separated sx name via the default mangling rule — no `#selector` override needed. Cleanup wins: - `objc_getClass("NSBundle")` and `objc_getClass("NSNotificationCenter")` call sites gone — class slots now populated by emit_llvm's `__sx_objc_class_init` constructor. - `userInfo`'s return type is `*NSDictionary` directly, so the previous `*void → *NSDictionary` cast at the keyboard-frame callsite collapses. 166/166 tests; chess builds clean on macOS + iOS + Android via `sx build main.sx`. --- current/CHECKPOINT-FFI.md | 9 ++++++++- library/modules/platform/uikit.sx | 32 ++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/current/CHECKPOINT-FFI.md b/current/CHECKPOINT-FFI.md index 6b44c16..1679b16 100644 --- a/current/CHECKPOINT-FFI.md +++ b/current/CHECKPOINT-FFI.md @@ -553,8 +553,15 @@ 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). +Phase 3.2 C2 landed: notifications + bundle cluster migrated. +NSNotification (`userInfo`), NSBundle (`mainBundle`, `resourcePath`), +NSNotificationCenter (`defaultCenter`, `addObserver_selector_name_object`) +declared as `#foreign #objc_class` blocks. The 4-keyword +`addObserver:selector:name:object:` selector derives cleanly from +the underscore-separated sx name (`addObserver_selector_name_object`). + Open work: -- **Phase 3 step 3.2 — C2..C5** — uikit.sx migration, one cluster +- **Phase 3 step 3.2 — C3..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 2b0df77..ac3eaab 100644 --- a/library/modules/platform/uikit.sx +++ b/library/modules/platform/uikit.sx @@ -84,6 +84,22 @@ NSSet :: #foreign #objc_class("NSSet") { anyObject :: (self: *Self) -> *void; } +// ── Notifications + Bundle (Phase 3.2 C2) ────────────────────────────── + +NSNotification :: #foreign #objc_class("NSNotification") { + userInfo :: (self: *Self) -> *NSDictionary; +} + +NSBundle :: #foreign #objc_class("NSBundle") { + mainBundle :: () -> *NSBundle; + resourcePath :: (self: *Self) -> *void; +} + +NSNotificationCenter :: #foreign #objc_class("NSNotificationCenter") { + defaultCenter :: () -> *NSNotificationCenter; + addObserver_selector_name_object :: (self: *Self, observer: *void, sel: *void, name: *void, obj: *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; @@ -304,9 +320,8 @@ uikit_refresh_safe_insets :: (plat: *UIKitPlatform) { uikit_chdir_to_bundle :: () { inline if OS != .ios { return; } - NSBundle := objc_getClass("NSBundle".ptr); - bundle := #objc_call(*void)(NSBundle, "mainBundle"); - rsrc := #objc_call(*void)(bundle, "resourcePath"); + bundle := NSBundle.mainBundle(); + rsrc := bundle.resourcePath(); if rsrc == null { return; } chdir(c_string(rsrc)); } @@ -388,9 +403,9 @@ uikit_keyboard_will_change_frame :: (self: *void, _cmd: *void, notification: *vo if g_uikit_plat == null { return; } plat := g_uikit_plat; - user_info_raw := #objc_call(*void)(notification, "userInfo"); - if user_info_raw == null { return; } - user_info : *NSDictionary = xx user_info_raw; + notif : *NSNotification = xx notification; + user_info := notif.userInfo(); + if user_info == null { return; } end_value_raw := user_info.objectForKey(ns_string("UIKeyboardFrameEndUserInfoKey".ptr)); if end_value_raw == null { return; } @@ -494,9 +509,8 @@ uikit_did_finish_launching :: (self: *void, _cmd: *void, app: *void, opts: *void uikit_subscribe_keyboard_notifications :: (delegate: *void) { inline if OS != .ios { return; } - NSNotificationCenter := objc_getClass("NSNotificationCenter".ptr); - center := #objc_call(*void)(NSNotificationCenter, "defaultCenter"); - #objc_call(void)(center, "addObserver:selector:name:object:", + center := NSNotificationCenter.defaultCenter(); + center.addObserver_selector_name_object( delegate, sel_registerName("sxKeyboardWillChangeFrame:".ptr), ns_string("UIKeyboardWillChangeFrameNotification".ptr),