Browse Source

Add more objc attributes

gingerBill 3 years ago
parent
commit
f8afda3b22

+ 25 - 11
core/sys/darwin/Foundation/NSArray.odin

@@ -3,26 +3,40 @@ package objc_Foundation
 import "core:intrinsics"
 
 @(objc_class="NSArray")
-Array :: struct($T: typeid) where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object) {
-	using _: Copying(Array(T)),
+Array :: struct {
+	using _: Copying(Array),
 }
 
-Array_initWithObjects :: proc(self: ^$A/Array($T), objects: [^]^Object, count: UInteger) -> ^A {
-	return msgSend(^A, "initWithObjects:count:", objects, count)
+@(objc_type=Array, objc_class_name="alloc")
+Array_alloc :: proc() -> ^Array {
+	return msgSend(^Array, Array, "alloc")
 }
 
-Array_initWithCoder :: proc(self: ^$A/Array($T), coder: ^Coder) -> ^A {
-	return msgSend(^A, "initWithCoder:", coder)
+@(objc_type=Array, objc_name="init")
+Array_init :: proc(self: ^Array) -> ^Array {
+	return msgSend(^Array, self, "init")
 }
 
-Array_objectAtIndex :: proc(self: ^Array($T), index: UInteger) -> ^Object {
-	return msgSend(^Object, self, "objectAtIndex:", index)
+@(objc_type=Array, objc_name="initWithObjects")
+Array_initWithObjects :: proc(self: ^Array, objects: [^]^Object, count: UInteger) -> ^Array {
+	return msgSend(^Array, self, "initWithObjects:count:", objects, count)
+}
+
+@(objc_type=Array, objc_name="initWithCoder")
+Array_initWithCoder :: proc(self: ^Array, coder: ^Coder) -> ^Array {
+	return msgSend(^Array, self, "initWithCoder:", coder)
 }
 
-Array_object :: proc(self: ^Array($T), index: UInteger) -> T {
-	return (T)(Array_objectAtIndex(self, index))
+@(objc_type=Array, objc_name="object")
+Array_object :: proc(self: ^Array, index: UInteger) -> ^Object {
+	return msgSend(^Object, self, "objectAtIndex:", index)
+}
+@(objc_type=Array, objc_name="objectAs")
+Array_objectAs :: proc(self: ^Array, index: UInteger, $T: typeid) -> T where intrinsics.type_is_pointer(T), intrinsics.type_is_subtype_of(T, ^Object)  {
+	return (T)(Array_object(self, index))
 }
 
-Array_count :: proc(self: ^Array($T)) -> UInteger {
+@(objc_type=Array, objc_name="count")
+Array_count :: proc(self: ^Array) -> UInteger {
 	return msgSend(UInteger, self, "count")
 }

+ 14 - 1
core/sys/darwin/Foundation/NSAutoreleasePool.odin

@@ -3,12 +3,25 @@ package objc_Foundation
 @(objc_class="NSAutoreleasePool")
 AutoreleasePool :: struct {using _: Object}
 
+@(objc_type=AutoreleasePool, objc_class_name="alloc")
+AutoreleasePool_alloc :: proc() -> ^AutoreleasePool {
+	return msgSend(^AutoreleasePool, AutoreleasePool, "alloc")
+}
+
+@(objc_type=AutoreleasePool, objc_name="init")
+AutoreleasePool_init :: proc(self: ^AutoreleasePool) -> ^AutoreleasePool {
+	return msgSend(^AutoreleasePool, self, "init")
+}
+
+@(objc_type=AutoreleasePool, objc_name="drain")
 AutoreleasePool_drain :: proc(self: ^AutoreleasePool) {
 	msgSend(nil, self, "drain")
 }
+@(objc_type=AutoreleasePool, objc_name="addObject")
 AutoreleasePool_addObject :: proc(self: ^AutoreleasePool, obj: ^Object) {
 	msgSend(nil, self, "addObject:", obj)
 }
+@(objc_type=AutoreleasePool, objc_name="showPools")
 AutoreleasePool_showPools :: proc(self: ^AutoreleasePool, obj: ^Object) {
 	msgSend(nil, self, "showPools")
 }
@@ -16,5 +29,5 @@ AutoreleasePool_showPools :: proc(self: ^AutoreleasePool, obj: ^Object) {
 
 @(deferred_out=AutoreleasePool_drain)
 scoped_autoreleasepool :: proc() -> ^AutoreleasePool {
-	return init(alloc(AutoreleasePool))
+	return AutoreleasePool.alloc()->init()
 }

+ 46 - 10
core/sys/darwin/Foundation/NSBundle.odin

@@ -3,98 +3,120 @@ package objc_Foundation
 @(objc_class="NSBundle")
 Bundle :: struct { using _: Object }
 
+@(objc_type=Bundle, objc_class_name="mainBundle")
 Bundle_mainBundle :: proc() -> ^Bundle {
 	return msgSend(^Bundle, Bundle, "mainBundle")
 }
 
+@(objc_type=Bundle, objc_class_name="bundleWithPath")
 Bundle_bundleWithPath :: proc(path: ^String) -> ^Bundle {
 	return msgSend(^Bundle, Bundle, "bundleWithPath:", path)
 }
 
+@(objc_type=Bundle, objc_class_name="bundleWithURL")
 Bundle_bundleWithURL :: proc(url: ^URL) -> ^Bundle {
 	return msgSend(^Bundle, Bundle, "bundleWithUrl:", url)
 }
-Bundle_bundle :: proc{
-	Bundle_bundleWithPath,
-	Bundle_bundleWithURL,
+
+
+@(objc_type=Bundle, objc_class_name="alloc")
+Bundle_alloc :: proc() -> ^Bundle {
+	return msgSend(^Bundle, Bundle, "alloc")
 }
 
+@(objc_type=Bundle, objc_name="init")
+Bundle_init :: proc(self: ^Bundle) -> ^Bundle {
+	return msgSend(^Bundle, self, "init")
+}
 
+@(objc_type=Bundle, objc_name="initWithPath")
 Bundle_initWithPath :: proc(self: ^Bundle, path: ^String) -> ^Bundle {
 	return msgSend(^Bundle, self, "initWithPath:", path)
 }
 
+@(objc_type=Bundle, objc_name="initWithURL")
 Bundle_initWithURL :: proc(self: ^Bundle, url: ^URL) -> ^Bundle {
 	return msgSend(^Bundle, self, "initWithUrl:", url)
 }
-Bundle_init :: proc{
-	Bundle_initWithPath,
-	Bundle_initWithURL,
-}
-
 
-Bundle_allBundles :: proc() -> (all: ^Array(^Bundle)) {
+@(objc_type=Bundle, objc_name="allBundles")
+Bundle_allBundles :: proc() -> (all: ^Array) {
 	return msgSend(type_of(all), Bundle, "allBundles")
 }
 
-Bundle_allFrameworks :: proc() -> (all: ^Array(^Object)) {
+@(objc_type=Bundle, objc_name="allFrameworks")
+Bundle_allFrameworks :: proc() -> (all: ^Array) {
 	return msgSend(type_of(all), Bundle, "allFrameworks")
 }
 
+@(objc_type=Bundle, objc_name="load")
 Bundle_load :: proc(self: ^Bundle) -> BOOL {
 	return msgSend(BOOL, self, "load")
 }
+@(objc_type=Bundle, objc_name="unload")
 Bundle_unload :: proc(self: ^Bundle) -> BOOL {
 	return msgSend(BOOL, self, "unload")
 }
 
+@(objc_type=Bundle, objc_name="isLoaded")
 Bundle_isLoaded :: proc(self: ^Bundle) -> BOOL {
 	return msgSend(BOOL, self, "isLoaded")
 }
 
+@(objc_type=Bundle, objc_name="preflightAndReturnError")
 Bundle_preflightAndReturnError :: proc(self: ^Bundle) -> (ok: BOOL, error: ^Error) {
 	ok = msgSend(BOOL, self, "preflightAndReturnError:", &error)
 	return
 }
 
+@(objc_type=Bundle, objc_name="loadAndReturnError")
 Bundle_loadAndReturnError :: proc(self: ^Bundle) -> (ok: BOOL, error: ^Error) {
 	ok = msgSend(BOOL, self, "loadAndReturnError:", &error)
 	return
 }
 
+@(objc_type=Bundle, objc_name="bundleURL")
 Bundle_bundleURL :: proc(self: ^Bundle) -> ^URL {
 	return msgSend(^URL, self, "bundleURL")
 }
 
+@(objc_type=Bundle, objc_name="resourceURL")
 Bundle_resourceURL :: proc(self: ^Bundle) -> ^URL {
 	return msgSend(^URL, self, "resourceURL")
 }
 
+@(objc_type=Bundle, objc_name="executableURL")
 Bundle_executableURL :: proc(self: ^Bundle) -> ^URL {
 	return msgSend(^URL, self, "executableURL")
 }
 
+@(objc_type=Bundle, objc_name="URLForAuxiliaryExecutable")
 Bundle_URLForAuxiliaryExecutable :: proc(self: ^Bundle, executableName: ^String) -> ^URL {
 	return msgSend(^URL, self, "URLForAuxiliaryExecutable:", executableName)
 }
 
+@(objc_type=Bundle, objc_name="privateFrameworksURL")
 Bundle_privateFrameworksURL :: proc(self: ^Bundle) -> ^URL {
 	return msgSend(^URL, self, "privateFrameworksURL")
 }
 
+@(objc_type=Bundle, objc_name="sharedFrameworksURL")
 Bundle_sharedFrameworksURL :: proc(self: ^Bundle) -> ^URL {
 	return msgSend(^URL, self, "sharedFrameworksURL")
 }
 
 
+@(objc_type=Bundle, objc_name="sharedSupportURL")
 Bundle_sharedSupportURL :: proc(self: ^Bundle) -> ^URL {
 	return msgSend(^URL, self, "sharedSupportURL")
 }
 
+@(objc_type=Bundle, objc_name="builtInPlugInsURL")
 Bundle_builtInPlugInsURL :: proc(self: ^Bundle) -> ^URL {
 	return msgSend(^URL, self, "builtInPlugInsURL")
 }
 
+@(objc_type=Bundle, objc_name="appStoreReceiptURL")
 Bundle_appStoreReceiptURL :: proc(self: ^Bundle) -> ^URL {
 	return msgSend(^URL, self, "appStoreReceiptURL")
 }
@@ -102,60 +124,74 @@ Bundle_appStoreReceiptURL :: proc(self: ^Bundle) -> ^URL {
 
 
 
+@(objc_type=Bundle, objc_name="bundlePath")
 Bundle_bundlePath :: proc(self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "bundlePath")
 }
 
+@(objc_type=Bundle, objc_name="resourcePath")
 Bundle_resourcePath :: proc(self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "resourcePath")
 }
 
+@(objc_type=Bundle, objc_name="executablePath")
 Bundle_executablePath :: proc(self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "executablePath")
 }
 
+@(objc_type=Bundle, objc_name="PathForAuxiliaryExecutable")
 Bundle_PathForAuxiliaryExecutable :: proc(self: ^Bundle, executableName: ^String) -> ^String {
 	return msgSend(^String, self, "PathForAuxiliaryExecutable:", executableName)
 }
 
+@(objc_type=Bundle, objc_name="privateFrameworksPath")
 Bundle_privateFrameworksPath :: proc(self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "privateFrameworksPath")
 }
 
+@(objc_type=Bundle, objc_name="sharedFrameworksPath")
 Bundle_sharedFrameworksPath :: proc(self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "sharedFrameworksPath")
 }
 
 
+@(objc_type=Bundle, objc_name="sharedSupportPath")
 Bundle_sharedSupportPath :: proc(self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "sharedSupportPath")
 }
 
+@(objc_type=Bundle, objc_name="builtInPlugInsPath")
 Bundle_builtInPlugInsPath :: proc(self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "builtInPlugInsPath")
 }
 
+@(objc_type=Bundle, objc_name="appStoreReceiptPath")
 Bundle_appStoreReceiptPath :: proc(self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "appStoreReceiptPath")
 }
 
+@(objc_type=Bundle, objc_name="bundleIdentifier")
 Bundle_bundleIdentifier :: proc(self: ^Bundle) -> ^String {
 	return msgSend(^String, self, "bundleIdentifier")
 }
 
 
+@(objc_type=Bundle, objc_name="infoDictionary")
 Bundle_infoDictionary :: proc(self: ^Bundle) -> ^Dictionary {
 	return msgSend(^Dictionary, self, "infoDictionary")
 }
 
+@(objc_type=Bundle, objc_name="localizedInfoDictionary")
 Bundle_localizedInfoDictionary :: proc(self: ^Bundle) -> ^Dictionary {
 	return msgSend(^Dictionary, self, "localizedInfoDictionary")
 }
 
+@(objc_type=Bundle, objc_name="objectForInfoDictionaryKey")
 Bundle_objectForInfoDictionaryKey :: proc(self: ^Bundle, key: ^String) -> ^Object {
 	return msgSend(^Object, self, "objectForInfoDictionaryKey:", key)
 }
 
+@(objc_type=Bundle, objc_name="localizedStringForKey")
 Bundle_localizedStringForKey :: proc(self: ^Bundle, key: ^String, value: ^String = nil, tableName: ^String = nil) -> ^String {
 	return msgSend(^String, self, "localizedStringForKey:value:table:", key, value, tableName)
 }

+ 12 - 0
core/sys/darwin/Foundation/NSData.odin

@@ -3,10 +3,22 @@ package objc_Foundation
 @(objc_class="NSData")
 Data :: struct {using _: Copying(Data)}
 
+@(objc_type=Data, objc_class_name="alloc")
+Data_alloc :: proc() -> ^Data {
+	return msgSend(^Data, Data, "alloc")
+}
+
+@(objc_type=Data, objc_name="init")
+Data_init :: proc(self: ^Data) -> ^Data {
+	return msgSend(^Data, self, "init")
+}
+
+@(objc_type=Data, objc_name="mutableBytes")
 Data_mutableBytes :: proc(self: ^Data) -> rawptr {
 	return msgSend(rawptr, self, "mutableBytes")
 }
 
+@(objc_type=Data, objc_name="length")
 Data_length :: proc(self: ^Data) -> UInteger {
 	return msgSend(UInteger, self, "length")
 }

+ 12 - 0
core/sys/darwin/Foundation/NSDate.odin

@@ -3,6 +3,18 @@ package objc_Foundation
 @(objc_class="NSDate")
 Date :: struct {using _: Copying(Date)}
 
+@(objc_type=Date, objc_class_name="alloc")
+Date_alloc :: proc() -> ^Date {
+	return msgSend(^Date, Date, "alloc")
+}
+
+@(objc_type=Date, objc_name="init")
+Date_init :: proc(self: ^Date) -> ^Date {
+	return msgSend(^Date, self, "init")
+}
+
+
+@(objc_type=Date, objc_name="dateWithTimeIntervalSinceNow")
 Date_dateWithTimeIntervalSinceNow :: proc(secs: TimeInterval) -> ^Date {
 	return msgSend(^Date, Date, "dateWithTimeIntervalSinceNow:", secs)
 }

+ 18 - 0
core/sys/darwin/Foundation/NSDictionary.odin

@@ -3,31 +3,49 @@ package objc_Foundation
 @(objc_class="NSDictionary")
 Dictionary :: struct {using _: Copying(Dictionary)}
 
+@(objc_type=Dictionary, objc_class_name="dictionary")
 Dictionary_dictionary :: proc() -> ^Dictionary {
 	return msgSend(^Dictionary, Dictionary, "dictionary")
 }
 
+@(objc_type=Dictionary, objc_class_name="dictionaryWithObject")
 Dictionary_dictionaryWithObject :: proc(object: ^Object, forKey: ^Object) -> ^Dictionary {
 	return msgSend(^Dictionary, Dictionary, "dictionaryWithObject:forKey:", object, forKey)
 }
 
+@(objc_type=Dictionary, objc_class_name="dictionaryWithObjects")
 Dictionary_dictionaryWithObjects :: proc(objects: [^]^Object, forKeys: [^]^Object, count: UInteger) -> ^Dictionary {
 	return msgSend(^Dictionary, Dictionary, "dictionaryWithObjects:forKeys:count", objects, forKeys, count)
 }
 
 
+@(objc_type=Dictionary, objc_class_name="alloc")
+Dictionary_alloc :: proc() -> ^Dictionary {
+	return msgSend(^Dictionary, Dictionary, "alloc")
+}
+
+@(objc_type=Dictionary, objc_name="init")
+Dictionary_init :: proc(self: ^Dictionary) -> ^Dictionary {
+	return msgSend(^Dictionary, self, "init")
+}
+
+
+@(objc_type=Dictionary, objc_name="initWithObjects")
 Dictionary_initWithObjects :: proc(self: ^Dictionary, objects: [^]^Object, forKeys: [^]^Object, count: UInteger) -> ^Dictionary {
 	return msgSend(^Dictionary, self, "initWithObjects:forKeys:count", objects, forKeys, count)
 }
 
+@(objc_type=Dictionary, objc_name="objectForKey")
 Dictionary_objectForKey :: proc(self: ^Dictionary, key: ^Object) -> ^Object {
 	return msgSend(^Dictionary, self, "objectForKey:", key)
 }
 
+@(objc_type=Dictionary, objc_name="count")
 Dictionary_count :: proc(self: ^Dictionary) -> UInteger {
 	return msgSend(UInteger, self, "count")
 }
 
+@(objc_type=Dictionary, objc_name="keyEnumerator")
 Dictionary_keyEnumerator :: proc(self: ^Dictionary, $KeyType: typeid) -> (enumerator: ^Enumerator(KeyType)) {
 	return msgSend(type_of(enumerator), self, "keyEnumerator")
 }

+ 14 - 1
core/sys/darwin/Foundation/NSEnumerator.odin

@@ -18,6 +18,19 @@ Enumerator :: struct($T: typeid) where intrinsics.type_is_pointer(T), intrinsics
 	using _: FastEnumeration,
 }
 
+
+@(objc_type=FastEnumeration, objc_class_name="alloc")
+FastEnumeration_alloc :: proc() -> ^FastEnumeration {
+	return msgSend(^FastEnumeration, FastEnumeration, "alloc")
+}
+
+@(objc_type=FastEnumeration, objc_name="init")
+FastEnumeration_init :: proc(self: ^FastEnumeration) -> ^FastEnumeration {
+	return msgSend(^FastEnumeration, self, "init")
+}
+
+
+@(objc_type=FastEnumeration, objc_name="countByEnumerating")
 FastEnumeration_countByEnumerating :: proc(self: ^FastEnumeration, state: ^FastEnumerationState, buffer: [^]^Object, len: UInteger) -> UInteger {
 	return msgSend(UInteger, self, "countByEnumeratingWithState:objects:count:", state, buffer, len)
 }
@@ -26,7 +39,7 @@ Enumerator_nextObject :: proc(self: ^$E/Enumerator($T)) -> T {
 	return msgSend(T, self, "nextObject")
 }
 
-Enumerator_allObjects :: proc(self: ^$E/Enumerator($T)) -> (all: Array(T)) {
+Enumerator_allObjects :: proc(self: ^$E/Enumerator($T)) -> (all: ^Array) {
 	return msgSend(type_of(all), self, "allObjects")
 }
 

+ 21 - 1
core/sys/darwin/Foundation/NSError.odin

@@ -31,38 +31,58 @@ foreign Foundation {
 @(objc_class="NSError")
 Error :: struct { using _: Copying(Error) }
 
+
+@(objc_type=Error, objc_class_name="alloc")
+Error_alloc :: proc() -> ^Error {
+	return msgSend(^Error, Error, "alloc")
+}
+
+@(objc_type=Error, objc_name="init")
+Error_init :: proc(self: ^Error) -> ^Error {
+	return msgSend(^Error, self, "init")
+}
+
+@(objc_type=Error, objc_class_name="errorWithDomain")
 Error_errorWithDomain :: proc(domain: ErrorDomain, code: Integer, userInfo: ^Dictionary) -> ^Error {
 	return msgSend(^Error, Error, "errorWithDomain:code:userInfo:", domain, code, userInfo)
 }
 
+@(objc_type=Error, objc_name="initWithDomain")
 Error_initWithDomain :: proc(self: ^Error, domain: ErrorDomain, code: Integer, userInfo: ^Dictionary) -> ^Error {
 	return msgSend(^Error, self, "initWithDomain:code:userInfo:", domain, code, userInfo)
 }
 
+@(objc_type=Error, objc_name="code")
 Error_code :: proc(self: ^Error) -> Integer {
 	return msgSend(Integer, self, "code")
 }
 
+@(objc_type=Error, objc_name="domain")
 Error_domain :: proc(self: ^Error) -> ErrorDomain {
 	return msgSend(ErrorDomain, self, "domain")
 }
 
+@(objc_type=Error, objc_name="userInfo")
 Error_userInfo :: proc(self: ^Error) -> ^Dictionary {
 	return msgSend(^Dictionary, self, "userInfo")
 }
 
+@(objc_type=Error, objc_name="localizedDescription")
 Error_localizedDescription :: proc(self: ^Error) -> ^String {
 	return msgSend(^String, self, "localizedDescription")
 }
 
-Error_localizedRecoveryOptions :: proc(self: ^Error) -> (options: ^Array(^Object)) {
+@(objc_type=Error, objc_name="localizedRecoveryOptions")
+Error_localizedRecoveryOptions :: proc(self: ^Error) -> (options: ^Array) {
 	return msgSend(type_of(options), self, "localizedRecoveryOptions")
 }
 
+@(objc_type=Error, objc_name="localizedRecoverySuggestion")
 Error_localizedRecoverySuggestion :: proc(self: ^Error) -> ^String {
 	return msgSend(^String, self, "localizedRecoverySuggestion")
 }
 
+@(objc_type=Error, objc_name="localizedFailureReason")
 Error_localizedFailureReason :: proc(self: ^Error) -> ^String {
 	return msgSend(^String, self, "localizedFailureReason")
 }

+ 24 - 0
core/sys/darwin/Foundation/NSLock.odin

@@ -12,18 +12,42 @@ Locking_unlock :: proc(self: ^Locking($T)) {
 @(objc_class="NSCondition")
 Condition :: struct {using _: Locking(Condition) }
 
+
+@(objc_type=Condition, objc_class_name="alloc")
+Condition_alloc :: proc() -> ^Condition {
+	return msgSend(^Condition, Condition, "alloc")
+}
+
+@(objc_type=Condition, objc_name="init")
+Condition_init :: proc(self: ^Condition) -> ^Condition {
+	return msgSend(^Condition, self, "init")
+}
+
+@(objc_type=Condition, objc_name="wait")
 Condition_wait :: proc(self: ^Condition) {
 	msgSend(nil, self, "wait")
 }
 
+@(objc_type=Condition, objc_name="waitUntilDate")
 Condition_waitUntilDate :: proc(self: ^Condition, limit: ^Date) -> BOOL {
 	return msgSend(BOOL, self, "waitUntilDate:", limit)
 }
 
+@(objc_type=Condition, objc_name="signal")
 Condition_signal :: proc(self: ^Condition) {
 	msgSend(nil, self, "signal")
 }
 
+@(objc_type=Condition, objc_name="broadcast")
 Condition_broadcast :: proc(self: ^Condition) {
 	msgSend(nil, self, "broadcast")
+}
+
+@(objc_type=Condition, objc_name="lock")
+Condition_lock :: proc(self: ^Condition) {
+	msgSend(nil, self, "lock")
+}
+@(objc_type=Condition, objc_name="unlock")
+Condition_unlock :: proc(self: ^Condition) {
+	msgSend(nil, self, "unlock")
 }

+ 15 - 0
core/sys/darwin/Foundation/NSNotification.odin

@@ -3,14 +3,29 @@ package objc_Foundation
 @(objc_class="NSNotification")
 Notification :: struct{using _: Object}
 
+
+@(objc_type=Notification, objc_class_name="alloc")
+Notification_alloc :: proc() -> ^Notification {
+	return msgSend(^Notification, Notification, "alloc")
+}
+
+@(objc_type=Notification, objc_name="init")
+Notification_init :: proc(self: ^Notification) -> ^Notification {
+	return msgSend(^Notification, self, "init")
+}
+
+
+@(objc_type=Notification, objc_name="name")
 Notification_name :: proc(self: ^Notification) -> ^String {
 	return msgSend(^String, self, "name")
 }
 
+@(objc_type=Notification, objc_name="object")
 Notification_object :: proc(self: ^Notification) -> ^Object {
 	return msgSend(^Object, self, "object")
 }
 
+@(objc_type=Notification, objc_name="userInfo")
 Notification_userInfo :: proc(self: ^Notification) -> ^Dictionary {
 	return msgSend(^Dictionary, self, "userInfo")
 }

+ 82 - 67
core/sys/darwin/Foundation/NSNumber.odin

@@ -8,35 +8,53 @@ import "core:c"
 @(objc_class="NSValue")
 Value :: struct{using _: Copying(Value)}
 
+@(objc_type=Value, objc_class_name="alloc")
+Value_alloc :: proc() -> ^Value {
+	return msgSend(^Value, Value, "alloc")
+}
+
+@(objc_type=Value, objc_name="init")
+Value_init :: proc(self: ^Value) -> ^Value {
+	return msgSend(^Value, self, "init")
+}
+
+@(objc_type=Value, objc_class_name="valueWithBytes")
 Value_valueWithBytes :: proc(value: rawptr, type: cstring) -> ^Value {
 	return msgSend(^Value, Value, "valueWithBytes:objCType:", value, type)
 }
 
+@(objc_type=Value, objc_class_name="valueWithPointer")
 Value_valueWithPointer :: proc(pointer: rawptr) -> ^Value {
 	return msgSend(^Value, Value, "valueWithPointer:", pointer)
 }
 
+@(objc_type=Value, objc_name="initWithBytes")
 Value_initWithBytes :: proc(self: ^Value, value: rawptr, type: cstring) -> ^Value {
 	return msgSend(^Value, self, "initWithBytes:objCType:", value, type)
 }
 
-Value_initWithCoder :: proc(coder: ^Coder) -> ^Value {
-	return msgSend(^Value, Value, "initWithCoder:", coder)
+@(objc_type=Value, objc_name="initWithCoder")
+Value_initWithCoder :: proc(self: ^Value, coder: ^Coder) -> ^Value {
+	return msgSend(^Value, self, "initWithCoder:", coder)
 }
 
+@(objc_type=Value, objc_name="getValue")
 Value_getValue :: proc(self: ^Value, value: rawptr, size: UInteger) {
 	msgSend(nil, self, "getValue:size:", value, size)
 }
 
 
+@(objc_type=Value, objc_name="objCType")
 Value_objCType :: proc(self: ^Value) -> cstring {
 	return msgSend(cstring, self, "objCType")
 }
 
+@(objc_type=Value, objc_name="isEqualToValue")
 Value_isEqualToValue :: proc(self, other: ^Value) -> BOOL {
 	return msgSend(BOOL, self, "isEqualToValue:", other)
 }
 
+@(objc_type=Value, objc_name="pointerValue")
 Value_pointerValue :: proc(self: ^Value) -> rawptr {
 	return msgSend(rawptr, self, "pointerValue")
 }
@@ -46,19 +64,29 @@ Value_pointerValue :: proc(self: ^Value) -> rawptr {
 Number :: struct{using _: Copying(Number), using _: Value}
 
 
-Number_numberWithI8   :: proc(value: i8)   -> ^Number { return msgSend(^Number, Number, "numberWithChar:",             value) }
-Number_numberWithU8   :: proc(value: u8)   -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedChar:",     value) }
-Number_numberWithI16  :: proc(value: i16)  -> ^Number { return msgSend(^Number, Number, "numberWithShort:",            value) }
-Number_numberWithU16  :: proc(value: u16)  -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedShort:",    value) }
-Number_numberWithI32  :: proc(value: i32)  -> ^Number { return msgSend(^Number, Number, "numberWithInt:",              value) }
-Number_numberWithU32  :: proc(value: u32)  -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedInt:",      value) }
-Number_numberWithInt  :: proc(value: int)  -> ^Number { return msgSend(^Number, Number, "numberWithLong:",             value) }
-Number_numberWithUint :: proc(value: uint) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLong:",     value) }
-Number_numberWithU64  :: proc(value: u64)  -> ^Number { return msgSend(^Number, Number, "numberWithLongLong:",         value) }
-Number_numberWithI64  :: proc(value: i64)  -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLongLong:", value) }
-Number_numberWithF32  :: proc(value: f32)  -> ^Number { return msgSend(^Number, Number, "numberWithFloat:",            value) }
-Number_numberWithF64  :: proc(value: f64)  -> ^Number { return msgSend(^Number, Number, "numberWithDouble:",           value) }
-Number_numberWithBool :: proc(value: BOOL) -> ^Number { return msgSend(^Number, Number, "numberWithBool:",             value) }
+@(objc_type=Number, objc_class_name="alloc")
+Number_alloc :: proc() -> ^Number {
+	return msgSend(^Number, Number, "alloc")
+}
+
+@(objc_type=Number, objc_name="init")
+Number_init :: proc(self: ^Number) -> ^Number {
+	return msgSend(^Number, self, "init")
+}
+
+@(objc_type=Number, objc_class_name="numberWithI8")   Number_numberWithI8   :: proc(value: i8)   -> ^Number { return msgSend(^Number, Number, "numberWithChar:",             value) }
+@(objc_type=Number, objc_class_name="numberWithU8")   Number_numberWithU8   :: proc(value: u8)   -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedChar:",     value) }
+@(objc_type=Number, objc_class_name="numberWithI16")  Number_numberWithI16  :: proc(value: i16)  -> ^Number { return msgSend(^Number, Number, "numberWithShort:",            value) }
+@(objc_type=Number, objc_class_name="numberWithU16")  Number_numberWithU16  :: proc(value: u16)  -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedShort:",    value) }
+@(objc_type=Number, objc_class_name="numberWithI32")  Number_numberWithI32  :: proc(value: i32)  -> ^Number { return msgSend(^Number, Number, "numberWithInt:",              value) }
+@(objc_type=Number, objc_class_name="numberWithU32")  Number_numberWithU32  :: proc(value: u32)  -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedInt:",      value) }
+@(objc_type=Number, objc_class_name="numberWithInt")  Number_numberWithInt  :: proc(value: int)  -> ^Number { return msgSend(^Number, Number, "numberWithLong:",             value) }
+@(objc_type=Number, objc_class_name="numberWithUint") Number_numberWithUint :: proc(value: uint) -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLong:",     value) }
+@(objc_type=Number, objc_class_name="numberWithU64")  Number_numberWithU64  :: proc(value: u64)  -> ^Number { return msgSend(^Number, Number, "numberWithLongLong:",         value) }
+@(objc_type=Number, objc_class_name="numberWithI64")  Number_numberWithI64  :: proc(value: i64)  -> ^Number { return msgSend(^Number, Number, "numberWithUnsignedLongLong:", value) }
+@(objc_type=Number, objc_class_name="numberWithF32")  Number_numberWithF32  :: proc(value: f32)  -> ^Number { return msgSend(^Number, Number, "numberWithFloat:",            value) }
+@(objc_type=Number, objc_class_name="numberWithF64")  Number_numberWithF64  :: proc(value: f64)  -> ^Number { return msgSend(^Number, Number, "numberWithDouble:",           value) }
+@(objc_type=Number, objc_class_name="numberWithBool") Number_numberWithBool :: proc(value: BOOL) -> ^Number { return msgSend(^Number, Number, "numberWithBool:",             value) }
 
 Number_number :: proc{
 	Number_numberWithI8,
@@ -76,62 +104,49 @@ Number_number :: proc{
 	Number_numberWithBool,
 }
 
-Number_initWithI8   :: proc(self: ^Number, value: i8)   -> ^Number { return msgSend(^Number, self, "initWithChar:",             value) }
-Number_initWithU8   :: proc(self: ^Number, value: u8)   -> ^Number { return msgSend(^Number, self, "initWithUnsignedChar:",     value) }
-Number_initWithI16  :: proc(self: ^Number, value: i16)  -> ^Number { return msgSend(^Number, self, "initWithShort:",            value) }
-Number_initWithU16  :: proc(self: ^Number, value: u16)  -> ^Number { return msgSend(^Number, self, "initWithUnsignedShort:",    value) }
-Number_initWithI32  :: proc(self: ^Number, value: i32)  -> ^Number { return msgSend(^Number, self, "initWithInt:",              value) }
-Number_initWithU32  :: proc(self: ^Number, value: u32)  -> ^Number { return msgSend(^Number, self, "initWithUnsignedInt:",      value) }
-Number_initWithInt  :: proc(self: ^Number, value: int)  -> ^Number { return msgSend(^Number, self, "initWithLong:",             value) }
-Number_initWithUint :: proc(self: ^Number, value: uint) -> ^Number { return msgSend(^Number, self, "initWithUnsignedLong:",     value) }
-Number_initWithU64  :: proc(self: ^Number, value: u64)  -> ^Number { return msgSend(^Number, self, "initWithLongLong:",         value) }
-Number_initWithI64  :: proc(self: ^Number, value: i64)  -> ^Number { return msgSend(^Number, self, "initWithUnsignedLongLong:", value) }
-Number_initWithF32  :: proc(self: ^Number, value: f32)  -> ^Number { return msgSend(^Number, self, "initWithFloat:",            value) }
-Number_initWithF64  :: proc(self: ^Number, value: f64)  -> ^Number { return msgSend(^Number, self, "initWithDouble:",           value) }
-Number_initWithBool :: proc(self: ^Number, value: BOOL) -> ^Number { return msgSend(^Number, self, "initWithBool:",             value) }
-
-
-Number_init :: proc{
-	Number_initWithI8,
-	Number_initWithU8,
-	Number_initWithI16,
-	Number_initWithU16,
-	Number_initWithI32,
-	Number_initWithU32,
-	Number_initWithInt,
-	Number_initWithUint,
-	Number_initWithU64,
-	Number_initWithI64,
-	Number_initWithF32,
-	Number_initWithF64,
-	Number_initWithBool,
-}
-
-Number_i8Value       :: proc(self: ^Number) -> i8          { return msgSend(i8,          self, "charValue")             }
-Number_u8Value       :: proc(self: ^Number) -> u8          { return msgSend(u8,          self, "unsignedCharValue")     }
-Number_i16Value      :: proc(self: ^Number) -> i16         { return msgSend(i16,         self, "shortValue")            }
-Number_u16Value      :: proc(self: ^Number) -> u16         { return msgSend(u16,         self, "unsignedShortValue")    }
-Number_i32Value      :: proc(self: ^Number) -> i32         { return msgSend(i32,         self, "intValue")              }
-Number_u32Value      :: proc(self: ^Number) -> u32         { return msgSend(u32,         self, "unsignedIntValue")      }
-Number_intValue      :: proc(self: ^Number) -> int         { return msgSend(int,         self, "longValue")             }
-Number_uintValue     :: proc(self: ^Number) -> uint        { return msgSend(uint,        self, "unsignedLongValue")     }
-Number_u64Value      :: proc(self: ^Number) -> u64         { return msgSend(u64,         self, "longLongValue")         }
-Number_i64Value      :: proc(self: ^Number) -> i64         { return msgSend(i64,         self, "unsignedLongLongValue") }
-Number_f32Value      :: proc(self: ^Number) -> f32         { return msgSend(f32,         self, "floatValue")            }
-Number_f64Value      :: proc(self: ^Number) -> f64         { return msgSend(f64,         self, "doubleValue")           }
-Number_boolValue     :: proc(self: ^Number) -> BOOL        { return msgSend(BOOL,        self, "boolValue")             }
-Number_integerValue  :: proc(self: ^Number) -> Integer     { return msgSend(Integer,     self, "integerValue")          }
-Number_uintegerValue :: proc(self: ^Number) -> UInteger    { return msgSend(UInteger,    self, "unsignedIntegerValue")  }
-Number_stringValue   :: proc(self: ^Number) -> ^String     { return msgSend(^String,     self, "stringValue")           }
-
-Number_compare :: proc(a, b: ^Number) -> ComparisonResult {
-	return msgSend(ComparisonResult, a, "compare:", b)
+@(objc_type=Number, objc_name="initWithI8")    Number_initWithI8   :: proc(self: ^Number, value: i8)   -> ^Number { return msgSend(^Number, self, "initWithChar:",             value) }
+@(objc_type=Number, objc_name="initWithU8")    Number_initWithU8   :: proc(self: ^Number, value: u8)   -> ^Number { return msgSend(^Number, self, "initWithUnsignedChar:",     value) }
+@(objc_type=Number, objc_name="initWithI16")   Number_initWithI16  :: proc(self: ^Number, value: i16)  -> ^Number { return msgSend(^Number, self, "initWithShort:",            value) }
+@(objc_type=Number, objc_name="initWithU16")   Number_initWithU16  :: proc(self: ^Number, value: u16)  -> ^Number { return msgSend(^Number, self, "initWithUnsignedShort:",    value) }
+@(objc_type=Number, objc_name="initWithI32")   Number_initWithI32  :: proc(self: ^Number, value: i32)  -> ^Number { return msgSend(^Number, self, "initWithInt:",              value) }
+@(objc_type=Number, objc_name="initWithU32")   Number_initWithU32  :: proc(self: ^Number, value: u32)  -> ^Number { return msgSend(^Number, self, "initWithUnsignedInt:",      value) }
+@(objc_type=Number, objc_name="initWithInt")   Number_initWithInt  :: proc(self: ^Number, value: int)  -> ^Number { return msgSend(^Number, self, "initWithLong:",             value) }
+@(objc_type=Number, objc_name="initWithUint")  Number_initWithUint :: proc(self: ^Number, value: uint) -> ^Number { return msgSend(^Number, self, "initWithUnsignedLong:",     value) }
+@(objc_type=Number, objc_name="initWithU64")   Number_initWithU64  :: proc(self: ^Number, value: u64)  -> ^Number { return msgSend(^Number, self, "initWithLongLong:",         value) }
+@(objc_type=Number, objc_name="initWithI64")   Number_initWithI64  :: proc(self: ^Number, value: i64)  -> ^Number { return msgSend(^Number, self, "initWithUnsignedLongLong:", value) }
+@(objc_type=Number, objc_name="initWithF32")   Number_initWithF32  :: proc(self: ^Number, value: f32)  -> ^Number { return msgSend(^Number, self, "initWithFloat:",            value) }
+@(objc_type=Number, objc_name="initWithF64")   Number_initWithF64  :: proc(self: ^Number, value: f64)  -> ^Number { return msgSend(^Number, self, "initWithDouble:",           value) }
+@(objc_type=Number, objc_name="initWithBool")  Number_initWithBool :: proc(self: ^Number, value: BOOL) -> ^Number { return msgSend(^Number, self, "initWithBool:",             value) }
+
+
+@(objc_type=Number, objc_name="i8Value")       Number_i8Value       :: proc(self: ^Number) -> i8          { return msgSend(i8,          self, "charValue")             }
+@(objc_type=Number, objc_name="u8Value")       Number_u8Value       :: proc(self: ^Number) -> u8          { return msgSend(u8,          self, "unsignedCharValue")     }
+@(objc_type=Number, objc_name="i16Value")      Number_i16Value      :: proc(self: ^Number) -> i16         { return msgSend(i16,         self, "shortValue")            }
+@(objc_type=Number, objc_name="u16Value")      Number_u16Value      :: proc(self: ^Number) -> u16         { return msgSend(u16,         self, "unsignedShortValue")    }
+@(objc_type=Number, objc_name="i32Value")      Number_i32Value      :: proc(self: ^Number) -> i32         { return msgSend(i32,         self, "intValue")              }
+@(objc_type=Number, objc_name="u32Value")      Number_u32Value      :: proc(self: ^Number) -> u32         { return msgSend(u32,         self, "unsignedIntValue")      }
+@(objc_type=Number, objc_name="intValue")      Number_intValue      :: proc(self: ^Number) -> int         { return msgSend(int,         self, "longValue")             }
+@(objc_type=Number, objc_name="uintValue")     Number_uintValue     :: proc(self: ^Number) -> uint        { return msgSend(uint,        self, "unsignedLongValue")     }
+@(objc_type=Number, objc_name="u64Value")      Number_u64Value      :: proc(self: ^Number) -> u64         { return msgSend(u64,         self, "longLongValue")         }
+@(objc_type=Number, objc_name="i64Value")      Number_i64Value      :: proc(self: ^Number) -> i64         { return msgSend(i64,         self, "unsignedLongLongValue") }
+@(objc_type=Number, objc_name="f32Value")      Number_f32Value      :: proc(self: ^Number) -> f32         { return msgSend(f32,         self, "floatValue")            }
+@(objc_type=Number, objc_name="f64Value")      Number_f64Value      :: proc(self: ^Number) -> f64         { return msgSend(f64,         self, "doubleValue")           }
+@(objc_type=Number, objc_name="boolValue")     Number_boolValue     :: proc(self: ^Number) -> BOOL        { return msgSend(BOOL,        self, "boolValue")             }
+@(objc_type=Number, objc_name="integerValue")  Number_integerValue  :: proc(self: ^Number) -> Integer     { return msgSend(Integer,     self, "integerValue")          }
+@(objc_type=Number, objc_name="uintegerValue") Number_uintegerValue :: proc(self: ^Number) -> UInteger    { return msgSend(UInteger,    self, "unsignedIntegerValue")  }
+@(objc_type=Number, objc_name="stringValue")   Number_stringValue   :: proc(self: ^Number) -> ^String     { return msgSend(^String,     self, "stringValue")           }
+
+@(objc_type=Number, objc_name="compare")
+Number_compare :: proc(self, other: ^Number) -> ComparisonResult {
+	return msgSend(ComparisonResult, self, "compare:", other)
 }
 
-Number_isEqualToNumber :: proc(a, b: ^Number) -> BOOL {
-	return msgSend(BOOL, a, "isEqualToNumber:", b)
+@(objc_type=Number, objc_name="isEqualToNumber")
+Number_isEqualToNumber :: proc(self, other: ^Number) -> BOOL {
+	return msgSend(BOOL, self, "isEqualToNumber:", other)
 }
 
+@(objc_type=Number, objc_name="descriptionWithLocale")
 Number_descriptionWithLocale :: proc(self: ^Number, locale: ^Object) -> ^String {
 	return msgSend(^String, self, "descriptionWithLocale:", locale)
 }

+ 18 - 10
core/sys/darwin/Foundation/NSObject.odin

@@ -27,37 +27,45 @@ alloc :: proc($T: typeid) -> ^T where intrinsics.type_is_subtype_of(T, Object) {
 init :: proc(self: ^$T) -> ^T where intrinsics.type_is_subtype_of(T, Object) {
 	return msgSend(^T, self, "init")
 }
-retain :: proc(self: ^$T) -> ^T where intrinsics.type_is_subtype_of(T, Object) {
-	return msgSend(^T, self, "retain")
+copy :: proc(self: ^Copying($T)) -> ^T where intrinsics.type_is_subtype_of(T, Object) {
+	return msgSend(^T, self, "copy")
+}
+
+
+@(objc_type=Object, objc_name="retain")
+retain :: proc(self: ^Object) {
+	_ = msgSend(^Object, self, "retain")
 }
-release :: proc(self: ^$T) where intrinsics.type_is_subtype_of(T, Object) {
+@(objc_type=Object, objc_name="release")
+release :: proc(self: ^Object) {
 	msgSend(nil, self, "release")
 }
-autorelease :: proc(self: ^$T) where intrinsics.type_is_subtype_of(T, Object) {
+@(objc_type=Object, objc_name="autorelease")
+autorelease :: proc(self: ^Object) {
 	msgSend(nil, self, "autorelease")
 }
-retainCount :: proc(self: ^$T) -> UInteger where intrinsics.type_is_subtype_of(T, Object) {
+@(objc_type=Object, objc_name="retainCount")
+retainCount :: proc(self: ^Object) -> UInteger {
 	return msgSend(UInteger, self, "retainCount")
 }
 
 
-copy :: proc(self: ^Copying($T)) -> ^T where intrinsics.type_is_subtype_of(T, Object) {
-	return msgSend(^T, self, "copy")
-}
-
-
+@(objc_type=Object, objc_name="hash")
 hash :: proc(self: ^Object) -> UInteger {
 	return msgSend(UInteger, self, "hash")
 }
 
+@(objc_type=Object, objc_name="isEqual")
 isEqual :: proc(self, pObject: ^Object) -> BOOL {
 	return msgSend(BOOL, self, "isEqual:", pObject)
 }
 
+@(objc_type=Object, objc_name="description")
 description :: proc(self: ^Object) -> ^String {
 	return msgSend(^String, self, "description")
 }
 
+@(objc_type=Object, objc_name="debugDescription")
 debugDescription :: proc(self: ^Object) -> ^String {
 	if msgSendSafeCheck(self, intrinsics.objc_selector_name("debugDescription")) {
 		return msgSend(^String, self, "debugDescription")

+ 24 - 0
core/sys/darwin/Foundation/NSString.odin

@@ -59,54 +59,78 @@ MakeConstantString :: proc "c" (#const c: cstring) -> ^String {
 }
 
 
+@(objc_type=String, objc_class_name="alloc")
+String_alloc :: proc() -> ^String {
+	return msgSend(^String, String, "alloc")
+}
+
+@(objc_type=String, objc_name="init")
+String_init :: proc(self: ^String) -> ^String {
+	return msgSend(^String, self, "init")
+}
+
+
+@(objc_type=String, objc_name="initWithString")
 String_initWithString :: proc(self: ^String, other: ^String) -> ^String {
 	return msgSend(^String, self, "initWithString:", other)
 }
 
+@(objc_type=String, objc_name="initWithCString")
 String_initWithCString :: proc(self: ^String, pString: cstring, encoding: StringEncoding) -> ^String {
 	return msgSend(^String, self, "initWithCstring:encoding:", pString, encoding)
 }
 
+@(objc_type=String, objc_name="initWithBytesNoCopy")
 String_initWithBytesNoCopy :: proc(self: ^String, pBytes: rawptr, length: UInteger, encoding: StringEncoding, freeWhenDone: bool) -> ^String {
 	return msgSend(^String, self, "initWithBytesNoCopy:length:encoding:freeWhenDone:", pBytes, length, encoding, freeWhenDone)
 }
 
+@(objc_type=String, objc_name="initWithOdinString")
 String_initWithOdinString :: proc(self: ^String, str: string) -> ^String {
 	return String_initWithBytesNoCopy(self, raw_data(str), UInteger(len(str)), .UTF8, false)
 }
 
+@(objc_type=String, objc_name="characterAtIndex")
 String_characterAtIndex :: proc(self: ^String, index: UInteger) -> unichar {
 	return msgSend(unichar, self, "characterAtIndex:", index)
 }
 
+@(objc_type=String, objc_name="length")
 String_length :: proc(self: ^String) -> UInteger {
 	return msgSend(UInteger, self, "length")
 }
 
+@(objc_type=String, objc_name="cStringUsingEncoding")
 String_cStringUsingEncoding :: proc(self: ^String, encoding: StringEncoding) -> cstring {
 	return msgSend(cstring, self, "cStringUsingEncoding:", encoding)
 }
 
+@(objc_type=String, objc_name="UTF8String")
 String_UTF8String :: proc(self: ^String) -> cstring {
 	return msgSend(cstring, self, "UTF8String")
 }
 
+@(objc_type=String, objc_name="OdinString")
 String_OdinString :: proc(self: ^String) -> string {
 	return string(String_UTF8String(self))
 }
 
+@(objc_type=String, objc_name="maximumLengthOfBytesUsingEncoding")
 String_maximumLengthOfBytesUsingEncoding :: proc(self: ^String, encoding: StringEncoding) -> UInteger {
 	return msgSend(UInteger, self, "maximumLengthOfBytesUsingEncoding:", encoding)
 }
 
+@(objc_type=String, objc_name="lengthOfBytesUsingEncoding")
 String_lengthOfBytesUsingEncoding :: proc(self: ^String, encoding: StringEncoding) -> UInteger {
 	return msgSend(UInteger, self, "lengthOfBytesUsingEncoding:", encoding)
 }
 
+@(objc_type=String, objc_name="isEqualToString")
 String_isEqualToString :: proc(self, other: ^String) -> BOOL {
 	return msgSend(BOOL, self, "isEqualToString:", other)
 }
 
+@(objc_type=String, objc_name="rangeOfString")
 String_rangeOfString :: proc(self, other: ^String, options: StringCompareOptions) -> Range {
 	return msgSend(Range, self, "rangeOfString:options:", other, options)
 }

+ 12 - 0
core/sys/darwin/Foundation/NSURL.odin

@@ -3,6 +3,18 @@ package objc_Foundation
 @(objc_class="NSURL")
 URL :: struct{using _: Copying(URL)}
 
+
+@(objc_type=URL, objc_class_name="alloc")
+URL_alloc :: proc() -> ^URL {
+	return msgSend(^URL, URL, "alloc")
+}
+
+@(objc_type=URL, objc_name="init")
+URL_init :: proc(self: ^URL) -> ^URL {
+	return msgSend(^URL, self, "init")
+}
+
+
 URL_initWithString :: proc(self: ^URL, value: ^String) -> ^URL {
 	return msgSend(^URL, self, "initWithString:", value)
 }

+ 3 - 5
src/check_builtin.cpp

@@ -287,15 +287,13 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call
 		Operand self = {};
 		check_expr_or_type(c, &self, ce->args[1]);
 		if (self.mode == Addressing_Type) {
-			if (!internal_check_is_assignable_to(self.type, t_objc_object)) {
+			if (!is_type_objc_object(self.type)) {
 				gbString t = type_to_string(self.type);
 				error(self.expr, "'%.*s' expected a type or value derived from intrinsics.objc_object, got type %s", LIT(builtin_name), t);
 				gb_string_free(t);
 				return false;
 			}
-			if (!(self.type->kind == Type_Named &&
-			      self.type->Named.type_name != nullptr &&
-			      self.type->Named.type_name->TypeName.objc_class_name != "")) {
+			if (!has_type_got_objc_class_attribute(self.type)) {
 				gbString t = type_to_string(self.type);
 				error(self.expr, "'%.*s' expected a named type with the attribute @(obj_class=<string>) , got type %s", LIT(builtin_name), t);
 				gb_string_free(t);
@@ -306,7 +304,7 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call
 		} else if (!is_operand_value(self) || !check_is_assignable_to(c, &self, t_objc_id)) {
 			gbString e = expr_to_string(self.expr);
 			gbString t = type_to_string(self.type);
-			error(self.expr, "'%.*s'3 expected a type or value derived from intrinsics.objc_object, got '%s' of type %s %d", LIT(builtin_name), e, t, self.type->kind);
+			error(self.expr, "'%.*s' expected a type or value derived from intrinsics.objc_object, got '%s' of type %s %d", LIT(builtin_name), e, t, self.type->kind);
 			gb_string_free(t);
 			gb_string_free(e);
 			return false;

+ 63 - 0
src/check_decl.cpp

@@ -340,6 +340,10 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def)
 		check_decl_attributes(ctx, decl->attributes, type_decl_attribute, &ac);
 		if (e->kind == Entity_TypeName && ac.objc_class != "") {
 			e->TypeName.objc_class_name = ac.objc_class;
+
+			if (type_size_of(e->type) > 0) {
+				error(e->token, "@(objc_class) marked type must be of zero size");
+			}
 		}
 	}
 
@@ -822,6 +826,65 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
 	}
 	e->Procedure.optimization_mode = cast(ProcedureOptimizationMode)ac.optimization_mode;
 
+	if (ac.objc_name.len || ac.objc_class_name.len || ac.objc_type) {
+		if (ac.objc_class_name.len && ac.objc_name.len) {
+			error(e->token, "@(objc_class_name) and @(objc_name) may not be allowed at the same time");
+		} else if (ac.objc_type == nullptr) {
+			if (ac.objc_name.len) {
+				error(e->token, "@(objc_name) requires that @(objc_type) to be set");
+			} else {
+				error(e->token, "@(objc_class_name) requires that @(objc_type) to be set");
+			}
+		} else {
+			Type *t = ac.objc_type;
+			if (t->kind == Type_Named) {
+				Entity *tn = t->Named.type_name;
+
+				GB_ASSERT(tn->kind == Entity_TypeName);
+
+				if (tn->scope != e->scope) {
+					error(e->token, "@(objc_name) and @(objc_class_name) attributes may only be applied to procedures and types within the same scope");
+				} else {
+					mutex_lock(&global_type_name_objc_metadata_mutex);
+					defer (mutex_unlock(&global_type_name_objc_metadata_mutex));
+
+					if (!tn->TypeName.objc_metadata) {
+						tn->TypeName.objc_metadata = create_type_name_obj_c_metadata();
+					}
+					auto *md = tn->TypeName.objc_metadata;
+					mutex_lock(md->mutex);
+					defer (mutex_unlock(md->mutex));
+
+					if (ac.objc_name.len) {
+						bool ok = true;
+						for (TypeNameObjCMetadataEntry const &entry : md->value_entries) {
+							if (entry.name == ac.objc_name) {
+								error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name));
+								ok = false;
+								break;
+							}
+						}
+						if (ok) {
+							array_add(&md->value_entries, TypeNameObjCMetadataEntry{ac.objc_name, e});
+						}
+					} else {
+						bool ok = true;
+						for (TypeNameObjCMetadataEntry const &entry : md->type_entries) {
+							if (entry.name == ac.objc_class_name) {
+								error(e->token, "Previous declaration of @(objc_class_name=\"%.*s\")", LIT(ac.objc_class_name));
+								ok = false;
+								break;
+							}
+						}
+						if (ok) {
+							array_add(&md->type_entries, TypeNameObjCMetadataEntry{ac.objc_class_name, e});
+						}
+					}
+				}
+			}
+		}
+	}
+
 
 	switch (e->Procedure.optimization_mode) {
 	case ProcedureOptimizationMode_None:

+ 2 - 0
src/check_type.cpp

@@ -325,6 +325,8 @@ void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_t
 	named_type->Named.type_name = e;
 	GB_ASSERT(original_type->kind == Type_Named);
 	e->TypeName.objc_class_name = original_type->Named.type_name->TypeName.objc_class_name;
+	// TODO(bill): Is this even correct? Or should the metadata be copied?
+	e->TypeName.objc_metadata = original_type->Named.type_name->TypeName.objc_metadata;
 
 	mutex_lock(&ctx->info->gen_types_mutex);
 	auto *found_gen_types = map_get(&ctx->info->gen_types, original_type);

+ 49 - 1
src/checker.cpp

@@ -4,7 +4,7 @@
 void check_expr(CheckerContext *c, Operand *operand, Ast *expression);
 void check_expr_or_type(CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint=nullptr);
 void add_comparison_procedures_for_fields(CheckerContext *c, Type *t);
-
+Type *check_type(CheckerContext *ctx, Ast *e);
 
 bool is_operand_value(Operand o) {
 	switch (o.mode) {
@@ -2740,6 +2740,14 @@ ExactValue check_decl_attribute_value(CheckerContext *c, Ast *value) {
 	return ev;
 }
 
+Type *check_decl_attribute_type(CheckerContext *c, Ast *value) {
+	if (value != nullptr) {
+		return check_type(c, value);
+	}
+	return nullptr;
+}
+
+
 #define ATTRIBUTE_USER_TAG_NAME "tag"
 
 
@@ -3039,6 +3047,46 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
 			error(elem, "Expected a string for '%.*s'", LIT(name));
 		}
 		return true;
+	} else if (name == "objc_name") {
+		ExactValue ev = check_decl_attribute_value(c, value);
+		if (ev.kind == ExactValue_String) {
+			if (string_is_valid_identifier(ev.value_string)) {
+				ac->objc_name = ev.value_string;
+			} else {
+				error(elem, "Invalid identifier for '%.*s', got '%.*s'", LIT(name), LIT(ev.value_string));
+			}
+		} else {
+			error(elem, "Expected a string value for '%.*s'", LIT(name));
+		}
+		return true;
+	} else if (name == "objc_class_name") {
+		ExactValue ev = check_decl_attribute_value(c, value);
+		if (ev.kind == ExactValue_String) {
+			if (string_is_valid_identifier(ev.value_string)) {
+				ac->objc_class_name = ev.value_string;
+			} else {
+				error(elem, "Invalid identifier for '%.*s', got '%.*s'", LIT(name), LIT(ev.value_string));
+			}
+		} else {
+			error(elem, "Expected a string value for '%.*s'", LIT(name));
+		}
+		return true;
+	} else if (name == "objc_type") {
+		if (value == nullptr) {
+			error(elem, "Expected a type for '%.*s'", LIT(name));
+		} else {
+			Type *objc_type = check_type(c, value);
+			if (objc_type != nullptr) {
+				if (!has_type_got_objc_class_attribute(objc_type)) {
+					gbString t = type_to_string(objc_type);
+					error(value, "'%.*s' expected a named type with the attribute @(obj_class=<string>), got type %s", LIT(name), t);
+					gb_string_free(t);
+				} else {
+					ac->objc_type = objc_type;
+				}
+			}
+		}
+		return true;
 	}
 	return false;
 }

+ 5 - 1
src/checker.hpp

@@ -107,7 +107,6 @@ struct AttributeContext {
 	String  thread_local_model;
 	String  deprecated_message;
 	String  warning_message;
-	String  objc_class;
 	DeferredProcedure deferred_procedure;
 	bool    is_export           : 1;
 	bool    is_static           : 1;
@@ -119,6 +118,11 @@ struct AttributeContext {
 	bool    init                : 1;
 	bool    set_cold            : 1;
 	u32 optimization_mode; // ProcedureOptimizationMode
+
+	String  objc_class;
+	String  objc_name;
+	String  objc_class_name;
+	Type *  objc_type;
 };
 
 AttributeContext make_attribute_context(String link_prefix) {

+ 23 - 0
src/entity.cpp

@@ -122,6 +122,28 @@ enum ProcedureOptimizationMode : u32 {
 	ProcedureOptimizationMode_Speed,
 };
 
+
+BlockingMutex global_type_name_objc_metadata_mutex;
+
+struct TypeNameObjCMetadataEntry {
+	String name;
+	Entity *entity;
+};
+struct TypeNameObjCMetadata {
+	BlockingMutex *mutex;
+	Array<TypeNameObjCMetadataEntry> type_entries;
+	Array<TypeNameObjCMetadataEntry> value_entries;
+};
+
+TypeNameObjCMetadata *create_type_name_obj_c_metadata() {
+	TypeNameObjCMetadata *md = gb_alloc_item(permanent_allocator(), TypeNameObjCMetadata);
+	md->mutex = gb_alloc_item(permanent_allocator(), BlockingMutex);
+	mutex_init(md->mutex);
+	array_init(&md->type_entries,  heap_allocator());
+	array_init(&md->value_entries, heap_allocator());
+	return md;
+}
+
 // An Entity is a named "thing" in the language
 struct Entity {
 	EntityKind  kind;
@@ -187,6 +209,7 @@ struct Entity {
 			String ir_mangled_name;
 			bool   is_type_alias;
 			String objc_class_name;
+			TypeNameObjCMetadata *objc_metadata;
 		} TypeName;
 		struct {
 			u64     tags;

+ 10 - 1
src/llvm_backend_expr.cpp

@@ -3320,7 +3320,12 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 
 			Type *type = base_type(tav.type);
 			if (tav.mode == Addressing_Type) { // Addressing_Type
-				GB_PANIC("Unreachable");
+				Selection sel = lookup_field(tav.type, selector, true);
+				if (sel.pseudo_field) {
+					GB_ASSERT(sel.entity->kind == Entity_Procedure);
+					return lb_addr(lb_find_value_from_entity(p->module, sel.entity));
+				}
+				GB_PANIC("Unreachable %.*s", LIT(selector));
 			}
 
 			if (se->swizzle_count > 0) {
@@ -3347,6 +3352,10 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
 
 			Selection sel = lookup_field(type, selector, false);
 			GB_ASSERT(sel.entity != nullptr);
+			if (sel.pseudo_field) {
+				GB_ASSERT(sel.entity->kind == Entity_Procedure);
+				return lb_addr(lb_find_value_from_entity(p->module, sel.entity));
+			}
 
 			{
 				lbAddr addr = lb_build_addr(p, se->expr);

+ 1 - 31
src/main.cpp

@@ -585,37 +585,6 @@ void usage(String argv0) {
 	print_usage_line(1, "e.g. odin build -help");
 }
 
-
-bool string_is_valid_identifier(String str) {
-	if (str.len <= 0) return false;
-
-	isize rune_count = 0;
-
-	isize w = 0;
-	isize offset = 0;
-	while (offset < str.len) {
-		Rune r = 0;
-		w = utf8_decode(str.text, str.len, &r);
-		if (r == GB_RUNE_INVALID) {
-			return false;
-		}
-
-		if (rune_count == 0) {
-			if (!rune_is_letter(r)) {
-				return false;
-			}
-		} else {
-			if (!rune_is_letter(r) && !rune_is_digit(r)) {
-				return false;
-			}
-		}
-		rune_count += 1;
-		offset += w;
-	}
-
-	return true;
-}
-
 enum BuildFlagKind {
 	BuildFlag_Invalid,
 
@@ -2447,6 +2416,7 @@ int main(int arg_count, char const **arg_ptr) {
 	virtual_memory_init();
 	mutex_init(&fullpath_mutex);
 	mutex_init(&hash_exact_value_mutex);
+	mutex_init(&global_type_name_objc_metadata_mutex);
 
 	init_string_buffer_memory();
 	init_string_interner();

+ 31 - 0
src/string.cpp

@@ -781,3 +781,34 @@ i32 unquote_string(gbAllocator a, String *s_, u8 quote=0, bool has_carriage_retu
 	return 2;
 }
 
+
+
+bool string_is_valid_identifier(String str) {
+	if (str.len <= 0) return false;
+
+	isize rune_count = 0;
+
+	isize w = 0;
+	isize offset = 0;
+	while (offset < str.len) {
+		Rune r = 0;
+		w = utf8_decode(str.text, str.len, &r);
+		if (r == GB_RUNE_INVALID) {
+			return false;
+		}
+
+		if (rune_count == 0) {
+			if (!rune_is_letter(r)) {
+				return false;
+			}
+		} else {
+			if (!rune_is_letter(r) && !rune_is_digit(r)) {
+				return false;
+			}
+		}
+		rune_count += 1;
+		offset += w;
+	}
+
+	return true;
+}

+ 62 - 0
src/types.cpp

@@ -393,6 +393,7 @@ struct Selection {
 	bool       indirect; // Set if there was a pointer deref anywhere down the line
 	u8 swizzle_count;    // maximum components = 4
 	u8 swizzle_indices;  // 2 bits per component, representing which swizzle index
+	bool pseudo_field;
 };
 Selection empty_selection = {0};
 
@@ -2782,6 +2783,7 @@ Selection lookup_field_from_index(Type *type, i64 index) {
 }
 
 Entity *scope_lookup_current(Scope *s, String const &name);
+bool has_type_got_objc_class_attribute(Type *t);
 
 Selection lookup_field_with_selection(Type *type_, String field_name, bool is_type, Selection sel, bool allow_blank_ident) {
 	GB_ASSERT(type_ != nullptr);
@@ -2794,9 +2796,40 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
 	bool is_ptr = type != type_;
 	sel.indirect = sel.indirect || is_ptr;
 
+	Type *original_type = type;
+
 	type = base_type(type);
 
 	if (is_type) {
+		if (has_type_got_objc_class_attribute(original_type) && original_type->kind == Type_Named) {
+			Entity *e = original_type->Named.type_name;
+			GB_ASSERT(e->kind == Entity_TypeName);
+			if (e->TypeName.objc_metadata) {
+				auto *md = e->TypeName.objc_metadata;
+				mutex_lock(md->mutex);
+				defer (mutex_unlock(md->mutex));
+				for (TypeNameObjCMetadataEntry const &entry : md->type_entries) {
+					GB_ASSERT(entry.entity->kind == Entity_Procedure);
+					if (entry.name == field_name) {
+						sel.entity = entry.entity;
+						sel.pseudo_field = true;
+						return sel;
+					}
+				}
+			}
+			if (type->kind == Type_Struct) {
+				for_array(i, type->Struct.fields) {
+					Entity *f = type->Struct.fields[i];
+					if (f->flags&EntityFlag_Using) {
+						sel = lookup_field_with_selection(f->type, field_name, is_type, sel, allow_blank_ident);
+						if (sel.entity) {
+							return sel;
+						}
+					}
+				}
+			}
+		}
+
 		if (is_type_enum(type)) {
 			// NOTE(bill): These may not have been added yet, so check in case
 			for_array(i, type->Enum.fields) {
@@ -2843,6 +2876,24 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
 	} else if (type->kind == Type_Union) {
 
 	} else if (type->kind == Type_Struct) {
+		if (has_type_got_objc_class_attribute(original_type) && original_type->kind == Type_Named) {
+			Entity *e = original_type->Named.type_name;
+			GB_ASSERT(e->kind == Entity_TypeName);
+			if (e->TypeName.objc_metadata) {
+				auto *md = e->TypeName.objc_metadata;
+				mutex_lock(md->mutex);
+				defer (mutex_unlock(md->mutex));
+				for (TypeNameObjCMetadataEntry const &entry : md->value_entries) {
+					GB_ASSERT(entry.entity->kind == Entity_Procedure);
+					if (entry.name == field_name) {
+						sel.entity = entry.entity;
+						sel.pseudo_field = true;
+						return sel;
+					}
+				}
+			}
+		}
+
 		for_array(i, type->Struct.fields) {
 			Entity *f = type->Struct.fields[i];
 			if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) {
@@ -3792,6 +3843,17 @@ bool is_type_subtype_of(Type *src, Type *dst) {
 }
 
 
+bool has_type_got_objc_class_attribute(Type *t) {
+	return t->kind == Type_Named && t->Named.type_name != nullptr && t->Named.type_name->TypeName.objc_class_name != "";
+}
+
+
+
+bool is_type_objc_object(Type *t) {
+	bool internal_check_is_assignable_to(Type *src, Type *dst);
+
+	return internal_check_is_assignable_to(t, t_objc_object);
+}
 
 Type *get_struct_field_type(Type *t, isize index) {
 	t = base_type(type_deref(t));