#location(..) and #call_location

This commit is contained in:
Ginger Bill
2017-06-18 14:36:06 +01:00
parent e4944b4f2e
commit 4236519b84
11 changed files with 241 additions and 96 deletions

View File

@@ -184,6 +184,19 @@ type (
#thread_local var __context: Context;
type SourceCodeLocation struct {
fully_pathed_filename: string,
procedure: string,
line, column: i64,
}
proc make_source_code_location(file, procedure: string, line, column: i64) -> SourceCodeLocation {
return SourceCodeLocation{file, procedure, line, column};
}
const DEFAULT_ALIGNMENT = align_of([vector 4]f32);

View File

@@ -1062,22 +1062,30 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
ast_node(p, Field, param);
AstNode *type_expr = p->type;
Type *type = NULL;
AstNode *default_value = p->default_value;
AstNode *default_value = unparen_expr(p->default_value);
ExactValue value = {};
bool default_is_nil = false;
bool default_is_location = false;
if (type_expr == NULL) {
Operand o = {};
check_expr_or_type(c, &o, default_value);
if (is_operand_nil(o)) {
default_is_nil = true;
} else if (o.mode != Addressing_Constant) {
error_node(default_value, "Default parameter must be a constant");
if (default_value->kind == AstNode_BasicDirective &&
default_value->BasicDirective.name == "caller_location") {
init_preload(c);
default_is_location = true;
type = t_source_code_location;
} else {
value = o.value;
}
Operand o = {};
check_expr_or_type(c, &o, default_value);
if (is_operand_nil(o)) {
default_is_nil = true;
} else if (o.mode != Addressing_Constant) {
error_node(default_value, "Default parameter must be a constant");
} else {
value = o.value;
}
type = default_type(o.type);
type = default_type(o.type);
}
} else {
if (type_expr->kind == AstNode_Ellipsis) {
type_expr = type_expr->Ellipsis.expr;
@@ -1095,14 +1103,22 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
if (default_value != NULL) {
Operand o = {};
check_expr_with_type_hint(c, &o, default_value, type);
if (is_operand_nil(o)) {
default_is_nil = true;
} else if (o.mode != Addressing_Constant) {
error_node(default_value, "Default parameter must be a constant");
if (default_value->kind == AstNode_BasicDirective &&
default_value->BasicDirective.name == "caller_location") {
init_preload(c);
default_is_location = true;
o.type = t_source_code_location;
o.mode = Addressing_Value;
} else {
value = o.value;
check_expr_with_type_hint(c, &o, default_value, type);
if (is_operand_nil(o)) {
default_is_nil = true;
} else if (o.mode != Addressing_Constant) {
error_node(default_value, "Default parameter must be a constant");
} else {
value = o.value;
}
}
check_is_assignable_to(c, &o, type);
@@ -1145,6 +1161,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
(p->flags&FieldFlag_using) != 0, false);
param->Variable.default_value = value;
param->Variable.default_is_nil = default_is_nil;
param->Variable.default_is_location = default_is_location;
}
if (p->flags&FieldFlag_no_alias) {
param->flags |= EntityFlag_NoAlias;
@@ -3639,7 +3656,10 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
// NOTE(bill): The first arg may be a Type, this will be checked case by case
break;
default:
check_multi_expr(c, operand, ce->args[0]);
if (ce->args.count > 0) {
check_multi_expr(c, operand, ce->args[0]);
}
break;
}
switch (id) {
@@ -3647,6 +3667,32 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_procs[id].name));
break;
case BuiltinProc_DIRECTIVE: {
ast_node(bd, BasicDirective, ce->proc);
String name = bd->name;
GB_ASSERT(name == "location");
if (ce->args.count > 1) {
error_node(ce->args[0], "`#location` expects either 0 or 1 arguments, got %td", ce->args.count);
}
if (ce->args.count > 0) {
AstNode *arg = ce->args[0];
Entity *e = NULL;
Operand o = {};
if (arg->kind == AstNode_Ident) {
e = check_ident(c, &o, arg, NULL, NULL, true);
} else if (arg->kind == AstNode_SelectorExpr) {
e = check_selector(c, &o, arg, NULL);
}
if (e == NULL) {
error_node(ce->args[0], "`#location` expected a valid entity name");
}
}
operand->type = t_source_code_location;
operand->mode = Addressing_Value;
} break;
case BuiltinProc_len:
case BuiltinProc_cap: {
// proc len(Type) -> int
@@ -4822,11 +4868,9 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
}
GB_ASSERT(e->kind == Entity_Variable);
if (e->Variable.default_value.kind != ExactValue_Invalid) {
param_count_excluding_defaults--;
continue;
}
if (e->Variable.default_is_nil) {
if (e->Variable.default_value.kind != ExactValue_Invalid ||
e->Variable.default_is_nil ||
e->Variable.default_is_location) {
param_count_excluding_defaults--;
continue;
}
@@ -5214,7 +5258,19 @@ Entity *find_using_index_expr(Type *t) {
ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
GB_ASSERT(call->kind == AstNode_CallExpr);
ast_node(ce, CallExpr, call);
check_expr_or_type(c, operand, ce->proc);
if (ce->proc != NULL &&
ce->proc->kind == AstNode_BasicDirective) {
ast_node(bd, BasicDirective, ce->proc);
String name = bd->name;
GB_ASSERT(name == "location");
operand->mode = Addressing_Builtin;
operand->builtin_id = BuiltinProc_DIRECTIVE;
operand->expr = ce->proc;
operand->type = t_invalid;
add_type_and_value(&c->info, ce->proc, operand->mode, operand->type, operand->value);
} else {
check_expr_or_type(c, operand, ce->proc);
}
if (ce->args.count > 0) {
bool fail = false;
@@ -5508,9 +5564,13 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
o->type = t_untyped_string;
o->value = exact_value_string(c->context.proc_name);
}
} else if (bd->name == "caller_location") {
init_preload(c);
error_node(node, "#caller_location may only be used as a default argument parameter");
o->type = t_source_code_location;
o->mode = Addressing_Value;
} else {
GB_PANIC("Unknown basic basic directive");
GB_PANIC("Unknown basic directive");
}
o->mode = Addressing_Constant;
case_end;

View File

@@ -1161,7 +1161,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
TokenKind op = {};
TokenKind op = Token_Invalid;
Operand a = lhs;
Operand b = rhs;

View File

@@ -65,9 +65,11 @@ enum BuiltinProcId {
BuiltinProc_transmute,
BuiltinProc_Count,
BuiltinProc_DIRECTIVE,
BuiltinProc_COUNT,
};
gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT(""), 0, false, Expr_Stmt},
{STR_LIT("len"), 1, false, Expr_Expr},
@@ -110,6 +112,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
{STR_LIT("clamp"), 3, false, Expr_Expr},
{STR_LIT("transmute"), 2, false, Expr_Expr},
{STR_LIT(""), 0, true, Expr_Expr}, // DIRECTIVE
};
@@ -660,9 +664,12 @@ void init_universal_scope(void) {
// Builtin Procedures
for (isize i = 0; i < gb_count_of(builtin_procs); i++) {
BuiltinProcId id = cast(BuiltinProcId)i;
Entity *entity = alloc_entity(a, Entity_Builtin, NULL, make_token_ident(builtin_procs[i].name), t_invalid);
entity->Builtin.id = id;
add_global_entity(entity);
String name = builtin_procs[i].name;
if (name != "") {
Entity *entity = alloc_entity(a, Entity_Builtin, NULL, make_token_ident(name), t_invalid);
entity->Builtin.id = id;
add_global_entity(entity);
}
}
@@ -1284,6 +1291,12 @@ void init_preload(Checker *c) {
t_context_ptr = make_type_pointer(c->allocator, t_context);
}
if (t_source_code_location == NULL) {
Entity *e = find_core_entity(c, str_lit("SourceCodeLocation"));
t_source_code_location = e->type;
t_source_code_location_ptr = make_type_pointer(c->allocator, t_allocator);
}
if (t_map_key == NULL) {
Entity *e = find_core_entity(c, str_lit("__MapKey"));
t_map_key = e->type;
@@ -1755,7 +1768,7 @@ void check_collect_entities(Checker *c, Array<AstNode *> nodes, bool is_file_sco
void check_all_global_entities(Checker *c) {
Scope *prev_file = {};
Scope *prev_file = NULL;
for_array(i, c->info.entities.entries) {
auto *entry = &c->info.entities.entries[i];

View File

@@ -86,6 +86,7 @@ struct Entity {
i32 field_src_index;
ExactValue default_value;
bool default_is_nil;
bool default_is_location;
bool is_immutable;
bool is_thread_local;
bool is_foreign;

View File

@@ -152,7 +152,12 @@ u64 bit128__digit_value(Rune r) {
return 16; // NOTE(bill): Larger than highest possible
}
u128 u128_lo_hi(u64 lo, u64 hi) { return u128{lo, hi}; }
u128 u128_lo_hi(u64 lo, u64 hi) {
u128 r = {};
r.lo = lo;
r.hi = hi;
return r;
}
u128 u128_from_u32(u32 u) { return u128_lo_hi(cast(u64)u, 0); }
u128 u128_from_u64(u64 u) { return u128_lo_hi(cast(u64)u, 0); }
u128 u128_from_i64(i64 u) { return u128_lo_hi(cast(u64)u, u < 0 ? -1 : 0); }

View File

@@ -3522,7 +3522,8 @@ irBranchBlocks ir_lookup_branch_blocks(irProcedure *proc, AstNode *ident) {
}
GB_PANIC("Unreachable");
return irBranchBlocks{};
irBranchBlocks empty = {};
return empty;
}
@@ -3628,10 +3629,46 @@ bool is_double_pointer(Type *t) {
return is_type_pointer(td);
}
irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv, Entity *e) {
irValue *ir_emit_source_code_location(irProcedure *proc, String procedure, TokenPos pos) {
gbAllocator a = proc->module->allocator;
irValue **args = gb_alloc_array(a, irValue *, 4);
args[0] = ir_const_string(a, pos.file);
args[1] = ir_const_string(a, procedure);
args[2] = ir_const_i64(a, pos.line);
args[3] = ir_const_i64(a, pos.column);
return ir_emit_global_call(proc, "make_source_code_location", args, 4);
}
irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv, BuiltinProcId id) {
ast_node(ce, CallExpr, expr);
switch (e->Builtin.id) {
switch (id) {
case BuiltinProc_DIRECTIVE: {
ast_node(bd, BasicDirective, ce->proc);
String name = bd->name;
GB_ASSERT(name == "location");
String procedure = proc->entity->token.string;
TokenPos pos = ast_node_token(ce->proc).pos;
if (ce->args.count > 0) {
AstNode *ident = ce->args[0];;
while (ident->kind == AstNode_SelectorExpr) {
ident = ident->SelectorExpr.selector;
}
Entity *e = entity_of_ident(proc->module->info, ident);
GB_ASSERT(e != NULL);
if (e->parent_proc_decl != NULL) {
procedure = e->parent_proc_decl->entities[0]->token.string;
} else {
procedure = str_lit("");
}
pos = e->token.pos;
}
return ir_emit_source_code_location(proc, procedure, pos);
} break;
case BuiltinProc_type_info: {
Type *t = default_type(type_of_expr(proc->module->info, ce->args[0]));
return ir_type_info(proc, t);
@@ -4573,7 +4610,9 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
case_ast_node(ce, CallExpr, expr);
if (type_and_value_of_expr(proc->module->info, ce->proc).mode == Addressing_Type) {
TypeAndValue proc_tv = type_and_value_of_expr(proc->module->info, ce->proc);
AddressingMode proc_mode = proc_tv.mode;
if (proc_mode == Addressing_Type) {
GB_ASSERT(ce->args.count == 1);
irValue *x = ir_build_expr(proc, ce->args[0]);
irValue *y = ir_emit_conv(proc, x, tv.type);
@@ -4581,11 +4620,10 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
}
AstNode *p = unparen_expr(ce->proc);
if (p->kind == AstNode_Ident) {
if (proc_mode == Addressing_Builtin) {
Entity *e = entity_of_ident(proc->module->info, p);
if (e != NULL && e->kind == Entity_Builtin) {
return ir_build_builtin_proc(proc, expr, tv, e);
}
BuiltinProcId id = cast(BuiltinProcId)(e != NULL ? e->Builtin.id : BuiltinProc_DIRECTIVE);
return ir_build_builtin_proc(proc, expr, tv, id);
}
// NOTE(bill): Regular call
@@ -4664,6 +4702,9 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
TypeTuple *pt = &type->params->Tuple;
if (arg_count < type->param_count) {
String procedure = proc->entity->token.string;
TokenPos pos = ast_node_token(ce->proc).pos;
isize end = type->param_count;
if (variadic) {
end--;
@@ -4673,6 +4714,8 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
GB_ASSERT(e->kind == Entity_Variable);
if (e->Variable.default_value.kind != ExactValue_Invalid) {
args[arg_index++] = ir_value_constant(proc->module->allocator, e->type, e->Variable.default_value);
} else if (e->Variable.default_is_location) {
args[arg_index++] = ir_emit_source_code_location(proc, procedure, pos);
} else {
args[arg_index++] = ir_value_nil(proc->module->allocator, e->type);
}
@@ -6459,7 +6502,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
irValue *cond = v_false;
if (is_ast_node_a_range(expr)) {
ast_node(ie, BinaryExpr, expr);
TokenKind op = {};
TokenKind op = Token_Invalid;
switch (ie->op.kind) {
case Token_Ellipsis: op = Token_LtEq; break;
case Token_HalfClosed: op = Token_Lt; break;

View File

@@ -1,4 +1,4 @@
#define USE_CUSTOM_BACKEND false
#define USE_CUSTOM_BACKEND 0
#include "common.cpp"
#include "timings.cpp"
@@ -205,7 +205,7 @@ int main(int argc, char **argv) {
#endif
#if USE_CUSTOM_BACKEND
#if defined(USE_CUSTOM_BACKEND) && USE_CUSTOM_BACKEND
if (global_error_collector.count != 0) {
return 1;
}

View File

@@ -114,10 +114,9 @@ enum StmtAllowFlag {
Array<AstNode *> make_ast_node_array(AstFile *f) {
Array<AstNode *> make_ast_node_array(AstFile *f, isize init_capacity = 8) {
Array<AstNode *> a;
// array_init(&a, gb_arena_allocator(&f->arena));
array_init(&a, heap_allocator());
array_init(&a, heap_allocator(), init_capacity);
return a;
}
@@ -2029,8 +2028,9 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *link_name, ProcCallingConven
Array<AstNode *> parse_lhs_expr_list(AstFile *f);
Array<AstNode *> parse_rhs_expr_list(AstFile *f);
AstNode * parse_simple_stmt (AstFile *f, StmtAllowFlag flags);
AstNode * parse_type (AstFile *f);
AstNode * parse_simple_stmt (AstFile *f, StmtAllowFlag flags);
AstNode * parse_type (AstFile *f);
AstNode * parse_call_expr (AstFile *f, AstNode *operand);
AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) {
if (statement == NULL) {
@@ -2117,7 +2117,10 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
} else if (name.string == "file") { return ast_basic_directive(f, token, name.string);
} else if (name.string == "line") { return ast_basic_directive(f, token, name.string);
} else if (name.string == "procedure") { return ast_basic_directive(f, token, name.string);
// } else if (!lhs && name.string == "alias") { return ast_alias(f, token, parse_expr(f, false));
} else if (name.string == "caller_location") { return ast_basic_directive(f, token, name.string);
} else if (name.string == "location") {
AstNode *tag = ast_basic_directive(f, token, name.string);
return parse_call_expr(f, tag);
} else {
operand = ast_tag_expr(f, token, name, parse_expr(f, false));
}
@@ -2613,7 +2616,7 @@ AstNode *parse_gen_decl(AstFile *f, Token token, ParseSpecFunc *func) {
expect_semicolon(f, NULL);
}
} else {
array_init(&specs, heap_allocator(), 1);
specs = make_ast_node_array(f, 1);
AstNode *spec = func(f, token);
array_add(&specs, spec);
}
@@ -2942,9 +2945,8 @@ AstNode *parse_simple_stmt(AstFile *f, StmtAllowFlag flags) {
AstNode *expr = parse_expr(f, false);
f->allow_range = prev_allow_range;
Array<AstNode *> rhs = {};
array_init_count(&rhs, heap_allocator(), 1);
rhs[0] = expr;
Array<AstNode *> rhs = make_ast_node_array(f, 1);
array_add(&rhs, expr);
return ast_assign_stmt(f, token, lhs, rhs);
}
@@ -3031,8 +3033,8 @@ AstNode *parse_results(AstFile *f) {
}
AstNode *parse_proc_type(AstFile *f, Token proc_token, String *link_name_) {
AstNode *params = {};
AstNode *results = {};
AstNode *params = NULL;
AstNode *results = NULL;
expect_token(f, Token_OpenParen);
params = parse_field_list(f, NULL, FieldFlag_Signature, Token_CloseParen);
@@ -3166,8 +3168,7 @@ struct AstNodeAndFlags {
};
Array<AstNode *> convert_to_ident_list(AstFile *f, Array<AstNodeAndFlags> list, bool ignore_flags) {
Array<AstNode *> idents = {};
array_init(&idents, heap_allocator(), list.count);
Array<AstNode *> idents = make_ast_node_array(f, list.count);
// Convert to ident list
for_array(i, list) {
AstNode *ident = list[i].node;
@@ -3211,7 +3212,10 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
Token start_token = f->curr_token;
Array<AstNode *> params = make_ast_node_array(f);
Array<AstNodeAndFlags> list = {}; array_init(&list, heap_allocator()); // LEAK(bill):
Array<AstNodeAndFlags> list = {}; array_init(&list, heap_allocator());
defer (array_free(&list));
isize total_name_count = 0;
bool allow_ellipsis = allowed_flags&FieldFlag_ellipsis;
bool is_procedure = allowed_flags == FieldFlag_Signature;

View File

@@ -25,8 +25,11 @@ struct String {
// NOTE(bill): used for printf style arguments
#define LIT(x) ((int)(x).len), (x).text
#define STR_LIT(c_str) {cast(u8 *)c_str, gb_size_of(c_str)-1}
#define str_lit(c_str) String{cast(u8 *)c_str, gb_size_of(c_str)-1}
#if defined(GB_COMPILER_MSVC) && _MSC_VER < 1700
#define str_lit(c_str) make_string(cast(u8 *)c_str, gb_size_of(c_str)-1)
#else
#define str_lit(c_str) String{cast(u8 *)c_str, gb_size_of(c_str)-1}
#endif
// NOTE(bill): String16 is only used for Windows due to its file directories
struct String16 {

View File

@@ -321,35 +321,35 @@ gb_global Type *t_string_slice = NULL;
// Type generated for the "preload" file
gb_global Type *t_type_info = NULL;
gb_global Type *t_type_info_record = NULL;
gb_global Type *t_type_info_enum_value = NULL;
gb_global Type *t_type_info_ptr = NULL;
gb_global Type *t_type_info_record_ptr = NULL;
gb_global Type *t_type_info_enum_value_ptr = NULL;
gb_global Type *t_type_info = NULL;
gb_global Type *t_type_info_record = NULL;
gb_global Type *t_type_info_enum_value = NULL;
gb_global Type *t_type_info_ptr = NULL;
gb_global Type *t_type_info_record_ptr = NULL;
gb_global Type *t_type_info_enum_value_ptr = NULL;
gb_global Type *t_type_info_named = NULL;
gb_global Type *t_type_info_integer = NULL;
gb_global Type *t_type_info_rune = NULL;
gb_global Type *t_type_info_float = NULL;
gb_global Type *t_type_info_complex = NULL;
gb_global Type *t_type_info_any = NULL;
gb_global Type *t_type_info_string = NULL;
gb_global Type *t_type_info_boolean = NULL;
gb_global Type *t_type_info_pointer = NULL;
gb_global Type *t_type_info_atomic = NULL;
gb_global Type *t_type_info_procedure = NULL;
gb_global Type *t_type_info_array = NULL;
gb_global Type *t_type_info_dynamic_array = NULL;
gb_global Type *t_type_info_slice = NULL;
gb_global Type *t_type_info_vector = NULL;
gb_global Type *t_type_info_tuple = NULL;
gb_global Type *t_type_info_struct = NULL;
gb_global Type *t_type_info_raw_union = NULL;
gb_global Type *t_type_info_union = NULL;
gb_global Type *t_type_info_enum = NULL;
gb_global Type *t_type_info_map = NULL;
gb_global Type *t_type_info_bit_field = NULL;
gb_global Type *t_type_info_named = NULL;
gb_global Type *t_type_info_integer = NULL;
gb_global Type *t_type_info_rune = NULL;
gb_global Type *t_type_info_float = NULL;
gb_global Type *t_type_info_complex = NULL;
gb_global Type *t_type_info_any = NULL;
gb_global Type *t_type_info_string = NULL;
gb_global Type *t_type_info_boolean = NULL;
gb_global Type *t_type_info_pointer = NULL;
gb_global Type *t_type_info_atomic = NULL;
gb_global Type *t_type_info_procedure = NULL;
gb_global Type *t_type_info_array = NULL;
gb_global Type *t_type_info_dynamic_array = NULL;
gb_global Type *t_type_info_slice = NULL;
gb_global Type *t_type_info_vector = NULL;
gb_global Type *t_type_info_tuple = NULL;
gb_global Type *t_type_info_struct = NULL;
gb_global Type *t_type_info_raw_union = NULL;
gb_global Type *t_type_info_union = NULL;
gb_global Type *t_type_info_enum = NULL;
gb_global Type *t_type_info_map = NULL;
gb_global Type *t_type_info_bit_field = NULL;
gb_global Type *t_type_info_named_ptr = NULL;
gb_global Type *t_type_info_integer_ptr = NULL;
@@ -375,13 +375,16 @@ gb_global Type *t_type_info_enum_ptr = NULL;
gb_global Type *t_type_info_map_ptr = NULL;
gb_global Type *t_type_info_bit_field_ptr = NULL;
gb_global Type *t_allocator = NULL;
gb_global Type *t_allocator_ptr = NULL;
gb_global Type *t_context = NULL;
gb_global Type *t_context_ptr = NULL;
gb_global Type *t_allocator = NULL;
gb_global Type *t_allocator_ptr = NULL;
gb_global Type *t_context = NULL;
gb_global Type *t_context_ptr = NULL;
gb_global Type *t_map_key = NULL;
gb_global Type *t_map_header = NULL;
gb_global Type *t_source_code_location = NULL;
gb_global Type *t_source_code_location_ptr = NULL;
gb_global Type *t_map_key = NULL;
gb_global Type *t_map_header = NULL;