mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-01 12:18:15 +00:00
Add intrinsics.procedure_of
```odin
foo :: proc(x: $T) { fmt.println(x) }
bar :: intrinsics.procedure_of(foo(int(123))) // parameters are never ran at compile time, similar to `size_of`
bar(333) // prints 333
```
This commit is contained in:
@@ -295,6 +295,10 @@ simd_rotate_right :: proc(a: #simd[N]T, $offset: int) -> #simd[N]T ---
|
|||||||
// if all listed features are supported.
|
// if all listed features are supported.
|
||||||
has_target_feature :: proc($test: $T) -> bool where type_is_string(T) || type_is_proc(T) ---
|
has_target_feature :: proc($test: $T) -> bool where type_is_string(T) || type_is_proc(T) ---
|
||||||
|
|
||||||
|
|
||||||
|
// Returns the value of the procedure where `x` must be a call expression
|
||||||
|
procedure_of :: proc(x: $T) -> T where type_is_proc(T) ---
|
||||||
|
|
||||||
// WASM targets only
|
// WASM targets only
|
||||||
wasm_memory_grow :: proc(index, delta: uintptr) -> int ---
|
wasm_memory_grow :: proc(index, delta: uintptr) -> int ---
|
||||||
wasm_memory_size :: proc(index: uintptr) -> int ---
|
wasm_memory_size :: proc(index: uintptr) -> int ---
|
||||||
|
|||||||
@@ -1843,6 +1843,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
|||||||
case BuiltinProc_objc_register_class:
|
case BuiltinProc_objc_register_class:
|
||||||
case BuiltinProc_atomic_type_is_lock_free:
|
case BuiltinProc_atomic_type_is_lock_free:
|
||||||
case BuiltinProc_has_target_feature:
|
case BuiltinProc_has_target_feature:
|
||||||
|
case BuiltinProc_procedure_of:
|
||||||
// NOTE(bill): The first arg may be a Type, this will be checked case by case
|
// NOTE(bill): The first arg may be a Type, this will be checked case by case
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -6157,6 +6158,51 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case BuiltinProc_procedure_of:
|
||||||
|
{
|
||||||
|
Ast *call_expr = unparen_expr(ce->args[0]);
|
||||||
|
Operand op = {};
|
||||||
|
check_expr_base(c, &op, ce->args[0], nullptr);
|
||||||
|
if (op.mode != Addressing_Value && !(call_expr && call_expr->kind == Ast_CallExpr)) {
|
||||||
|
error(ce->args[0], "Expected a call expression for '%.*s'", LIT(builtin_name));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ast *proc = call_expr->CallExpr.proc;
|
||||||
|
Entity *e = entity_of_node(proc);
|
||||||
|
|
||||||
|
if (e == nullptr) {
|
||||||
|
error(ce->args[0], "Invalid procedure value, expected a regular/specialized procedure");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeAndValue tav = proc->tav;
|
||||||
|
|
||||||
|
|
||||||
|
operand->type = e->type;
|
||||||
|
operand->mode = Addressing_Value;
|
||||||
|
operand->value = tav.value;
|
||||||
|
operand->builtin_id = BuiltinProc_Invalid;
|
||||||
|
operand->proc_group = nullptr;
|
||||||
|
|
||||||
|
if (tav.mode == Addressing_Builtin) {
|
||||||
|
operand->mode = tav.mode;
|
||||||
|
operand->builtin_id = cast(BuiltinProcId)e->Builtin.id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_type_proc(e->type)) {
|
||||||
|
gbString s = type_to_string(e->type);
|
||||||
|
error(ce->args[0], "Expected a procedure value, got '%s'", s);
|
||||||
|
gb_string_free(s);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ce->entity_procedure_of = e;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case BuiltinProc_constant_utf16_cstring:
|
case BuiltinProc_constant_utf16_cstring:
|
||||||
{
|
{
|
||||||
String value = {};
|
String value = {};
|
||||||
|
|||||||
+12
-5
@@ -88,11 +88,14 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
|
|||||||
e->type = t_invalid;
|
e->type = t_invalid;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
} else if (is_type_polymorphic(t)) {
|
} else if (is_type_polymorphic(t)) {
|
||||||
gbString str = type_to_string(t);
|
Entity *e = entity_of_node(operand->expr);
|
||||||
defer (gb_string_free(str));
|
if (e->state.load() != EntityState_Resolved) {
|
||||||
error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name));
|
gbString str = type_to_string(t);
|
||||||
e->type = t_invalid;
|
defer (gb_string_free(str));
|
||||||
return nullptr;
|
error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name));
|
||||||
|
e->type = t_invalid;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
} else if (is_type_empty_union(t)) {
|
} else if (is_type_empty_union(t)) {
|
||||||
gbString str = type_to_string(t);
|
gbString str = type_to_string(t);
|
||||||
defer (gb_string_free(str));
|
defer (gb_string_free(str));
|
||||||
@@ -479,6 +482,9 @@ gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr
|
|||||||
entity = check_selector(ctx, &operand, init, e->type);
|
entity = check_selector(ctx, &operand, init, e->type);
|
||||||
} else {
|
} else {
|
||||||
check_expr_or_type(ctx, &operand, init, e->type);
|
check_expr_or_type(ctx, &operand, init, e->type);
|
||||||
|
if (init->kind == Ast_CallExpr) {
|
||||||
|
entity = init->CallExpr.entity_procedure_of;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (operand.mode) {
|
switch (operand.mode) {
|
||||||
@@ -526,6 +532,7 @@ gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (entity != nullptr) {
|
if (entity != nullptr) {
|
||||||
if (e->type != nullptr) {
|
if (e->type != nullptr) {
|
||||||
Operand x = {};
|
Operand x = {};
|
||||||
|
|||||||
@@ -578,6 +578,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
|
|||||||
d->defer_use_checked = false;
|
d->defer_use_checked = false;
|
||||||
|
|
||||||
Entity *entity = alloc_entity_procedure(nullptr, token, final_proc_type, tags);
|
Entity *entity = alloc_entity_procedure(nullptr, token, final_proc_type, tags);
|
||||||
|
entity->state.store(EntityState_Resolved);
|
||||||
entity->identifier = ident;
|
entity->identifier = ident;
|
||||||
|
|
||||||
add_entity_and_decl_info(&nctx, ident, entity, d);
|
add_entity_and_decl_info(&nctx, ident, entity, d);
|
||||||
|
|||||||
+9
-1
@@ -2224,8 +2224,16 @@ gb_internal void check_expr_stmt(CheckerContext *ctx, Ast *node) {
|
|||||||
}
|
}
|
||||||
if (do_require) {
|
if (do_require) {
|
||||||
gbString expr_str = expr_to_string(ce->proc);
|
gbString expr_str = expr_to_string(ce->proc);
|
||||||
|
defer (gb_string_free(expr_str));
|
||||||
|
if (builtin_id) {
|
||||||
|
String real_name = builtin_procs[builtin_id].name;
|
||||||
|
if (real_name != make_string(cast(u8 const *)expr_str, gb_string_length(expr_str))) {
|
||||||
|
error(node, "'%s' ('%.*s.%.*s') requires that its results must be handled", expr_str,
|
||||||
|
LIT(builtin_proc_pkg_name[builtin_procs[builtin_id].pkg]), LIT(real_name));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
error(node, "'%s' requires that its results must be handled", expr_str);
|
error(node, "'%s' requires that its results must be handled", expr_str);
|
||||||
gb_string_free(expr_str);
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (expr && expr->kind == Ast_SelectorCallExpr) {
|
} else if (expr && expr->kind == Ast_SelectorCallExpr) {
|
||||||
|
|||||||
@@ -1479,6 +1479,10 @@ gb_internal Entity *entity_of_node(Ast *expr) {
|
|||||||
case_ast_node(cc, CaseClause, expr);
|
case_ast_node(cc, CaseClause, expr);
|
||||||
return cc->implicit_entity;
|
return cc->implicit_entity;
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
|
case_ast_node(ce, CallExpr, expr);
|
||||||
|
return ce->entity_procedure_of;
|
||||||
|
case_end;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,12 @@ enum StmtFlag {
|
|||||||
enum BuiltinProcPkg {
|
enum BuiltinProcPkg {
|
||||||
BuiltinProcPkg_builtin,
|
BuiltinProcPkg_builtin,
|
||||||
BuiltinProcPkg_intrinsics,
|
BuiltinProcPkg_intrinsics,
|
||||||
|
BuiltinProcPkg_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
String builtin_proc_pkg_name[BuiltinProcPkg_COUNT] = {
|
||||||
|
str_lit("builtin"),
|
||||||
|
str_lit("intrinsics"),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BuiltinProc {
|
struct BuiltinProc {
|
||||||
|
|||||||
@@ -299,6 +299,8 @@ BuiltinProc__type_simple_boolean_end,
|
|||||||
|
|
||||||
BuiltinProc__type_end,
|
BuiltinProc__type_end,
|
||||||
|
|
||||||
|
BuiltinProc_procedure_of,
|
||||||
|
|
||||||
BuiltinProc___entry_point,
|
BuiltinProc___entry_point,
|
||||||
|
|
||||||
BuiltinProc_objc_send,
|
BuiltinProc_objc_send,
|
||||||
@@ -614,6 +616,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
|||||||
|
|
||||||
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||||
|
|
||||||
|
{STR_LIT("procedure_of"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||||
|
|
||||||
{STR_LIT("__entry_point"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
{STR_LIT("__entry_point"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||||
|
|
||||||
{STR_LIT("objc_send"), 3, true, Expr_Expr, BuiltinProcPkg_intrinsics, false, true},
|
{STR_LIT("objc_send"), 3, true, Expr_Expr, BuiltinProcPkg_intrinsics, false, true},
|
||||||
|
|||||||
@@ -458,6 +458,7 @@ AST_KIND(_ExprBegin, "", bool) \
|
|||||||
bool optional_ok_one; \
|
bool optional_ok_one; \
|
||||||
bool was_selector; \
|
bool was_selector; \
|
||||||
AstSplitArgs *split_args; \
|
AstSplitArgs *split_args; \
|
||||||
|
Entity *entity_procedure_of; \
|
||||||
}) \
|
}) \
|
||||||
AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \
|
AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \
|
||||||
AST_KIND(EnumFieldValue, "enum field value", struct { \
|
AST_KIND(EnumFieldValue, "enum field value", struct { \
|
||||||
|
|||||||
Reference in New Issue
Block a user