Built-in procedure #defined

This commit is contained in:
gingerBill
2018-10-27 18:44:28 +01:00
parent 5c608b01ba
commit 2ddb27869b
6 changed files with 105 additions and 32 deletions
+14
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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));
+3
View File
@@ -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));
} }
+1
View File
@@ -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 {