mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-02 20:58:15 +00:00
Minor refactor and basic library
This commit is contained in:
+37
-33
@@ -20,7 +20,7 @@ struct Operand {
|
||||
Type *type;
|
||||
ExactValue value;
|
||||
AstNode *expr;
|
||||
BuiltinProcedureId builtin_id;
|
||||
BuiltinProcId builtin_id;
|
||||
};
|
||||
|
||||
struct TypeAndValue {
|
||||
@@ -110,32 +110,34 @@ enum ExpressionKind {
|
||||
Expression_Statement,
|
||||
};
|
||||
|
||||
enum BuiltinProcedureId {
|
||||
BuiltinProcedure_Invalid,
|
||||
enum BuiltinProcId {
|
||||
BuiltinProc_Invalid,
|
||||
|
||||
BuiltinProcedure_size_of,
|
||||
BuiltinProcedure_size_of_val,
|
||||
BuiltinProcedure_align_of,
|
||||
BuiltinProcedure_align_of_val,
|
||||
BuiltinProcedure_offset_of,
|
||||
BuiltinProcedure_offset_of_val,
|
||||
BuiltinProcedure_static_assert,
|
||||
BuiltinProcedure_len,
|
||||
BuiltinProcedure_cap,
|
||||
BuiltinProcedure_copy,
|
||||
BuiltinProcedure_print,
|
||||
BuiltinProcedure_println,
|
||||
BuiltinProc_size_of,
|
||||
BuiltinProc_size_of_val,
|
||||
BuiltinProc_align_of,
|
||||
BuiltinProc_align_of_val,
|
||||
BuiltinProc_offset_of,
|
||||
BuiltinProc_offset_of_val,
|
||||
BuiltinProc_static_assert,
|
||||
BuiltinProc_len,
|
||||
BuiltinProc_cap,
|
||||
BuiltinProc_copy,
|
||||
BuiltinProc_append,
|
||||
BuiltinProc_print,
|
||||
BuiltinProc_println,
|
||||
|
||||
BuiltinProcedure_Count,
|
||||
BuiltinProc_Count,
|
||||
};
|
||||
struct BuiltinProcedure {
|
||||
struct BuiltinProc {
|
||||
String name;
|
||||
isize arg_count;
|
||||
b32 variadic;
|
||||
ExpressionKind kind;
|
||||
};
|
||||
gb_global BuiltinProcedure builtin_procedures[BuiltinProcedure_Count] = {
|
||||
gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
|
||||
{STR_LIT(""), 0, false, Expression_Statement},
|
||||
|
||||
{STR_LIT("size_of"), 1, false, Expression_Expression},
|
||||
{STR_LIT("size_of_val"), 1, false, Expression_Expression},
|
||||
{STR_LIT("align_of"), 1, false, Expression_Expression},
|
||||
@@ -143,9 +145,11 @@ gb_global BuiltinProcedure builtin_procedures[BuiltinProcedure_Count] = {
|
||||
{STR_LIT("offset_of"), 2, false, Expression_Expression},
|
||||
{STR_LIT("offset_of_val"), 1, false, Expression_Expression},
|
||||
{STR_LIT("static_assert"), 1, false, Expression_Statement},
|
||||
|
||||
{STR_LIT("len"), 1, false, Expression_Expression},
|
||||
{STR_LIT("cap"), 1, false, Expression_Expression},
|
||||
{STR_LIT("copy"), 2, false, Expression_Expression},
|
||||
{STR_LIT("append"), 2, false, Expression_Expression},
|
||||
{STR_LIT("print"), 1, true, Expression_Statement},
|
||||
{STR_LIT("println"), 1, true, Expression_Statement},
|
||||
};
|
||||
@@ -172,14 +176,14 @@ struct Checker {
|
||||
AstFile * curr_ast_file;
|
||||
BaseTypeSizes sizes;
|
||||
Scope * global_scope;
|
||||
gbArray(ProcedureInfo) procedures; // NOTE(bill): Procedures to check
|
||||
gbArray(ProcedureInfo) procs; // NOTE(bill): Procedures to check
|
||||
|
||||
gbArena arena;
|
||||
gbAllocator allocator;
|
||||
|
||||
CheckerContext context;
|
||||
|
||||
gbArray(Type *) procedure_stack;
|
||||
gbArray(Type *) proc_stack;
|
||||
b32 in_defer; // TODO(bill): Actually handle correctly
|
||||
|
||||
ErrorCollector error_collector;
|
||||
@@ -334,10 +338,10 @@ void init_universal_scope(void) {
|
||||
add_global_constant(a, make_string("null"), t_untyped_pointer, make_exact_value_pointer(NULL));
|
||||
|
||||
// Builtin Procedures
|
||||
for (isize i = 0; i < gb_count_of(builtin_procedures); i++) {
|
||||
BuiltinProcedureId id = cast(BuiltinProcedureId)i;
|
||||
for (isize i = 0; i < gb_count_of(builtin_procs); i++) {
|
||||
BuiltinProcId id = cast(BuiltinProcId)i;
|
||||
Token token = {Token_Identifier};
|
||||
token.string = builtin_procedures[i].name;
|
||||
token.string = builtin_procs[i].name;
|
||||
Entity *entity = alloc_entity(a, Entity_Builtin, NULL, token, t_invalid);
|
||||
entity->builtin.id = id;
|
||||
add_global_entity(entity);
|
||||
@@ -376,8 +380,8 @@ void init_checker(Checker *c, Parser *parser) {
|
||||
c->sizes.word_size = 8;
|
||||
c->sizes.max_align = 8;
|
||||
|
||||
gb_array_init(c->procedure_stack, a);
|
||||
gb_array_init(c->procedures, a);
|
||||
gb_array_init(c->proc_stack, a);
|
||||
gb_array_init(c->procs, a);
|
||||
|
||||
// NOTE(bill): Is this big enough or too small?
|
||||
isize item_size = gb_max(gb_max(gb_size_of(Entity), gb_size_of(Type)), gb_size_of(Scope));
|
||||
@@ -397,8 +401,8 @@ void init_checker(Checker *c, Parser *parser) {
|
||||
void destroy_checker(Checker *c) {
|
||||
destroy_checker_info(&c->info);
|
||||
destroy_scope(c->global_scope);
|
||||
gb_array_free(c->procedure_stack);
|
||||
gb_array_free(c->procedures);
|
||||
gb_array_free(c->proc_stack);
|
||||
gb_array_free(c->procs);
|
||||
|
||||
gb_arena_free(&c->arena);
|
||||
}
|
||||
@@ -500,7 +504,7 @@ void check_procedure_later(Checker *c, AstFile *file, Token token, DeclInfo *dec
|
||||
info.decl = decl;
|
||||
info.type = type;
|
||||
info.body = body;
|
||||
gb_array_append(c->procedures, info);
|
||||
gb_array_append(c->procs, info);
|
||||
}
|
||||
|
||||
void check_add_deferred_stmt(Checker *c, AstNode *stmt) {
|
||||
@@ -509,12 +513,12 @@ void check_add_deferred_stmt(Checker *c, AstNode *stmt) {
|
||||
gb_array_append(c->context.scope->deferred_stmts, stmt);
|
||||
}
|
||||
|
||||
void push_procedure(Checker *c, Type *procedure_type) {
|
||||
gb_array_append(c->procedure_stack, procedure_type);
|
||||
void push_procedure(Checker *c, Type *type) {
|
||||
gb_array_append(c->proc_stack, type);
|
||||
}
|
||||
|
||||
void pop_procedure(Checker *c) {
|
||||
gb_array_pop(c->procedure_stack);
|
||||
gb_array_pop(c->proc_stack);
|
||||
}
|
||||
|
||||
void add_curr_ast_file(Checker *c, AstFile *file) {
|
||||
@@ -655,8 +659,8 @@ void check_parsed_files(Checker *c) {
|
||||
|
||||
|
||||
// Check procedure bodies
|
||||
gb_for_array(i, c->procedures) {
|
||||
ProcedureInfo *pi = &c->procedures[i];
|
||||
gb_for_array(i, c->procs) {
|
||||
ProcedureInfo *pi = &c->procs[i];
|
||||
add_curr_ast_file(c, pi->file);
|
||||
check_proc_body(c, pi->token, pi->decl, pi->type, pi->body);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
struct Scope;
|
||||
struct Checker;
|
||||
enum BuiltinProcedureId;
|
||||
enum BuiltinProcId;
|
||||
|
||||
#define ENTITY_KINDS \
|
||||
ENTITY_KIND(Invalid), \
|
||||
@@ -47,7 +47,7 @@ struct Entity {
|
||||
struct {} type_name;
|
||||
struct {} alias_name;
|
||||
struct {} procedure;
|
||||
struct { BuiltinProcedureId id; } builtin;
|
||||
struct { BuiltinProcId id; } builtin;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -105,7 +105,7 @@ Entity *make_entity_procedure(gbAllocator a, Scope *parent, Token token, Type *s
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_builtin(gbAllocator a, Scope *parent, Token token, Type *type, BuiltinProcedureId id) {
|
||||
Entity *make_entity_builtin(gbAllocator a, Scope *parent, Token token, Type *type, BuiltinProcId id) {
|
||||
Entity *entity = alloc_entity(a, Entity_Builtin, parent, token, type);
|
||||
entity->builtin.id = id;
|
||||
return entity;
|
||||
|
||||
+93
-56
@@ -105,11 +105,6 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *list, isize list_coun
|
||||
Entity *param = make_entity_param(c->allocator, scope, token, type);
|
||||
// NOTE(bill): No need to record
|
||||
variables[variable_index++] = param;
|
||||
|
||||
if (get_base_type(type)->kind == Type_Array) {
|
||||
// TODO(bill): Should I allow array's to returned?
|
||||
error(&c->error_collector, token, "You cannot return an array from a procedure");
|
||||
}
|
||||
}
|
||||
tuple->tuple.variables = variables;
|
||||
tuple->tuple.variable_count = list_count;
|
||||
@@ -129,11 +124,11 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) {
|
||||
Type *params = check_get_params(c, c->context.scope, pt->param_list, param_count);
|
||||
Type *results = check_get_results(c, c->context.scope, pt->result_list, result_count);
|
||||
|
||||
type->procedure.scope = c->context.scope;
|
||||
type->procedure.params = params;
|
||||
type->procedure.param_count = pt->param_count;
|
||||
type->procedure.results = results;
|
||||
type->procedure.result_count = pt->result_count;
|
||||
type->proc.scope = c->context.scope;
|
||||
type->proc.params = params;
|
||||
type->proc.param_count = pt->param_count;
|
||||
type->proc.results = results;
|
||||
type->proc.result_count = pt->result_count;
|
||||
}
|
||||
|
||||
|
||||
@@ -292,7 +287,7 @@ Type *check_type_expr_extra(Checker *c, AstNode *e, Type *named_type) {
|
||||
case_end;
|
||||
|
||||
case_ast_node(pt, ProcType, e);
|
||||
Type *t = alloc_type(c->allocator, Type_Procedure);
|
||||
Type *t = alloc_type(c->allocator, Type_Proc);
|
||||
set_base_type(named_type, t);
|
||||
check_open_scope(c, e);
|
||||
check_procedure_type(c, t, e);
|
||||
@@ -384,7 +379,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type) {
|
||||
case_end;
|
||||
|
||||
case_ast_node(pt, ProcType, e);
|
||||
type = alloc_type(c->allocator, Type_Procedure);
|
||||
type = alloc_type(c->allocator, Type_Proc);
|
||||
set_base_type(named_type, type);
|
||||
check_procedure_type(c, type, e);
|
||||
goto end;
|
||||
@@ -958,7 +953,7 @@ Entity *lookup_field(Type *type, AstNode *field_node, isize *index = NULL) {
|
||||
GB_ASSERT(field_node->kind == AstNode_Ident);
|
||||
type = get_base_type(type);
|
||||
if (type->kind == Type_Pointer)
|
||||
type = get_base_type(type->pointer.element);
|
||||
type = get_base_type(type->pointer.elem);
|
||||
|
||||
ast_node(i, Ident, field_node);
|
||||
String field_str = i->token.string;
|
||||
@@ -1016,7 +1011,7 @@ void check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||
b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) {
|
||||
GB_ASSERT(call->kind == AstNode_CallExpr);
|
||||
ast_node(ce, CallExpr, call);
|
||||
BuiltinProcedure *bp = &builtin_procedures[id];
|
||||
BuiltinProc *bp = &builtin_procs[id];
|
||||
{
|
||||
char *err = NULL;
|
||||
if (ce->arg_list_count < bp->arg_count)
|
||||
@@ -1033,9 +1028,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
}
|
||||
|
||||
switch (id) {
|
||||
case BuiltinProcedure_size_of:
|
||||
case BuiltinProcedure_align_of:
|
||||
case BuiltinProcedure_offset_of:
|
||||
case BuiltinProc_size_of:
|
||||
case BuiltinProc_align_of:
|
||||
case BuiltinProc_offset_of:
|
||||
// NOTE(bill): The first arg is a Type, this will be checked case by case
|
||||
break;
|
||||
default:
|
||||
@@ -1043,7 +1038,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
}
|
||||
|
||||
switch (id) {
|
||||
case BuiltinProcedure_size_of: {
|
||||
case BuiltinProc_size_of: {
|
||||
// size_of :: proc(Type)
|
||||
Type *type = check_type(c, ce->arg_list);
|
||||
if (!type) {
|
||||
@@ -1057,7 +1052,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
|
||||
} break;
|
||||
|
||||
case BuiltinProcedure_size_of_val:
|
||||
case BuiltinProc_size_of_val:
|
||||
// size_of_val :: proc(val)
|
||||
check_assignment(c, operand, NULL, make_string("argument of `size_of`"));
|
||||
if (operand->mode == Addressing_Invalid)
|
||||
@@ -1068,7 +1063,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
operand->type = t_int;
|
||||
break;
|
||||
|
||||
case BuiltinProcedure_align_of: {
|
||||
case BuiltinProc_align_of: {
|
||||
// align_of :: proc(Type)
|
||||
Type *type = check_type(c, ce->arg_list);
|
||||
if (!type) {
|
||||
@@ -1080,7 +1075,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
operand->type = t_int;
|
||||
} break;
|
||||
|
||||
case BuiltinProcedure_align_of_val:
|
||||
case BuiltinProc_align_of_val:
|
||||
// align_of_val :: proc(val)
|
||||
check_assignment(c, operand, NULL, make_string("argument of `align_of`"));
|
||||
if (operand->mode == Addressing_Invalid)
|
||||
@@ -1091,7 +1086,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
operand->type = t_int;
|
||||
break;
|
||||
|
||||
case BuiltinProcedure_offset_of: {
|
||||
case BuiltinProc_offset_of: {
|
||||
// offset_val :: proc(Type, field)
|
||||
Type *type = get_base_type(check_type(c, ce->arg_list));
|
||||
AstNode *field_arg = unparen_expr(ce->arg_list->next);
|
||||
@@ -1122,7 +1117,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
operand->type = t_int;
|
||||
} break;
|
||||
|
||||
case BuiltinProcedure_offset_of_val: {
|
||||
case BuiltinProc_offset_of_val: {
|
||||
// offset_val :: proc(val)
|
||||
AstNode *arg = unparen_expr(ce->arg_list);
|
||||
if (arg->kind != AstNode_SelectorExpr) {
|
||||
@@ -1140,7 +1135,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
if (get_base_type(type)->kind == Type_Pointer) {
|
||||
Type *p = get_base_type(type);
|
||||
if (get_base_type(p)->kind == Type_Structure)
|
||||
type = p->pointer.element;
|
||||
type = p->pointer.elem;
|
||||
}
|
||||
|
||||
isize index = 0;
|
||||
@@ -1158,7 +1153,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
operand->type = t_int;
|
||||
} break;
|
||||
|
||||
case BuiltinProcedure_static_assert:
|
||||
case BuiltinProc_static_assert:
|
||||
// static_assert :: proc(cond: bool)
|
||||
// TODO(bill): Should `static_assert` and `assert` be unified?
|
||||
|
||||
@@ -1180,8 +1175,8 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
break;
|
||||
|
||||
// TODO(bill): Should these be procedures and are their names appropriate?
|
||||
case BuiltinProcedure_len:
|
||||
case BuiltinProcedure_cap: {
|
||||
case BuiltinProc_len:
|
||||
case BuiltinProc_cap: {
|
||||
Type *t = get_base_type(operand->type);
|
||||
|
||||
AddressingMode mode = Addressing_Invalid;
|
||||
@@ -1189,7 +1184,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
if (id == BuiltinProcedure_len) {
|
||||
if (id == BuiltinProc_len) {
|
||||
if (is_type_string(t)) {
|
||||
if (operand->mode == Addressing_Constant) {
|
||||
mode = Addressing_Constant;
|
||||
@@ -1226,14 +1221,13 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
|
||||
} break;
|
||||
|
||||
// TODO(bill): copy() pointer version?
|
||||
case BuiltinProcedure_copy: {
|
||||
case BuiltinProc_copy: {
|
||||
// copy :: proc(x, y: []Type) -> int
|
||||
Type *dest_type = NULL, *src_type = NULL;
|
||||
|
||||
Type *d = get_base_type(operand->type);
|
||||
if (d->kind == Type_Slice)
|
||||
dest_type = d->slice.element;
|
||||
dest_type = d->slice.elem;
|
||||
|
||||
Operand op = {};
|
||||
check_expr(c, &op, ce->arg_list->next);
|
||||
@@ -1241,7 +1235,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
return false;
|
||||
Type *s = get_base_type(op.type);
|
||||
if (s->kind == Type_Slice)
|
||||
src_type = s->slice.element;
|
||||
src_type = s->slice.elem;
|
||||
|
||||
if (dest_type == NULL || src_type == NULL) {
|
||||
error(&c->error_collector, ast_node_token(call), "`copy` only expects slices as arguments");
|
||||
@@ -1258,20 +1252,56 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
defer (gb_string_free(d_str));
|
||||
defer (gb_string_free(s_str));
|
||||
error(&c->error_collector, ast_node_token(call),
|
||||
"Arguments to `copy`, %s, %s, have different element types: %s vs %s",
|
||||
"Arguments to `copy`, %s, %s, have different elem types: %s vs %s",
|
||||
d_arg, s_arg, d_str, s_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->type = t_int; // Returns number of elements copied
|
||||
operand->type = t_int; // Returns number of elems copied
|
||||
operand->mode = Addressing_Value;
|
||||
} break;
|
||||
|
||||
case BuiltinProcedure_print:
|
||||
case BuiltinProcedure_println: {
|
||||
case BuiltinProc_append: {
|
||||
// append :: proc(x : ^[]Type, y : Type) -> bool
|
||||
Type *x_type = NULL, *y_type = NULL;
|
||||
x_type = get_base_type(operand->type);
|
||||
|
||||
Operand op = {};
|
||||
check_expr(c, &op, ce->arg_list->next);
|
||||
if (op.mode == Addressing_Invalid)
|
||||
return false;
|
||||
y_type = get_base_type(op.type);
|
||||
|
||||
if (!(is_type_pointer(x_type) && is_type_slice(x_type->pointer.elem))) {
|
||||
error(&c->error_collector, ast_node_token(call), "First argument to `append` must be a pointer to a slice");
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *elem_type = x_type->pointer.elem->slice.elem;
|
||||
if (!check_is_assignable_to(c, &op, elem_type)) {
|
||||
gbString d_arg = expr_to_string(ce->arg_list);
|
||||
gbString s_arg = expr_to_string(ce->arg_list->next);
|
||||
gbString d_str = type_to_string(elem_type);
|
||||
gbString s_str = type_to_string(y_type);
|
||||
defer (gb_string_free(d_arg));
|
||||
defer (gb_string_free(s_arg));
|
||||
defer (gb_string_free(d_str));
|
||||
defer (gb_string_free(s_str));
|
||||
error(&c->error_collector, ast_node_token(call),
|
||||
"Arguments to `append`, %s, %s, have different element types: %s vs %s",
|
||||
d_arg, s_arg, d_str, s_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->type = t_bool; // Returns if it was successful
|
||||
operand->mode = Addressing_Value;
|
||||
} break;
|
||||
|
||||
case BuiltinProc_print:
|
||||
case BuiltinProc_println: {
|
||||
for (AstNode *arg = ce->arg_list; arg != NULL; arg = arg->next) {
|
||||
// TOOD(bill): `check_assignment` doesn't allow tuples at the moment, should it?
|
||||
// Or should we destruct the tuple and use each element?
|
||||
// Or should we destruct the tuple and use each elem?
|
||||
check_assignment(c, operand, NULL, make_string("argument"));
|
||||
if (operand->mode == Addressing_Invalid)
|
||||
return false;
|
||||
@@ -1285,14 +1315,14 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
|
||||
void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode *call) {
|
||||
GB_ASSERT(call->kind == AstNode_CallExpr);
|
||||
GB_ASSERT(proc_type->kind == Type_Procedure);
|
||||
GB_ASSERT(proc_type->kind == Type_Proc);
|
||||
ast_node(ce, CallExpr, call);
|
||||
isize error_code = 0;
|
||||
isize param_index = 0;
|
||||
isize param_count = 0;
|
||||
|
||||
if (proc_type->procedure.params)
|
||||
param_count = proc_type->procedure.params->tuple.variable_count;
|
||||
if (proc_type->proc.params)
|
||||
param_count = proc_type->proc.params->tuple.variable_count;
|
||||
|
||||
if (ce->arg_list_count == 0 && param_count == 0)
|
||||
return;
|
||||
@@ -1300,7 +1330,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
|
||||
if (ce->arg_list_count > param_count) {
|
||||
error_code = +1;
|
||||
} else {
|
||||
Entity **sig_params = proc_type->procedure.params->tuple.variables;
|
||||
Entity **sig_params = proc_type->proc.params->tuple.variables;
|
||||
AstNode *call_arg = ce->arg_list;
|
||||
for (; call_arg != NULL; call_arg = call_arg->next) {
|
||||
check_multi_expr(c, operand, call_arg);
|
||||
@@ -1376,11 +1406,11 @@ ExpressionKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
|
||||
if (!check_builtin_procedure(c, operand, call, id))
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->expr = call;
|
||||
return builtin_procedures[id].kind;
|
||||
return builtin_procs[id].kind;
|
||||
}
|
||||
|
||||
Type *proc_type = get_base_type(operand->type);
|
||||
if (proc_type == NULL || proc_type->kind != Type_Procedure) {
|
||||
if (proc_type == NULL || proc_type->kind != Type_Proc) {
|
||||
AstNode *e = operand->expr;
|
||||
gbString str = expr_to_string(e);
|
||||
defer (gb_string_free(str));
|
||||
@@ -1395,7 +1425,7 @@ ExpressionKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
|
||||
|
||||
check_call_arguments(c, operand, proc_type, call);
|
||||
|
||||
auto *proc = &proc_type->procedure;
|
||||
auto *proc = &proc_type->proc;
|
||||
if (proc->result_count == 0) {
|
||||
operand->mode = Addressing_NoValue;
|
||||
} else if (proc->result_count == 1) {
|
||||
@@ -1448,6 +1478,14 @@ b32 check_castable_to(Checker *c, Operand *operand, Type *y) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// []byte/[]u8 <-> string
|
||||
if (is_type_byte_slice(xb) && is_type_string(yb)) {
|
||||
return true;
|
||||
}
|
||||
if (is_type_string(xb) && is_type_byte_slice(yb)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1590,13 +1628,13 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
|
||||
case Type_Slice:
|
||||
case Type_Array:
|
||||
{
|
||||
Type *element_type = NULL;
|
||||
Type *elem_type = NULL;
|
||||
String context_name = {};
|
||||
if (t->kind == Type_Slice) {
|
||||
element_type = t->slice.element;
|
||||
elem_type = t->slice.elem;
|
||||
context_name = make_string("slice literal");
|
||||
} else {
|
||||
element_type = t->array.element;
|
||||
elem_type = t->array.elem;
|
||||
context_name = make_string("array literal");
|
||||
}
|
||||
|
||||
@@ -1612,8 +1650,8 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
|
||||
}
|
||||
|
||||
Operand o = {};
|
||||
check_expr_with_type_hint(c, &o, e, element_type);
|
||||
check_assignment(c, &o, element_type, context_name);
|
||||
check_expr_with_type_hint(c, &o, e, elem_type);
|
||||
check_assignment(c, &o, elem_type, context_name);
|
||||
}
|
||||
if (max < index)
|
||||
max = index;
|
||||
@@ -1693,19 +1731,19 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
|
||||
max_count = t->array.count;
|
||||
if (o->mode != Addressing_Variable)
|
||||
o->mode = Addressing_Value;
|
||||
o->type = t->array.element;
|
||||
o->type = t->array.elem;
|
||||
break;
|
||||
|
||||
case Type_Slice:
|
||||
valid = true;
|
||||
o->type = t->slice.element;
|
||||
o->type = t->slice.elem;
|
||||
o->mode = Addressing_Variable;
|
||||
break;
|
||||
|
||||
case Type_Pointer:
|
||||
valid = true;
|
||||
o->mode = Addressing_Variable;
|
||||
o->type = get_base_type(t->pointer.element);
|
||||
o->type = get_base_type(t->pointer.elem);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1757,7 +1795,7 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
|
||||
gb_string_free(str);
|
||||
goto error;
|
||||
}
|
||||
o->type = make_type_slice(c->allocator, t->array.element);
|
||||
o->type = make_type_slice(c->allocator, t->array.elem);
|
||||
o->mode = Addressing_Value;
|
||||
break;
|
||||
|
||||
@@ -1768,7 +1806,7 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
|
||||
|
||||
case Type_Pointer:
|
||||
valid = true;
|
||||
o->type = make_type_slice(c->allocator, get_base_type(t->pointer.element));
|
||||
o->type = make_type_slice(c->allocator, get_base_type(t->pointer.elem));
|
||||
o->mode = Addressing_Value;
|
||||
break;
|
||||
}
|
||||
@@ -1832,7 +1870,7 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
|
||||
Type *t = get_base_type(o->type);
|
||||
if (t->kind == Type_Pointer) {
|
||||
o->mode = Addressing_Variable;
|
||||
o->type = t->pointer.element;
|
||||
o->type = t->pointer.elem;
|
||||
} else {
|
||||
gbString str = expr_to_string(o->expr);
|
||||
error(&c->error_collector, ast_node_token(o->expr), "Cannot dereference `%s`", str);
|
||||
@@ -1911,7 +1949,6 @@ void check_multi_expr(Checker *c, Operand *o, AstNode *e) {
|
||||
o->mode = Addressing_Invalid;
|
||||
}
|
||||
|
||||
// TODO(bill): Should I remove this entirely?
|
||||
void check_not_tuple(Checker *c, Operand *o) {
|
||||
if (o->mode == Addressing_Value) {
|
||||
// NOTE(bill): Tuples are not first class thus never named
|
||||
|
||||
@@ -108,13 +108,13 @@ b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type) {
|
||||
return true;
|
||||
|
||||
if (sb->kind == Type_Array && tb->kind == Type_Array) {
|
||||
if (are_types_identical(sb->array.element, tb->array.element)) {
|
||||
if (are_types_identical(sb->array.elem, tb->array.elem)) {
|
||||
return sb->array.count == tb->array.count;
|
||||
}
|
||||
}
|
||||
|
||||
if (sb->kind == Type_Slice && tb->kind == Type_Slice) {
|
||||
if (are_types_identical(sb->slice.element, tb->slice.element)) {
|
||||
if (are_types_identical(sb->slice.elem, tb->slice.elem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -391,7 +391,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
push_procedure(c, type);
|
||||
ast_node(bs, BlockStmt, body);
|
||||
check_stmt_list(c, bs->list, 0);
|
||||
if (type->procedure.result_count > 0) {
|
||||
if (type->proc.result_count > 0) {
|
||||
if (!check_is_terminating(c, body)) {
|
||||
error(&c->error_collector, bs->close, "Missing return statement at the end of the procedure");
|
||||
}
|
||||
@@ -404,7 +404,7 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
void check_proc_decl(Checker *c, Entity *e, DeclInfo *d, b32 check_body_later) {
|
||||
GB_ASSERT(e->type == NULL);
|
||||
|
||||
Type *proc_type = make_type_procedure(c->allocator, e->parent, NULL, 0, NULL, 0);
|
||||
Type *proc_type = make_type_proc(c->allocator, e->parent, NULL, 0, NULL, 0);
|
||||
e->type = proc_type;
|
||||
ast_node(pd, ProcDecl, d->proc_decl);
|
||||
|
||||
@@ -701,7 +701,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
case_end;
|
||||
|
||||
case_ast_node(rs, ReturnStmt, node);
|
||||
GB_ASSERT(gb_array_count(c->procedure_stack) > 0);
|
||||
GB_ASSERT(gb_array_count(c->proc_stack) > 0);
|
||||
|
||||
if (c->in_defer) {
|
||||
error(&c->error_collector, rs->token, "You cannot `return` within a defer statement");
|
||||
@@ -709,17 +709,17 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
break;
|
||||
}
|
||||
|
||||
Type *proc_type = c->procedure_stack[gb_array_count(c->procedure_stack)-1];
|
||||
Type *proc_type = c->proc_stack[gb_array_count(c->proc_stack)-1];
|
||||
isize result_count = 0;
|
||||
if (proc_type->procedure.results)
|
||||
result_count = proc_type->procedure.results->tuple.variable_count;
|
||||
if (proc_type->proc.results)
|
||||
result_count = proc_type->proc.results->tuple.variable_count;
|
||||
if (result_count != rs->result_count) {
|
||||
error(&c->error_collector, rs->token, "Expected %td return %s, got %td",
|
||||
result_count,
|
||||
(result_count != 1 ? "values" : "value"),
|
||||
rs->result_count);
|
||||
} else if (result_count > 0) {
|
||||
auto *tuple = &proc_type->procedure.results->tuple;
|
||||
auto *tuple = &proc_type->proc.results->tuple;
|
||||
check_init_variables(c, tuple->variables, tuple->variable_count,
|
||||
rs->result_list, rs->result_count, make_string("return statement"));
|
||||
}
|
||||
|
||||
+53
-39
@@ -62,7 +62,7 @@ struct BasicType {
|
||||
TYPE_KIND(Named), \
|
||||
TYPE_KIND(Alias), \
|
||||
TYPE_KIND(Tuple), \
|
||||
TYPE_KIND(Procedure), \
|
||||
TYPE_KIND(Proc), \
|
||||
TYPE_KIND(Count),
|
||||
|
||||
enum TypeKind {
|
||||
@@ -82,11 +82,11 @@ struct Type {
|
||||
union {
|
||||
BasicType basic;
|
||||
struct {
|
||||
Type *element;
|
||||
Type *elem;
|
||||
i64 count;
|
||||
} array;
|
||||
struct {
|
||||
Type *element;
|
||||
Type *elem;
|
||||
} slice;
|
||||
struct {
|
||||
// Theses are arrays
|
||||
@@ -95,7 +95,7 @@ struct Type {
|
||||
i64 * offsets;
|
||||
b32 are_offsets_set;
|
||||
} structure;
|
||||
struct { Type *element; } pointer;
|
||||
struct { Type *elem; } pointer;
|
||||
struct {
|
||||
String name;
|
||||
Type * base;
|
||||
@@ -116,7 +116,7 @@ struct Type {
|
||||
Type * results; // Type_Tuple
|
||||
isize param_count;
|
||||
isize result_count;
|
||||
} procedure;
|
||||
} proc;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -152,16 +152,16 @@ Type *make_type_basic(gbAllocator a, BasicType basic) {
|
||||
return t;
|
||||
}
|
||||
|
||||
Type *make_type_array(gbAllocator a, Type *element, i64 count) {
|
||||
Type *make_type_array(gbAllocator a, Type *elem, i64 count) {
|
||||
Type *t = alloc_type(a, Type_Array);
|
||||
t->array.element = element;
|
||||
t->array.elem = elem;
|
||||
t->array.count = count;
|
||||
return t;
|
||||
}
|
||||
|
||||
Type *make_type_slice(gbAllocator a, Type *element) {
|
||||
Type *make_type_slice(gbAllocator a, Type *elem) {
|
||||
Type *t = alloc_type(a, Type_Slice);
|
||||
t->array.element = element;
|
||||
t->array.elem = elem;
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -170,9 +170,9 @@ Type *make_type_structure(gbAllocator a) {
|
||||
return t;
|
||||
}
|
||||
|
||||
Type *make_type_pointer(gbAllocator a, Type *element) {
|
||||
Type *make_type_pointer(gbAllocator a, Type *elem) {
|
||||
Type *t = alloc_type(a, Type_Pointer);
|
||||
t->pointer.element = element;
|
||||
t->pointer.elem = elem;
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -197,20 +197,20 @@ Type *make_type_tuple(gbAllocator a) {
|
||||
return t;
|
||||
}
|
||||
|
||||
Type *make_type_procedure(gbAllocator a, Scope *scope, Type *params, isize param_count, Type *results, isize result_count) {
|
||||
Type *t = alloc_type(a, Type_Procedure);
|
||||
t->procedure.scope = scope;
|
||||
t->procedure.params = params;
|
||||
t->procedure.param_count = param_count;
|
||||
t->procedure.results = results;
|
||||
t->procedure.result_count = result_count;
|
||||
Type *make_type_proc(gbAllocator a, Scope *scope, Type *params, isize param_count, Type *results, isize result_count) {
|
||||
Type *t = alloc_type(a, Type_Proc);
|
||||
t->proc.scope = scope;
|
||||
t->proc.params = params;
|
||||
t->proc.param_count = param_count;
|
||||
t->proc.results = results;
|
||||
t->proc.result_count = result_count;
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
Type *type_deref(Type *t) {
|
||||
if (t != NULL && t->kind == Type_Pointer)
|
||||
return t->pointer.element;
|
||||
return t->pointer.elem;
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -338,12 +338,26 @@ b32 is_type_int_or_uint(Type *t) {
|
||||
return (t->basic.kind == Basic_int) || (t->basic.kind == Basic_uint);
|
||||
return false;
|
||||
}
|
||||
|
||||
b32 is_type_rawptr(Type *t) {
|
||||
if (t->kind == Type_Basic)
|
||||
return t->basic.kind == Basic_rawptr;
|
||||
return false;
|
||||
}
|
||||
b32 is_type_byte(Type *t) {
|
||||
if (t->kind == Type_Basic)
|
||||
return t->basic.kind == Basic_byte;
|
||||
return false;
|
||||
}
|
||||
b32 is_type_slice(Type *t) {
|
||||
return t->kind == Type_Slice;
|
||||
}
|
||||
|
||||
|
||||
b32 is_type_byte_slice(Type *t) {
|
||||
if (t->kind == Type_Slice)
|
||||
return is_type_byte(t->slice.elem);
|
||||
return false;
|
||||
}
|
||||
|
||||
b32 is_type_comparable(Type *t) {
|
||||
t = get_base_type(t);
|
||||
@@ -360,7 +374,7 @@ b32 is_type_comparable(Type *t) {
|
||||
return true;
|
||||
} break;
|
||||
case Type_Array:
|
||||
return is_type_comparable(t->array.element);
|
||||
return is_type_comparable(t->array.elem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -382,7 +396,7 @@ b32 are_types_identical(Type *x, Type *y) {
|
||||
|
||||
case Type_Array:
|
||||
if (y->kind == Type_Array)
|
||||
return (x->array.count == y->array.count) && are_types_identical(x->array.element, y->array.element);
|
||||
return (x->array.count == y->array.count) && are_types_identical(x->array.elem, y->array.elem);
|
||||
break;
|
||||
|
||||
case Type_Structure:
|
||||
@@ -401,7 +415,7 @@ b32 are_types_identical(Type *x, Type *y) {
|
||||
|
||||
case Type_Pointer:
|
||||
if (y->kind == Type_Pointer)
|
||||
return are_types_identical(x->pointer.element, y->pointer.element);
|
||||
return are_types_identical(x->pointer.elem, y->pointer.elem);
|
||||
break;
|
||||
|
||||
|
||||
@@ -426,10 +440,10 @@ b32 are_types_identical(Type *x, Type *y) {
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Procedure:
|
||||
if (y->kind == Type_Procedure) {
|
||||
return are_types_identical(x->procedure.params, y->procedure.params) &&
|
||||
are_types_identical(x->procedure.results, y->procedure.results);
|
||||
case Type_Proc:
|
||||
if (y->kind == Type_Proc) {
|
||||
return are_types_identical(x->proc.params, y->proc.params) &&
|
||||
are_types_identical(x->proc.results, y->proc.results);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -457,7 +471,7 @@ Type *default_type(Type *type) {
|
||||
// NOTE(bill): Internal sizes of certain types
|
||||
// string: 2*word_size (ptr+len)
|
||||
// slice: 3*word_size (ptr+len+cap)
|
||||
// array: count*size_of(element) aligned
|
||||
// array: count*size_of(elem) aligned
|
||||
|
||||
// NOTE(bill): Alignment of structures and other types are to be compatible with C
|
||||
|
||||
@@ -497,7 +511,7 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
||||
|
||||
switch (t->kind) {
|
||||
case Type_Array:
|
||||
return type_align_of(s, allocator, t->array.element);
|
||||
return type_align_of(s, allocator, t->array.elem);
|
||||
case Type_Structure: {
|
||||
i64 max = 1;
|
||||
for (isize i = 0; i < t->structure.field_count; i++) {
|
||||
@@ -555,8 +569,8 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
||||
i64 count = t->array.count;
|
||||
if (count == 0)
|
||||
return 0;
|
||||
i64 align = type_align_of(s, allocator, t->array.element);
|
||||
i64 size = type_size_of(s, allocator, t->array.element);
|
||||
i64 align = type_align_of(s, allocator, t->array.elem);
|
||||
i64 size = type_size_of(s, allocator, t->array.elem);
|
||||
i64 alignment = align_formula(size, align);
|
||||
return alignment*(count-1) + size;
|
||||
} break;
|
||||
@@ -600,12 +614,12 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
|
||||
case Type_Array:
|
||||
str = gb_string_appendc(str, gb_bprintf("[%td]", type->array.count));
|
||||
str = write_type_to_string(str, type->array.element);
|
||||
str = write_type_to_string(str, type->array.elem);
|
||||
break;
|
||||
|
||||
case Type_Slice:
|
||||
str = gb_string_appendc(str, "[]");
|
||||
str = write_type_to_string(str, type->array.element);
|
||||
str = write_type_to_string(str, type->array.elem);
|
||||
break;
|
||||
|
||||
case Type_Structure: {
|
||||
@@ -624,7 +638,7 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
|
||||
case Type_Pointer:
|
||||
str = gb_string_appendc(str, "^");
|
||||
str = write_type_to_string(str, type->pointer.element);
|
||||
str = write_type_to_string(str, type->pointer.elem);
|
||||
break;
|
||||
|
||||
case Type_Named:
|
||||
@@ -657,14 +671,14 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Procedure:
|
||||
case Type_Proc:
|
||||
str = gb_string_appendc(str, "proc(");
|
||||
if (type->procedure.params)
|
||||
str = write_type_to_string(str, type->procedure.params);
|
||||
if (type->proc.params)
|
||||
str = write_type_to_string(str, type->proc.params);
|
||||
str = gb_string_appendc(str, ")");
|
||||
if (type->procedure.results) {
|
||||
if (type->proc.results) {
|
||||
str = gb_string_appendc(str, " -> ");
|
||||
str = write_type_to_string(str, type->procedure.results);
|
||||
str = write_type_to_string(str, type->proc.results);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user