mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 23:58:50 +00:00
Allow objective-c procedures to have their @objc_name attribute inferred.
The `@objc_name` is automatically inferred if it is not specified and the procedure name is prefixed with type name specified in `@objc_type`, followed by an `_`. What followed the `_` is interpreted as the `@objc_name`.
This commit is contained in:
+20
-12
@@ -1001,27 +1001,36 @@ gb_internal String handle_link_name(CheckerContext *ctx, Token token, String lin
|
|||||||
|
|
||||||
|
|
||||||
gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeContext &ac) {
|
gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeContext &ac) {
|
||||||
if (!(ac.objc_name.len || ac.objc_is_class_method || ac.objc_type)) {
|
if (!ac.objc_type) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ac.objc_name.len == 0 && ac.objc_is_class_method) {
|
|
||||||
error(e->token, "@(objc_name) is required with @(objc_is_class_method)");
|
|
||||||
} else if (ac.objc_type == nullptr) {
|
|
||||||
error(e->token, "@(objc_name) requires that @(objc_type) to be set");
|
|
||||||
} else if (ac.objc_name.len == 0 && ac.objc_type) {
|
|
||||||
error(e->token, "@(objc_name) is required with @(objc_type)");
|
|
||||||
} else {
|
|
||||||
Type *t = ac.objc_type;
|
Type *t = ac.objc_type;
|
||||||
|
|
||||||
GB_ASSERT(t->kind == Type_Named); // NOTE(harold): This is already checked for at the attribute resolution stage.
|
GB_ASSERT(t->kind == Type_Named); // NOTE(harold): This is already checked for at the attribute resolution stage.
|
||||||
Entity *tn = t->Named.type_name;
|
|
||||||
|
|
||||||
|
// Attempt to infer th objc_name automatically if the proc name contains
|
||||||
|
// the type name objc_type's name, followed by an underscore, as a prefix.
|
||||||
|
if (ac.objc_name.len == 0) {
|
||||||
|
String proc_name = e->token.string;
|
||||||
|
String type_name = t->Named.name;
|
||||||
|
|
||||||
|
if (proc_name.len > type_name.len + 1 &&
|
||||||
|
proc_name[type_name.len] == '_' &&
|
||||||
|
str_eq(type_name, substring(proc_name, 0, type_name.len))
|
||||||
|
) {
|
||||||
|
ac.objc_name = substring(proc_name, type_name.len+1, proc_name.len);
|
||||||
|
} else {
|
||||||
|
error(e->token, "@(objc_name) requires that @(objc_type) be set or inferred "
|
||||||
|
"by prefixing the proc name with the type and underscore: MyObjcType_myProcName :: proc().");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity *tn = t->Named.type_name;
|
||||||
GB_ASSERT(tn->kind == Entity_TypeName);
|
GB_ASSERT(tn->kind == Entity_TypeName);
|
||||||
|
|
||||||
if (tn->scope != e->scope) {
|
if (tn->scope != e->scope) {
|
||||||
error(e->token, "@(objc_name) attribute may only be applied to procedures and types within the same scope");
|
error(e->token, "@(objc_name) attribute may only be applied to procedures and types within the same scope");
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Enable implementation by default if the class is an implementer too and
|
// Enable implementation by default if the class is an implementer too and
|
||||||
// @objc_implement was not set to false explicitly in this proc.
|
// @objc_implement was not set to false explicitly in this proc.
|
||||||
bool implement = tn->TypeName.objc_is_implementation;
|
bool implement = tn->TypeName.objc_is_implementation;
|
||||||
@@ -1117,7 +1126,6 @@ gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeCon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
gb_internal void check_foreign_procedure(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
gb_internal void check_foreign_procedure(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||||
GB_ASSERT(e != nullptr);
|
GB_ASSERT(e != nullptr);
|
||||||
|
|||||||
Reference in New Issue
Block a user