mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 23:28:48 +00:00
Built-in procedure #defined
This commit is contained in:
@@ -110,6 +110,20 @@ general_stuff :: proc() {
|
|||||||
My_Struct :: struct{x: int};
|
My_Struct :: struct{x: int};
|
||||||
#assert(My_Struct != struct{x: int});
|
#assert(My_Struct != struct{x: int});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
X :: 123;
|
||||||
|
when #defined(X) {
|
||||||
|
fmt.println("X is defined");
|
||||||
|
} else {
|
||||||
|
fmt.println("X is not defined");
|
||||||
|
}
|
||||||
|
when #defined(Y) {
|
||||||
|
fmt.println("Y is defined");
|
||||||
|
} else {
|
||||||
|
fmt.println("Y is not defined");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+56
-1
@@ -2885,6 +2885,36 @@ bool is_type_normal_pointer(Type *ptr, Type **elem) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool check_identifier_exists(Scope *s, Ast *node, bool nested = false, Scope **out_scope = nullptr) {
|
||||||
|
switch (node->kind) {
|
||||||
|
case_ast_node(i, Ident, node);
|
||||||
|
String name = i->token.string;
|
||||||
|
if (nested) {
|
||||||
|
Entity *e = scope_lookup_current(s, name);
|
||||||
|
if (e != nullptr) {
|
||||||
|
if (out_scope) *out_scope = e->scope;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Entity *e = scope_lookup(s, name);
|
||||||
|
if (e != nullptr) {
|
||||||
|
if (out_scope) *out_scope = e->scope;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case_end;
|
||||||
|
case_ast_node(se, SelectorExpr, node);
|
||||||
|
Ast *lhs = se->expr;
|
||||||
|
Ast *rhs = se->selector;
|
||||||
|
Scope *lhs_scope = nullptr;
|
||||||
|
if (check_identifier_exists(s, lhs, nested, &lhs_scope)) {
|
||||||
|
return check_identifier_exists(lhs_scope, rhs, true);
|
||||||
|
}
|
||||||
|
case_end;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id) {
|
bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id) {
|
||||||
ast_node(ce, CallExpr, call);
|
ast_node(ce, CallExpr, call);
|
||||||
@@ -2920,6 +2950,15 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
|||||||
case BuiltinProc_len:
|
case BuiltinProc_len:
|
||||||
// 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;
|
||||||
|
|
||||||
|
case BuiltinProc_DIRECTIVE: {
|
||||||
|
ast_node(bd, BasicDirective, ce->proc);
|
||||||
|
String name = bd->name;
|
||||||
|
if (name == "defined") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*fallthrough*/
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if (ce->args.count > 0) {
|
if (ce->args.count > 0) {
|
||||||
check_multi_expr(c, operand, ce->args[0]);
|
check_multi_expr(c, operand, ce->args[0]);
|
||||||
@@ -2984,6 +3023,22 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
|||||||
|
|
||||||
operand->type = t_untyped_bool;
|
operand->type = t_untyped_bool;
|
||||||
operand->mode = Addressing_Constant;
|
operand->mode = Addressing_Constant;
|
||||||
|
} else if (name == "defined") {
|
||||||
|
if (ce->args.count != 1) {
|
||||||
|
error(call, "'#defined' expects 1 argument, got %td", ce->args.count);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Ast *arg = unparen_expr(ce->args[0]);
|
||||||
|
if (arg->kind != Ast_Ident && arg->kind != Ast_SelectorExpr) {
|
||||||
|
error(call, "'#defined' expects an identifier or selector expression, got %s", LIT(ast_strings[arg->kind]));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_defined = check_identifier_exists(c->scope, arg);
|
||||||
|
operand->type = t_untyped_bool;
|
||||||
|
operand->mode = Addressing_Constant;
|
||||||
|
operand->value = exact_value_bool(is_defined);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
GB_PANIC("Unhandled #%.*s", LIT(name));
|
GB_PANIC("Unhandled #%.*s", LIT(name));
|
||||||
}
|
}
|
||||||
@@ -4957,7 +5012,7 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call) {
|
|||||||
ce->proc->kind == Ast_BasicDirective) {
|
ce->proc->kind == Ast_BasicDirective) {
|
||||||
ast_node(bd, BasicDirective, ce->proc);
|
ast_node(bd, BasicDirective, ce->proc);
|
||||||
String name = bd->name;
|
String name = bd->name;
|
||||||
if (name == "location" || name == "assert") {
|
if (name == "location" || name == "assert" || name == "defined") {
|
||||||
operand->mode = Addressing_Builtin;
|
operand->mode = Addressing_Builtin;
|
||||||
operand->builtin_id = BuiltinProc_DIRECTIVE;
|
operand->builtin_id = BuiltinProc_DIRECTIVE;
|
||||||
operand->expr = ce->proc;
|
operand->expr = ce->proc;
|
||||||
|
|||||||
+10
-11
@@ -659,6 +659,8 @@ struct irDebugInfo {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static irDebugInfo IR_DEBUG_INFO_EMPTY = {};
|
||||||
|
|
||||||
|
|
||||||
struct irGen {
|
struct irGen {
|
||||||
irModule module;
|
irModule module;
|
||||||
@@ -2613,8 +2615,8 @@ void ir_pop_debug_location(irModule *m) {
|
|||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
irValue *ir_emit_runtime_call(irProcedure *proc, char const *name_, Array<irValue *> args, Ast *expr = nullptr);
|
irValue *ir_emit_runtime_call(irProcedure *proc, char const *name_, Array<irValue *> args, Ast *expr = nullptr, ProcInlining inlining = ProcInlining_none);
|
||||||
irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char const *name_, Array<irValue *> args, Ast *expr = nullptr);
|
irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char const *name_, Array<irValue *> args, Ast *expr = nullptr, ProcInlining inlining = ProcInlining_none);
|
||||||
|
|
||||||
|
|
||||||
irValue *ir_emit_store(irProcedure *p, irValue *address, irValue *value) {
|
irValue *ir_emit_store(irProcedure *p, irValue *address, irValue *value) {
|
||||||
@@ -2668,7 +2670,8 @@ void ir_emit_zero_init(irProcedure *p, irValue *address, Ast *expr) {
|
|||||||
args[1] = ir_const_int(type_size_of(t));
|
args[1] = ir_const_int(type_size_of(t));
|
||||||
AstPackage *pkg = get_core_package(p->module->info, str_lit("mem"));
|
AstPackage *pkg = get_core_package(p->module->info, str_lit("mem"));
|
||||||
if (p->entity != nullptr && p->entity->token.string != "zero" && p->entity->pkg != pkg) {
|
if (p->entity != nullptr && p->entity->token.string != "zero" && p->entity->pkg != pkg) {
|
||||||
ir_emit_package_call(p, "mem", "zero", args, expr);
|
irValue *v = ir_emit_package_call(p, "mem", "zero", args, expr, ProcInlining_no_inline);
|
||||||
|
// v->loc = &IR_DEBUG_INFO_EMPTY; // NOTE(bill): remove debug location
|
||||||
}
|
}
|
||||||
ir_emit(p, ir_instr_zero_init(p, address));
|
ir_emit(p, ir_instr_zero_init(p, address));
|
||||||
}
|
}
|
||||||
@@ -2803,7 +2806,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, Pro
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
irValue *ir_emit_runtime_call(irProcedure *proc, char const *name_, Array<irValue *> args, Ast *expr) {
|
irValue *ir_emit_runtime_call(irProcedure *proc, char const *name_, Array<irValue *> args, Ast *expr, ProcInlining inlining) {
|
||||||
String name = make_string_c(cast(char *)name_);
|
String name = make_string_c(cast(char *)name_);
|
||||||
|
|
||||||
AstPackage *p = proc->module->info->runtime_package;
|
AstPackage *p = proc->module->info->runtime_package;
|
||||||
@@ -2811,10 +2814,10 @@ irValue *ir_emit_runtime_call(irProcedure *proc, char const *name_, Array<irValu
|
|||||||
irValue **found = map_get(&proc->module->values, hash_entity(e));
|
irValue **found = map_get(&proc->module->values, hash_entity(e));
|
||||||
GB_ASSERT_MSG(found != nullptr, "%.*s", LIT(name));
|
GB_ASSERT_MSG(found != nullptr, "%.*s", LIT(name));
|
||||||
irValue *gp = *found;
|
irValue *gp = *found;
|
||||||
irValue *call = ir_emit_call(proc, gp, args);
|
irValue *call = ir_emit_call(proc, gp, args, inlining);
|
||||||
return call;
|
return call;
|
||||||
}
|
}
|
||||||
irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char const *name_, Array<irValue *> args, Ast *expr) {
|
irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char const *name_, Array<irValue *> args, Ast *expr, ProcInlining inlining) {
|
||||||
String name = make_string_c(cast(char *)name_);
|
String name = make_string_c(cast(char *)name_);
|
||||||
String package_name = make_string_c(cast(char *)package_name_);
|
String package_name = make_string_c(cast(char *)package_name_);
|
||||||
|
|
||||||
@@ -2823,7 +2826,7 @@ irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char
|
|||||||
irValue **found = map_get(&proc->module->values, hash_entity(e));
|
irValue **found = map_get(&proc->module->values, hash_entity(e));
|
||||||
GB_ASSERT_MSG(found != nullptr, "%.*s", LIT(name));
|
GB_ASSERT_MSG(found != nullptr, "%.*s", LIT(name));
|
||||||
irValue *gp = *found;
|
irValue *gp = *found;
|
||||||
irValue *call = ir_emit_call(proc, gp, args);
|
irValue *call = ir_emit_call(proc, gp, args, inlining);
|
||||||
return call;
|
return call;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6766,7 +6769,6 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
|||||||
ir_emit_bounds_check(proc, ast_token(ie->index), index, len);
|
ir_emit_bounds_check(proc, ast_token(ie->index), index, len);
|
||||||
}
|
}
|
||||||
return ir_addr(elem);
|
return ir_addr(elem);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case Type_Slice: {
|
case Type_Slice: {
|
||||||
@@ -6785,7 +6787,6 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
|||||||
ir_emit_bounds_check(proc, ast_token(ie->index), index, len);
|
ir_emit_bounds_check(proc, ast_token(ie->index), index, len);
|
||||||
irValue *v = ir_emit_ptr_offset(proc, elem, index);
|
irValue *v = ir_emit_ptr_offset(proc, elem, index);
|
||||||
return ir_addr(v);
|
return ir_addr(v);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case Type_DynamicArray: {
|
case Type_DynamicArray: {
|
||||||
@@ -6804,7 +6805,6 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
|||||||
ir_emit_bounds_check(proc, ast_token(ie->index), index, len);
|
ir_emit_bounds_check(proc, ast_token(ie->index), index, len);
|
||||||
irValue *v = ir_emit_ptr_offset(proc, elem, index);
|
irValue *v = ir_emit_ptr_offset(proc, elem, index);
|
||||||
return ir_addr(v);
|
return ir_addr(v);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -6829,7 +6829,6 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
|
|||||||
ir_emit_bounds_check(proc, ast_token(ie->index), index, len);
|
ir_emit_bounds_check(proc, ast_token(ie->index), index, len);
|
||||||
|
|
||||||
return ir_addr(ir_emit_ptr_offset(proc, elem, index));
|
return ir_addr(ir_emit_ptr_offset(proc, elem, index));
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case_end;
|
case_end;
|
||||||
|
|||||||
+4
-3
@@ -221,9 +221,10 @@ bool ir_print_debug_location(irFileBuffer *f, irModule *m, irValue *v) {
|
|||||||
GB_ASSERT(v->kind == irValue_Instr);
|
GB_ASSERT(v->kind == irValue_Instr);
|
||||||
|
|
||||||
if (v->loc != nullptr) {
|
if (v->loc != nullptr) {
|
||||||
GB_ASSERT(v->loc->kind == irDebugInfo_Location);
|
if (v->loc->kind == irDebugInfo_Location) {
|
||||||
ir_fprintf(f, ", !dbg !%d", v->loc->id);
|
ir_fprintf(f, ", !dbg !%d", v->loc->id);
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
irProcedure *proc = v->Instr.block->proc;
|
irProcedure *proc = v->Instr.block->proc;
|
||||||
GB_ASSERT(proc->is_entry_point || (string_compare(proc->name, str_lit(IR_STARTUP_RUNTIME_PROC_NAME)) == 0));
|
GB_ASSERT(proc->is_entry_point || (string_compare(proc->name, str_lit(IR_STARTUP_RUNTIME_PROC_NAME)) == 0));
|
||||||
|
|||||||
@@ -1677,6 +1677,9 @@ Ast *parse_operand(AstFile *f, bool lhs) {
|
|||||||
} else if (name.string == "assert") {
|
} else if (name.string == "assert") {
|
||||||
Ast *tag = ast_basic_directive(f, token, name.string);
|
Ast *tag = ast_basic_directive(f, token, name.string);
|
||||||
return parse_call_expr(f, tag);
|
return parse_call_expr(f, tag);
|
||||||
|
} else if (name.string == "defined") {
|
||||||
|
Ast *tag = ast_basic_directive(f, token, name.string);
|
||||||
|
return parse_call_expr(f, tag);
|
||||||
} else {
|
} else {
|
||||||
operand = ast_tag_expr(f, token, name, parse_expr(f, false));
|
operand = ast_tag_expr(f, token, name, parse_expr(f, false));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,6 +150,7 @@ enum ProcTag {
|
|||||||
ProcTag_bounds_check = 1<<0,
|
ProcTag_bounds_check = 1<<0,
|
||||||
ProcTag_no_bounds_check = 1<<1,
|
ProcTag_no_bounds_check = 1<<1,
|
||||||
ProcTag_require_results = 1<<4,
|
ProcTag_require_results = 1<<4,
|
||||||
|
ProcTag_no_context = 1<<6,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ProcCallingConvention {
|
enum ProcCallingConvention {
|
||||||
|
|||||||
Reference in New Issue
Block a user