Add more objc attributes

This commit is contained in:
gingerBill
2022-02-11 22:54:51 +00:00
parent 416413bebf
commit f8afda3b22
24 changed files with 588 additions and 142 deletions

View File

@@ -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 {
@(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)
}
@(objc_type=Array, objc_name="object")
Array_object :: proc(self: ^Array, index: UInteger) -> ^Object {
return msgSend(^Object, self, "objectAtIndex:", index)
}
Array_object :: proc(self: ^Array($T), index: UInteger) -> T {
return (T)(Array_objectAtIndex(self, 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")
}

View File

@@ -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()
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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) }
@(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) }
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,
@(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_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)
}
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)
}

View File

@@ -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")
}
release :: proc(self: ^$T) where intrinsics.type_is_subtype_of(T, Object) {
msgSend(nil, self, "release")
}
autorelease :: proc(self: ^$T) where intrinsics.type_is_subtype_of(T, Object) {
msgSend(nil, self, "autorelease")
}
retainCount :: proc(self: ^$T) -> UInteger where intrinsics.type_is_subtype_of(T, Object) {
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="retain")
retain :: proc(self: ^Object) {
_ = msgSend(^Object, self, "retain")
}
@(objc_type=Object, objc_name="release")
release :: proc(self: ^Object) {
msgSend(nil, self, "release")
}
@(objc_type=Object, objc_name="autorelease")
autorelease :: proc(self: ^Object) {
msgSend(nil, self, "autorelease")
}
@(objc_type=Object, objc_name="retainCount")
retainCount :: proc(self: ^Object) -> UInteger {
return msgSend(UInteger, self, "retainCount")
}
@(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")

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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