ios + ir cleanup
- ios: --target ios/ios-sim shorthands, iOS SDK auto-discovery,
#framework directive + BuildOptions.add_framework hook,
.app bundle + Info.plist + codesign (ad-hoc and real),
--codesign-identity/--provisioning-profile/--entitlements flags,
modules/std/{objc,uikit}.sx, dynamic class registration,
typed objc_msgSend cast pattern, UIApplicationMain handoff,
UIWindow scene attach. Runs on iPhone hardware.
- ir: silent .s64 defaults → loud diagnostics,
resolveReturnType infers from body, sub-byte int sizes match LLVM,
tuple type interning includes names, compile errors exit 1
- issue-NNNN convention: resolved bugs rename to focused features
- 50 regression tests passing
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
// issue-0012: Pattern match expression with mixed null/concrete arms
|
||||
//
|
||||
// A match expression with both `null` arms and concrete struct value arms
|
||||
// should produce an optional type (?T) and correctly wrap non-null values.
|
||||
// Match expression with both `null` arms and concrete struct value arms
|
||||
// produces an optional type (?T) and correctly wraps non-null values.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// issue-0016: C calling convention for function pointers passed to foreign callbacks.
|
||||
//
|
||||
// `callconv(.c)` ensures the function uses C ABI, so it can be safely
|
||||
// passed as a callback to #foreign functions like SDL_AddEventWatch.
|
||||
// `callconv(.c)` on function pointers passed to foreign callbacks — ensures
|
||||
// the function uses C ABI so it can be safely invoked from `#foreign`
|
||||
// functions like SDL_AddEventWatch.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// issue-0017: Investigate data corruption in callconv(.c) callbacks
|
||||
// when accessing struct methods on global pointers.
|
||||
// `callconv(.c)` callbacks accessing struct methods on global pointers —
|
||||
// regression coverage for prior data-corruption when the callback dispatches
|
||||
// through a global pointer to a method on the pointed-to struct.
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
9
examples/55-err-field-not-found.sx
Normal file
9
examples/55-err-field-not-found.sx
Normal file
@@ -0,0 +1,9 @@
|
||||
// Accessing an unknown field on a struct produces a clear
|
||||
// `error: field 'X' not found on type 'Y'` diagnostic and exit 1.
|
||||
|
||||
Vec :: struct { x: f32; y: f32; }
|
||||
|
||||
main :: () -> s32 {
|
||||
v := Vec.{ x = 1.0, y = 2.0 };
|
||||
return xx v.bogus;
|
||||
}
|
||||
7
examples/56-err-tuple-oob.sx
Normal file
7
examples/56-err-tuple-oob.sx
Normal file
@@ -0,0 +1,7 @@
|
||||
// Out-of-range tuple index produces a clear
|
||||
// `error: field 'N' not found on type 'tuple'` diagnostic and exit 1.
|
||||
|
||||
main :: () -> s32 {
|
||||
t := (10, 20);
|
||||
return xx t.42;
|
||||
}
|
||||
7
examples/57-err-dot-shorthand.sx
Normal file
7
examples/57-err-dot-shorthand.sx
Normal file
@@ -0,0 +1,7 @@
|
||||
// Dot-shorthand `.Variant(args)` without a tagged-union target type produces
|
||||
// `error: cannot infer enum type for '.X'` instead of crashing.
|
||||
|
||||
main :: () -> s32 {
|
||||
x := .Foo(1, 2);
|
||||
return 0;
|
||||
}
|
||||
16
examples/58-infer-return-type.sx
Normal file
16
examples/58-infer-return-type.sx
Normal file
@@ -0,0 +1,16 @@
|
||||
// Functions without an explicit return type infer the type from the first
|
||||
// `return <value>;` statement in the body, so `foo :: () { return 42; }` is
|
||||
// usable from a typed context. No explicit-value return → `.void` default.
|
||||
|
||||
foo :: () { return 42; }
|
||||
bar :: () { return foo() * 2; }
|
||||
nested :: () {
|
||||
if true {
|
||||
return foo() + 10;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
main :: () -> s32 {
|
||||
return xx (foo() + bar() + nested());
|
||||
}
|
||||
22
examples/59-err-bad-variant.sx
Normal file
22
examples/59-err-bad-variant.sx
Normal file
@@ -0,0 +1,22 @@
|
||||
// A match arm with a variant name that doesn't exist on the subject's
|
||||
// enum/tagged-union produces `error: no variant 'X' on type 'Y'` instead of
|
||||
// falling back to the arm index (which used to cause duplicate switch cases
|
||||
// and LLVM verification failures).
|
||||
|
||||
#import "modules/std.sx";
|
||||
|
||||
Shape :: enum {
|
||||
circle: f32;
|
||||
rect: struct { w, h: f32; };
|
||||
none;
|
||||
}
|
||||
|
||||
main :: () {
|
||||
s :Shape = .circle(3.14);
|
||||
if s == {
|
||||
case .circle: (r) { print("r={}\n", r); }
|
||||
case .Bogus: (x) { print("bogus={}\n", x); }
|
||||
case .none: print("none\n");
|
||||
case .rect: print("rect\n");
|
||||
}
|
||||
}
|
||||
12
examples/60-frameworks.sx
Normal file
12
examples/60-frameworks.sx
Normal file
@@ -0,0 +1,12 @@
|
||||
// `#framework "Name"` top-level directive registers an Apple framework for
|
||||
// linking; `#foreign` declarations can omit the library identifier (frameworks
|
||||
// resolve symbols by global namespace at link time).
|
||||
|
||||
#framework "CoreFoundation";
|
||||
|
||||
CFAbsoluteTimeGetCurrent :: () -> f64 #foreign;
|
||||
|
||||
main :: () -> s32 {
|
||||
t := CFAbsoluteTimeGetCurrent();
|
||||
return if t > 0.0 then 0 else 1;
|
||||
}
|
||||
28
examples/61-objc-roundtrip.sx
Normal file
28
examples/61-objc-roundtrip.sx
Normal file
@@ -0,0 +1,28 @@
|
||||
// Obj-C runtime FFI smoke test: round-trip a string through NSString.
|
||||
//
|
||||
// Demonstrates the typed-fn-pointer cast idiom for `objc_msgSend`. Each
|
||||
// shape we invoke gets its own variable typed with the exact ABI:
|
||||
//
|
||||
// msg_3 : (*void, *void, [*]u8) -> *void = xx objc_msgSend;
|
||||
// msg_2 : (*void, *void) -> [*]u8 = xx objc_msgSend;
|
||||
//
|
||||
// On ARM64 Apple, objc_msgSend doesn't take a varargs path — invoking it
|
||||
// through a typed fn-pointer is the only correct way to land args in the
|
||||
// right registers.
|
||||
|
||||
#import "modules/std.sx";
|
||||
#import "modules/std/objc.sx";
|
||||
|
||||
main :: () -> s32 {
|
||||
ns_class := objc_getClass("NSString".ptr);
|
||||
sel_with_utf8 := sel_registerName("stringWithUTF8String:".ptr);
|
||||
sel_utf8 := sel_registerName("UTF8String".ptr);
|
||||
|
||||
msg_3 : (*void, *void, [*]u8) -> *void = xx objc_msgSend;
|
||||
ns_str := msg_3(ns_class, sel_with_utf8, "hi".ptr);
|
||||
|
||||
msg_2 : (*void, *void) -> [*]u8 = xx objc_msgSend;
|
||||
back := msg_2(ns_str, sel_utf8);
|
||||
|
||||
return xx (back[0] + back[1]); // 'h' + 'i' = 104 + 105 = 209
|
||||
}
|
||||
41
examples/62-objc-class.sx
Normal file
41
examples/62-objc-class.sx
Normal file
@@ -0,0 +1,41 @@
|
||||
// Register a brand-new Obj-C class from sx and prove a sx-defined method
|
||||
// actually runs when dispatched through `objc_msgSend`.
|
||||
//
|
||||
// The flow:
|
||||
// 1. `objc_allocateClassPair(NSObject, "SxThing", 0)` returns an unregistered Class.
|
||||
// 2. `class_addMethod(cls, sel_hello, IMP, "v@:")` attaches our sx function as
|
||||
// the `hello` method (type encoding "v@:" = void method(id self, SEL _cmd)).
|
||||
// 3. `objc_registerClassPair(cls)` finalizes it.
|
||||
// 4. `class_createInstance(cls, 0)` returns an `id` for a fresh instance.
|
||||
// 5. typed-cast `objc_msgSend` for `void (id, SEL)` and dispatch `hello`.
|
||||
// If the IMP ran, the global `g_marker` is non-zero and we return it as exit.
|
||||
|
||||
#import "modules/std.sx";
|
||||
#import "modules/std/objc.sx";
|
||||
|
||||
g_marker : s32 = 0;
|
||||
|
||||
// IMP for `hello`. Must use C calling convention so `self` and `_cmd` land in
|
||||
// x0 and x1 the way the Obj-C runtime expects.
|
||||
hello_imp :: (self: *void, _cmd: *void) callconv(.c) {
|
||||
g_marker = 42;
|
||||
}
|
||||
|
||||
main :: () -> s32 {
|
||||
NSObject := objc_getClass("NSObject".ptr);
|
||||
SxThing := objc_allocateClassPair(NSObject, "SxThing".ptr, 0);
|
||||
sel_hello := sel_registerName("hello".ptr);
|
||||
|
||||
ok := class_addMethod(SxThing, sel_hello, xx hello_imp, "v@:".ptr);
|
||||
if !ok { return 1; }
|
||||
objc_registerClassPair(SxThing);
|
||||
|
||||
obj := class_createInstance(SxThing, 0);
|
||||
if obj == xx 0 { return 2; }
|
||||
|
||||
// [obj hello]
|
||||
msg : (*void, *void) -> void = xx objc_msgSend;
|
||||
msg(obj, sel_hello);
|
||||
|
||||
return g_marker; // 42 if hello_imp ran
|
||||
}
|
||||
41
examples/63-uikit-app.sx
Normal file
41
examples/63-uikit-app.sx
Normal file
@@ -0,0 +1,41 @@
|
||||
// Minimal iOS app entry point — pure sx, no .m files.
|
||||
//
|
||||
// 1. Register a class `SxAppDelegate : UIResponder <UIApplicationDelegate>`
|
||||
// dynamically, with one method:
|
||||
// application:didFinishLaunchingWithOptions: returns YES (BOOL 1).
|
||||
// 2. Call UIApplicationMain(0, null, null, @"SxAppDelegate") to hand off to
|
||||
// UIKit's run loop. This blocks until the app exits.
|
||||
//
|
||||
// After install + launch, the simulator shows the default black screen
|
||||
// (UIWindow not created — that's 5.8) and the AppDelegate callback fires
|
||||
// once at startup. The process stays alive because UIApplicationMain
|
||||
// drives the iOS run loop.
|
||||
|
||||
#import "modules/std.sx";
|
||||
#import "modules/std/uikit.sx";
|
||||
|
||||
// IMP for application:didFinishLaunchingWithOptions:
|
||||
// Obj-C: -(BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)opts
|
||||
// Type encoding: "c@:@@" -- BOOL (signed char), self, _cmd, id, id
|
||||
did_finish_launching :: (self: *void, _cmd: *void, app: *void, opts: *void) -> u8 callconv(.c) {
|
||||
NSLog(ns_string("[sx] application:didFinishLaunchingWithOptions: called\n".ptr));
|
||||
return 1; // YES
|
||||
}
|
||||
|
||||
main :: () -> s32 {
|
||||
// SxAppDelegate : UIResponder. We deliberately don't try
|
||||
// `class_addProtocol(UIApplicationDelegate)` — the linker dead-strips the
|
||||
// protocol metadata from UIKit when nothing references it at compile
|
||||
// time, and the C runtime can't look it up by name. UIApplicationMain
|
||||
// duck-types on the method name, so this works without formal conformance.
|
||||
UIResponder := objc_getClass("UIResponder".ptr);
|
||||
SxAppDelegate := objc_allocateClassPair(UIResponder, "SxAppDelegate".ptr, 0);
|
||||
|
||||
sel := sel_registerName("application:didFinishLaunchingWithOptions:".ptr);
|
||||
class_addMethod(SxAppDelegate, sel, xx did_finish_launching, "c@:@@".ptr);
|
||||
|
||||
objc_registerClassPair(SxAppDelegate);
|
||||
|
||||
// Hand off to the iOS run loop. Never returns under normal operation.
|
||||
return UIApplicationMain(0, xx 0, xx 0, ns_string("SxAppDelegate".ptr));
|
||||
}
|
||||
94
examples/64-uikit-window.sx
Normal file
94
examples/64-uikit-window.sx
Normal file
@@ -0,0 +1,94 @@
|
||||
// Show something on screen — a UIWindow with a colored UIViewController root.
|
||||
//
|
||||
// Builds on 5.7's AppDelegate. Inside `didFinishLaunching`, we:
|
||||
// 1. [[UIWindow alloc] initWithFrame:CGRect]
|
||||
// 2. [[UIViewController alloc] init]; set view.backgroundColor
|
||||
// 3. window.rootViewController = vc
|
||||
// 4. [window makeKeyAndVisible]
|
||||
//
|
||||
// We hardcode the frame to 1024×1024 to avoid the struct-return ABI of
|
||||
// `[UIScreen mainScreen].bounds` for now — any frame bigger than the device
|
||||
// covers the screen, modulo safe-area insets.
|
||||
//
|
||||
// `g_window` is a module-level global so the window outlives the IMP scope
|
||||
// (no ARC; UIKit retains it as the key window anyway).
|
||||
|
||||
#import "modules/std.sx";
|
||||
#import "modules/std/uikit.sx";
|
||||
|
||||
g_window : *void = ---;
|
||||
|
||||
// AppDelegate's `window` property. iOS queries this getter to discover the
|
||||
// app's key window; without it, the legacy code path creates its own empty
|
||||
// window and ignores anything we configure.
|
||||
window_getter :: (self: *void, _cmd: *void) -> *void callconv(.c) {
|
||||
return g_window;
|
||||
}
|
||||
window_setter :: (self: *void, _cmd: *void, w: *void) callconv(.c) {
|
||||
g_window = w;
|
||||
}
|
||||
|
||||
did_finish_launching :: (self: *void, _cmd: *void, app: *void, opts: *void) -> u8 callconv(.c) {
|
||||
UIWindow := objc_getClass("UIWindow".ptr);
|
||||
UIViewController := objc_getClass("UIViewController".ptr);
|
||||
UIColor := objc_getClass("UIColor".ptr);
|
||||
|
||||
sel_alloc := sel_registerName("alloc".ptr);
|
||||
sel_init := sel_registerName("init".ptr);
|
||||
sel_init_with_scene := sel_registerName("initWithWindowScene:".ptr);
|
||||
sel_view := sel_registerName("view".ptr);
|
||||
sel_system_blue := sel_registerName("systemBlueColor".ptr);
|
||||
sel_set_bg := sel_registerName("setBackgroundColor:".ptr);
|
||||
sel_set_root_vc := sel_registerName("setRootViewController:".ptr);
|
||||
sel_make_key_visible := sel_registerName("makeKeyAndVisible".ptr);
|
||||
sel_connected_scenes := sel_registerName("connectedScenes".ptr);
|
||||
sel_any_object := sel_registerName("anyObject".ptr);
|
||||
|
||||
msg_o : (*void, *void) -> *void = xx objc_msgSend;
|
||||
msg_v : (*void, *void) -> void = xx objc_msgSend;
|
||||
msg_oo : (*void, *void, *void) -> void = xx objc_msgSend;
|
||||
msg_ooo : (*void, *void, *void) -> *void = xx objc_msgSend;
|
||||
|
||||
// Modern iOS path: get the connected windowScene, then construct the
|
||||
// window via initWithWindowScene: so UIKit auto-sizes it and attaches
|
||||
// it to the display in one step.
|
||||
scenes := msg_o(app, sel_connected_scenes);
|
||||
scene := msg_o(scenes, sel_any_object);
|
||||
if scene == xx 0 { NSLog(ns_string("[sx] scene NULL\n".ptr)); return 1; }
|
||||
NSLog(ns_string("[sx] scene: ok\n".ptr));
|
||||
|
||||
win_raw := msg_o(UIWindow, sel_alloc);
|
||||
g_window = msg_ooo(win_raw, sel_init_with_scene, scene);
|
||||
NSLog(ns_string("[sx] window: ok\n".ptr));
|
||||
|
||||
vc_raw := msg_o(UIViewController, sel_alloc);
|
||||
vc := msg_o(vc_raw, sel_init);
|
||||
msg_oo(g_window, sel_set_root_vc, vc);
|
||||
|
||||
blue := msg_o(UIColor, sel_system_blue);
|
||||
view := msg_o(vc, sel_view);
|
||||
msg_oo(view, sel_set_bg, blue);
|
||||
msg_oo(g_window, sel_set_bg, blue);
|
||||
|
||||
msg_v(g_window, sel_make_key_visible);
|
||||
NSLog(ns_string("[sx] makeKeyAndVisible done\n".ptr));
|
||||
return 1;
|
||||
}
|
||||
|
||||
main :: () -> s32 {
|
||||
UIResponder := objc_getClass("UIResponder".ptr);
|
||||
SxAppDelegate := objc_allocateClassPair(UIResponder, "SxAppDelegate".ptr, 0);
|
||||
|
||||
class_addMethod(SxAppDelegate,
|
||||
sel_registerName("application:didFinishLaunchingWithOptions:".ptr),
|
||||
xx did_finish_launching, "c@:@@".ptr);
|
||||
class_addMethod(SxAppDelegate,
|
||||
sel_registerName("window".ptr),
|
||||
xx window_getter, "@@:".ptr);
|
||||
class_addMethod(SxAppDelegate,
|
||||
sel_registerName("setWindow:".ptr),
|
||||
xx window_setter, "v@:@".ptr);
|
||||
|
||||
objc_registerClassPair(SxAppDelegate);
|
||||
return UIApplicationMain(0, xx 0, xx 0, ns_string("SxAppDelegate".ptr));
|
||||
}
|
||||
20
examples/65-add-framework.sx
Normal file
20
examples/65-add-framework.sx
Normal file
@@ -0,0 +1,20 @@
|
||||
// BuildOptions.add_framework registers an Apple framework at comptime,
|
||||
// equivalent to a top-level `#framework "Name"` directive. The advantage:
|
||||
// you can gate it with `inline if OS == .ios { ... }` or similar logic,
|
||||
// keeping the framework off non-Apple builds.
|
||||
|
||||
#import "modules/std.sx";
|
||||
#import "modules/compiler.sx";
|
||||
|
||||
configure_build :: () {
|
||||
opts := build_options();
|
||||
opts.add_framework("CoreFoundation");
|
||||
}
|
||||
#run configure_build();
|
||||
|
||||
CFAbsoluteTimeGetCurrent :: () -> f64 #foreign;
|
||||
|
||||
main :: () -> s32 {
|
||||
t := CFAbsoluteTimeGetCurrent();
|
||||
return if t > 0.0 then 0 else 1;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
OperatingSystem :: enum { macos; linux; windows; wasm; unknown; }
|
||||
OperatingSystem :: enum { macos; linux; windows; wasm; ios; unknown; }
|
||||
Architecture :: enum { aarch64; x86_64; wasm32; wasm64; unknown; }
|
||||
|
||||
OS : OperatingSystem = .unknown;
|
||||
@@ -7,6 +7,7 @@ POINTER_SIZE : s64 = 8;
|
||||
|
||||
BuildOptions :: struct {
|
||||
add_link_flag :: (self: BuildOptions, flag: [:0]u8) #compiler;
|
||||
add_framework :: (self: BuildOptions, name: [:0]u8) #compiler;
|
||||
set_output_path :: (self: BuildOptions, path: [:0]u8) #compiler;
|
||||
set_wasm_shell :: (self: BuildOptions, path: [:0]u8) #compiler;
|
||||
}
|
||||
|
||||
75
examples/modules/std/objc.sx
Normal file
75
examples/modules/std/objc.sx
Normal file
@@ -0,0 +1,75 @@
|
||||
// Obj-C runtime FFI primitives.
|
||||
//
|
||||
// `*void` stands in for the Obj-C `id`/`Class`/`SEL` types. There's no
|
||||
// sx-level type alias yet, so naming discipline at call sites is the only
|
||||
// thing keeping them apart.
|
||||
//
|
||||
// objc_msgSend has the standard ARM64 calling convention (no varargs path).
|
||||
// Each call site must invoke through a function pointer of the *exact*
|
||||
// argument and return shape. The idiom:
|
||||
//
|
||||
// msg_fn : (recv: *void, sel: *void, arg: [*]u8) -> *void = xx objc_msgSend;
|
||||
// result := msg_fn(receiver, selector, c_string);
|
||||
|
||||
// On macOS libobjc is auto-loaded by libSystem; on iOS it isn't, so we
|
||||
// link it explicitly. Foundation registers NSString etc. with the runtime,
|
||||
// also auto-loaded on macOS and required as an explicit framework on iOS.
|
||||
objc :: #library "objc";
|
||||
#framework "Foundation";
|
||||
|
||||
objc_getClass :: (name: [*]u8) -> *void #foreign objc;
|
||||
objc_lookUpClass :: (name: [*]u8) -> *void #foreign objc;
|
||||
sel_registerName :: (name: [*]u8) -> *void #foreign objc;
|
||||
class_createInstance :: (cls: *void, extra: usize) -> *void #foreign objc;
|
||||
object_getClass :: (obj: *void) -> *void #foreign objc;
|
||||
|
||||
// Declared with the simplest non-variadic shape. Cast per call site.
|
||||
objc_msgSend :: (recv: *void, sel: *void) -> *void #foreign objc;
|
||||
|
||||
// ─── Dynamic class registration ─────────────────────────────────────────
|
||||
// Define a new Obj-C class at runtime: allocate the pair, attach methods +
|
||||
// protocols, then finalize with `objc_registerClassPair`. The class is then
|
||||
// usable via `class_createInstance` and Obj-C dispatch.
|
||||
//
|
||||
// IMPs (method implementations) are function pointers with the implicit
|
||||
// Obj-C method shape: `(self: *void, _cmd: *void, ...args) -> ret` with
|
||||
// `callconv(.c)` so they land args in the standard C registers.
|
||||
//
|
||||
// Method type encoding strings follow Apple's runtime DSL:
|
||||
// v = void c = char/BOOL i = int l = long f = float d = double
|
||||
// @ = id (object) : = SEL # = Class
|
||||
// Return type comes first, then receiver (`@`), then `_cmd` (`:`), then args.
|
||||
// Examples:
|
||||
// "v@:" -> void method(id, SEL)
|
||||
// "c@:" -> BOOL method(id, SEL)
|
||||
// "@@:@" -> id method(id, SEL, id)
|
||||
// "B@:@@" -> BOOL method(id, SEL, id, id)
|
||||
objc_allocateClassPair :: (super: *void, name: [*]u8, extra: usize) -> *void #foreign objc;
|
||||
class_addMethod :: (cls: *void, sel: *void, imp: *void, types: [*]u8) -> bool #foreign objc;
|
||||
class_addProtocol :: (cls: *void, proto: *void) -> bool #foreign objc;
|
||||
objc_getProtocol :: (name: [*]u8) -> *void #foreign objc;
|
||||
objc_registerClassPair :: (cls: *void) -> void #foreign objc;
|
||||
|
||||
// Foundation C-API helpers (Foundation is already linked above via #framework).
|
||||
// NSLog takes an NSString format; the variadic tail is not exposed here.
|
||||
NSLog :: (fmt: *void) #foreign;
|
||||
|
||||
// ─── Convenience helpers ────────────────────────────────────────────────
|
||||
// These hide the typed-fn-pointer cast for the most common shapes. They
|
||||
// re-register selectors per call — if you're in a tight loop, cache the SEL.
|
||||
|
||||
// Wrap a C string in an autoreleased NSString.
|
||||
ns_string :: (s: [*]u8) -> *void {
|
||||
cls := objc_getClass("NSString".ptr);
|
||||
sel := sel_registerName("stringWithUTF8String:".ptr);
|
||||
fn_ptr : (*void, *void, [*]u8) -> *void = xx objc_msgSend;
|
||||
return fn_ptr(cls, sel, s);
|
||||
}
|
||||
|
||||
// View an NSString's bytes as a C string. The returned pointer's lifetime is
|
||||
// tied to the NSString; don't free it.
|
||||
c_string :: (ns: *void) -> [*]u8 {
|
||||
sel := sel_registerName("UTF8String".ptr);
|
||||
fn_ptr : (*void, *void) -> [*]u8 = xx objc_msgSend;
|
||||
return fn_ptr(ns, sel);
|
||||
}
|
||||
17
examples/modules/std/uikit.sx
Normal file
17
examples/modules/std/uikit.sx
Normal file
@@ -0,0 +1,17 @@
|
||||
// UIKit framework bindings — iOS only.
|
||||
//
|
||||
// Consumers `#import "modules/std/uikit.sx";` and inherit the
|
||||
// `#framework "UIKit"` link directive plus any C-API declarations exposed
|
||||
// here. Obj-C class/method dispatch goes through `modules/std/objc.sx`
|
||||
// which we re-import so users only need this one file.
|
||||
|
||||
#import "objc.sx";
|
||||
|
||||
#framework "UIKit";
|
||||
|
||||
// int UIApplicationMain(int argc, char *_Nullable argv[_Nonnull],
|
||||
// NSString *_Nullable principalClassName,
|
||||
// NSString *_Nullable delegateClassName);
|
||||
//
|
||||
// Blocks. Drives the iOS run loop. Normally never returns.
|
||||
UIApplicationMain :: (argc: s32, argv: *void, principal_class: *void, delegate_class: *void) -> s32 #foreign;
|
||||
Reference in New Issue
Block a user