mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-20 12:44:59 -07:00
Untyped nil
This commit is contained in:
+17
-3
@@ -33,6 +33,10 @@ struct Operand {
|
||||
BuiltinProcId builtin_id;
|
||||
};
|
||||
|
||||
b32 is_operand_nil(Operand *o) {
|
||||
return o->mode == Addressing_Value && o->type == t_untyped_nil;
|
||||
}
|
||||
|
||||
struct TypeAndValue {
|
||||
AddressingMode mode;
|
||||
Type *type;
|
||||
@@ -241,7 +245,9 @@ struct Checker {
|
||||
gbArray(ProcedureInfo) procs; // NOTE(bill): Procedures to check
|
||||
|
||||
gbArena arena;
|
||||
gbArena tmp_arena;
|
||||
gbAllocator allocator;
|
||||
gbAllocator tmp_allocator;
|
||||
|
||||
CheckerContext context;
|
||||
|
||||
@@ -501,9 +507,10 @@ void init_universal_scope(void) {
|
||||
}
|
||||
|
||||
// Constants
|
||||
add_global_constant(a, make_string("true"), t_untyped_bool, make_exact_value_bool(true));
|
||||
add_global_constant(a, make_string("false"), t_untyped_bool, make_exact_value_bool(false));
|
||||
add_global_constant(a, make_string("null"), t_untyped_pointer, make_exact_value_pointer(NULL));
|
||||
add_global_constant(a, make_string("true"), t_untyped_bool, make_exact_value_bool(true));
|
||||
add_global_constant(a, make_string("false"), t_untyped_bool, make_exact_value_bool(false));
|
||||
|
||||
add_global_entity(make_entity_nil(a, NULL, make_token_ident(make_string("nil")), t_untyped_nil));
|
||||
|
||||
// Builtin Procedures
|
||||
for (isize i = 0; i < gb_count_of(builtin_procs); i++) {
|
||||
@@ -564,7 +571,10 @@ void init_checker(Checker *c, Parser *parser, BaseTypeSizes sizes) {
|
||||
}
|
||||
isize arena_size = 2 * item_size * total_token_count;
|
||||
gb_arena_init_from_allocator(&c->arena, a, arena_size);
|
||||
gb_arena_init_from_allocator(&c->tmp_arena, a, arena_size);
|
||||
|
||||
c->allocator = gb_arena_allocator(&c->arena);
|
||||
c->tmp_allocator = gb_arena_allocator(&c->tmp_arena);
|
||||
|
||||
c->global_scope = make_scope(universal_scope, c->allocator);
|
||||
c->context.scope = c->global_scope;
|
||||
@@ -705,6 +715,10 @@ void add_type_info_type(Checker *c, Type *t) {
|
||||
return;
|
||||
}
|
||||
t = default_type(t);
|
||||
if (is_type_untyped(t)) {
|
||||
return; // Could be nil
|
||||
}
|
||||
|
||||
if (map_get(&c->info.type_info_map, hash_pointer(t)) != NULL) {
|
||||
// Types have already been added
|
||||
return;
|
||||
|
||||
@@ -10,6 +10,7 @@ enum BuiltinProcId;
|
||||
ENTITY_KIND(Procedure), \
|
||||
ENTITY_KIND(Builtin), \
|
||||
ENTITY_KIND(ImportName), \
|
||||
ENTITY_KIND(Nil), \
|
||||
ENTITY_KIND(Count),
|
||||
|
||||
|
||||
@@ -68,6 +69,8 @@ struct Entity {
|
||||
Scope *scope;
|
||||
b32 used;
|
||||
} ImportName;
|
||||
struct {
|
||||
} Nil;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -155,6 +158,12 @@ Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_nil(gbAllocator a, Scope *scope, Token token, Type *type) {
|
||||
Entity *entity = alloc_entity(a, Entity_Nil, scope, token, type);
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
Entity *make_entity_dummy_variable(gbAllocator a, Scope *file_scope, Token token) {
|
||||
token.string = make_string("_");
|
||||
return make_entity_variable(a, file_scope, token, NULL);
|
||||
|
||||
+139
-84
@@ -68,13 +68,16 @@ b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argu
|
||||
if (is_type_untyped(src)) {
|
||||
switch (dst->kind) {
|
||||
case Type_Basic:
|
||||
if (operand->mode == Addressing_Constant)
|
||||
if (operand->mode == Addressing_Constant) {
|
||||
return check_value_is_expressible(c, operand->value, dst, NULL);
|
||||
if (src->kind == Type_Basic)
|
||||
return src->Basic.kind == Basic_UntypedBool && is_type_boolean(dst);
|
||||
}
|
||||
if (src->kind == Type_Basic && src->Basic.kind == Basic_UntypedBool) {
|
||||
return is_type_boolean(dst);
|
||||
}
|
||||
break;
|
||||
case Type_Pointer:
|
||||
return src->Basic.kind == Basic_UntypedPointer;
|
||||
}
|
||||
if (type_has_nil(dst)) {
|
||||
return is_operand_nil(operand);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +88,10 @@ b32 check_is_assignable_to(Checker *c, Operand *operand, Type *type, b32 is_argu
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_type_untyped_nil(src)) {
|
||||
return type_has_nil(dst);
|
||||
}
|
||||
|
||||
// ^T <- rawptr
|
||||
// TODO(bill): Should C-style (not C++) pointer cast be allowed?
|
||||
// if (is_type_pointer(dst) && is_type_rawptr(src)) {
|
||||
@@ -146,7 +153,13 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
|
||||
if (is_type_untyped(operand->type)) {
|
||||
Type *target_type = type;
|
||||
|
||||
if (type == NULL || is_type_any(type)) {
|
||||
if (type == NULL || is_type_any(type) || is_type_untyped_nil(type)) {
|
||||
if (type == NULL && base_type(operand->type) == t_untyped_nil) {
|
||||
error(ast_node_token(operand->expr), "Use of untyped nil in %.*s", LIT(context_name));
|
||||
operand->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
add_type_info_type(c, type);
|
||||
target_type = default_type(operand->type);
|
||||
}
|
||||
@@ -229,14 +242,15 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
|
||||
isize other_field_index = 0;
|
||||
Entity *using_index_expr = NULL;
|
||||
|
||||
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
struct Delay {
|
||||
Entity *e;
|
||||
AstNode *t;
|
||||
};
|
||||
gbArray(Delay) delayed_const; gb_array_init(delayed_const, gb_heap_allocator());
|
||||
gbArray(Delay) delayed_type; gb_array_init(delayed_type, gb_heap_allocator());
|
||||
defer (gb_array_free(delayed_const));
|
||||
defer (gb_array_free(delayed_type));
|
||||
gbArray(Delay) delayed_const; gb_array_init_reserve(delayed_const, c->tmp_allocator, other_field_count);
|
||||
gbArray(Delay) delayed_type; gb_array_init_reserve(delayed_type, c->tmp_allocator, other_field_count);
|
||||
|
||||
gb_for_array(decl_index, decls) {
|
||||
AstNode *decl = decls[decl_index];
|
||||
@@ -729,8 +743,8 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
|
||||
make_token_ident(make_string("max_value")), constant_type, make_exact_value_integer(max_value));
|
||||
}
|
||||
|
||||
Type *check_get_params(Checker *c, Scope *scope, AstNodeArray fields, b32 *is_variadic_) {
|
||||
if (fields == NULL || gb_array_count(fields) == 0)
|
||||
Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, b32 *is_variadic_) {
|
||||
if (params == NULL || gb_array_count(params) == 0)
|
||||
return NULL;
|
||||
|
||||
b32 is_variadic = false;
|
||||
@@ -738,33 +752,32 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray fields, b32 *is_va
|
||||
Type *tuple = make_type_tuple(c->allocator);
|
||||
|
||||
isize variable_count = 0;
|
||||
gb_for_array(i, fields) {
|
||||
AstNode *field = fields[i];
|
||||
ast_node(f, Field, field);
|
||||
variable_count += gb_array_count(f->names);
|
||||
gb_for_array(i, params) {
|
||||
AstNode *field = params[i];
|
||||
ast_node(p, Parameter, field);
|
||||
variable_count += gb_array_count(p->names);
|
||||
}
|
||||
|
||||
Entity **variables = gb_alloc_array(c->allocator, Entity *, variable_count);
|
||||
isize variable_index = 0;
|
||||
gb_for_array(i, fields) {
|
||||
AstNode *field = fields[i];
|
||||
ast_node(f, Field, field);
|
||||
AstNode *type_expr = f->type;
|
||||
gb_for_array(i, params) {
|
||||
ast_node(p, Parameter, params[i]);
|
||||
AstNode *type_expr = p->type;
|
||||
if (type_expr) {
|
||||
if (type_expr->kind == AstNode_Ellipsis) {
|
||||
type_expr = type_expr->Ellipsis.expr;
|
||||
if (i+1 == gb_array_count(fields)) {
|
||||
if (i+1 == gb_array_count(params)) {
|
||||
is_variadic = true;
|
||||
} else {
|
||||
error(ast_node_token(field), "Invalid AST: Invalid variadic parameter");
|
||||
error(ast_node_token(params[i]), "Invalid AST: Invalid variadic parameter");
|
||||
}
|
||||
}
|
||||
|
||||
Type *type = check_type(c, type_expr);
|
||||
gb_for_array(j, f->names) {
|
||||
AstNode *name = f->names[j];
|
||||
gb_for_array(j, p->names) {
|
||||
AstNode *name = p->names[j];
|
||||
if (name->kind == AstNode_Ident) {
|
||||
Entity *param = make_entity_param(c->allocator, scope, name->Ident, type, f->is_using);
|
||||
Entity *param = make_entity_param(c->allocator, scope, name->Ident, type, p->is_using);
|
||||
add_entity(c, scope, name, param);
|
||||
variables[variable_index++] = param;
|
||||
} else {
|
||||
@@ -774,10 +787,10 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray fields, b32 *is_va
|
||||
}
|
||||
}
|
||||
|
||||
if (is_variadic && gb_array_count(fields) > 0) {
|
||||
if (is_variadic && gb_array_count(params) > 0) {
|
||||
// NOTE(bill): Change last variadic parameter to be a slice
|
||||
// Custom Calling convention for variadic parameters
|
||||
Entity *end = variables[gb_array_count(fields)-1];
|
||||
Entity *end = variables[gb_array_count(params)-1];
|
||||
end->type = make_type_slice(c->allocator, end->type);
|
||||
}
|
||||
|
||||
@@ -927,6 +940,10 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
|
||||
error(ast_node_token(n), "Use of import `%.*s` not in selector", LIT(e->ImportName.name));
|
||||
return;
|
||||
|
||||
case Entity_Nil:
|
||||
o->mode = Addressing_Value;
|
||||
break;
|
||||
|
||||
default:
|
||||
compiler_error("Compiler error: Unknown EntityKind");
|
||||
break;
|
||||
@@ -1184,15 +1201,20 @@ b32 check_binary_op(Checker *c, Operand *o, Token op) {
|
||||
}
|
||||
break;
|
||||
|
||||
case Token_Mod:
|
||||
case Token_And:
|
||||
case Token_Or:
|
||||
case Token_Xor:
|
||||
case Token_AndNot:
|
||||
|
||||
case Token_ModEq:
|
||||
case Token_AndEq:
|
||||
case Token_OrEq:
|
||||
if (!is_type_integer(type) && !is_type_boolean(type)) {
|
||||
error(op, "Operator `%.*s` is only allowed with integers or booleans", LIT(op.string));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case Token_Mod:
|
||||
case Token_Xor:
|
||||
case Token_AndNot:
|
||||
case Token_ModEq:
|
||||
case Token_XorEq:
|
||||
case Token_AndNotEq:
|
||||
if (!is_type_integer(type)) {
|
||||
@@ -1350,7 +1372,17 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) {
|
||||
|
||||
if (o->mode == Addressing_Constant) {
|
||||
Type *type = base_type(o->type);
|
||||
GB_ASSERT(type->kind == Type_Basic);
|
||||
if (type->kind != Type_Basic) {
|
||||
gbString xt = type_to_string(o->type);
|
||||
gbString err_str = expr_to_string(node);
|
||||
defer (gb_string_free(xt));
|
||||
defer (gb_string_free(err_str));
|
||||
error(op, "Invalid type, `%s`, for constant unary expression `%s`", xt, err_str);
|
||||
o->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
i32 precision = 0;
|
||||
if (is_type_unsigned(type))
|
||||
precision = cast(i32)(8 * type_size_of(c->sizes, c->allocator, type));
|
||||
@@ -1368,6 +1400,9 @@ void check_unary_expr(Checker *c, Operand *o, Token op, AstNode *node) {
|
||||
}
|
||||
|
||||
void check_comparison(Checker *c, Operand *x, Operand *y, Token op) {
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
gbString err_str = NULL;
|
||||
defer ({
|
||||
if (err_str != NULL)
|
||||
@@ -1392,16 +1427,16 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) {
|
||||
|
||||
if (!defined) {
|
||||
gbString type_string = type_to_string(x->type);
|
||||
err_str = gb_string_make(gb_heap_allocator(),
|
||||
defer (gb_string_free(type_string));
|
||||
err_str = gb_string_make(c->tmp_allocator,
|
||||
gb_bprintf("operator `%.*s` not defined for type `%s`", LIT(op.string), type_string));
|
||||
gb_string_free(type_string);
|
||||
}
|
||||
} else {
|
||||
gbString xt = type_to_string(x->type);
|
||||
gbString yt = type_to_string(y->type);
|
||||
defer(gb_string_free(xt));
|
||||
defer(gb_string_free(yt));
|
||||
err_str = gb_string_make(gb_heap_allocator(),
|
||||
err_str = gb_string_make(c->tmp_allocator,
|
||||
gb_bprintf("mismatched types `%s` and `%s`", xt, yt));
|
||||
}
|
||||
|
||||
@@ -1853,7 +1888,15 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
||||
ExactValue b = y->value;
|
||||
|
||||
Type *type = base_type(x->type);
|
||||
GB_ASSERT(type->kind == Type_Basic);
|
||||
if (type->kind != Type_Basic) {
|
||||
gbString xt = type_to_string(x->type);
|
||||
defer (gb_string_free(xt));
|
||||
err_str = expr_to_string(node);
|
||||
error(op, "Invalid type, `%s`, for constant binary expression `%s`", xt, err_str);
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
if (op.kind == Token_Quo && is_type_integer(type)) {
|
||||
op.kind = Token_QuoEq; // NOTE(bill): Hack to get division of integers
|
||||
}
|
||||
@@ -1932,8 +1975,10 @@ void convert_untyped_error(Checker *c, Operand *operand, Type *target_type) {
|
||||
|
||||
if (operand->mode == Addressing_Constant) {
|
||||
if (operand->value.value_integer == 0) {
|
||||
// NOTE(bill): Doesn't matter what the type is as it's still zero in the union
|
||||
extra_text = " - Did you want `null`?";
|
||||
if (make_string(expr_str) != "nil") { // HACK NOTE(bill): Just in case
|
||||
// NOTE(bill): Doesn't matter what the type is as it's still zero in the union
|
||||
extra_text = " - Did you want `nil`?";
|
||||
}
|
||||
}
|
||||
}
|
||||
error(ast_node_token(operand->expr), "Cannot convert `%s` to `%s`%s", expr_str, type_str, extra_text);
|
||||
@@ -1989,36 +2034,27 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Type_Pointer:
|
||||
switch (operand->type->Basic.kind) {
|
||||
case Basic_UntypedPointer:
|
||||
target_type = t_untyped_pointer;
|
||||
break;
|
||||
default:
|
||||
convert_untyped_error(c, operand, target_type);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Proc:
|
||||
switch (operand->type->Basic.kind) {
|
||||
case Basic_UntypedPointer:
|
||||
break;
|
||||
default:
|
||||
convert_untyped_error(c, operand, target_type);
|
||||
return;
|
||||
case Basic_UntypedNil:
|
||||
if (!type_has_nil(target_type)) {
|
||||
convert_untyped_error(c, operand, target_type);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
convert_untyped_error(c, operand, target_type);
|
||||
return;
|
||||
if (!type_has_nil(target_type)) {
|
||||
convert_untyped_error(c, operand, target_type);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
operand->type = target_type;
|
||||
update_expr_type(c, operand->expr, target_type, true);
|
||||
}
|
||||
|
||||
b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *value) {
|
||||
@@ -2415,6 +2451,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
error(ast_node_token(expr), "Invalid argument to `type_info`");
|
||||
return false;
|
||||
}
|
||||
|
||||
add_type_info_type(c, type);
|
||||
|
||||
operand->mode = Addressing_Value;
|
||||
@@ -2993,10 +3030,12 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode
|
||||
return;
|
||||
}
|
||||
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
isize operand_count = 0;
|
||||
gbArray(Operand) operands;
|
||||
gb_array_init_reserve(operands, gb_heap_allocator(), 2*param_count);
|
||||
defer (gb_array_free(operands));
|
||||
gb_array_init_reserve(operands, c->tmp_allocator, 2*param_count);
|
||||
|
||||
gb_for_array(i, ce->args) {
|
||||
Operand o = {};
|
||||
@@ -3374,12 +3413,12 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
error(ast_node_token(e), "Index %lld is out of bounds (>= %lld) for vector literal", index, t->Vector.count);
|
||||
}
|
||||
|
||||
Operand o = {};
|
||||
check_expr_with_type_hint(c, &o, e, elem_type);
|
||||
check_assignment(c, &o, elem_type, context_name);
|
||||
Operand operand = {};
|
||||
check_expr_with_type_hint(c, &operand, e, elem_type);
|
||||
check_assignment(c, &operand, elem_type, context_name);
|
||||
|
||||
if (is_constant) {
|
||||
is_constant = o.mode == Addressing_Constant;
|
||||
is_constant = operand.mode == Addressing_Constant;
|
||||
}
|
||||
}
|
||||
if (max < index)
|
||||
@@ -3730,10 +3769,9 @@ void check_expr_or_type(Checker *c, Operand *o, AstNode *e) {
|
||||
check_expr_base(c, o, e);
|
||||
check_not_tuple(c, o);
|
||||
if (o->mode == Addressing_NoValue) {
|
||||
AstNode *e = o->expr;
|
||||
gbString str = expr_to_string(e);
|
||||
gbString str = expr_to_string(o->expr);
|
||||
defer (gb_string_free(str));
|
||||
error(ast_node_token(e),
|
||||
error(ast_node_token(o->expr),
|
||||
"`%s` used as value or type", str);
|
||||
o->mode = Addressing_Invalid;
|
||||
}
|
||||
@@ -3742,15 +3780,14 @@ void check_expr_or_type(Checker *c, Operand *o, AstNode *e) {
|
||||
|
||||
gbString write_expr_to_string(gbString str, AstNode *node);
|
||||
|
||||
gbString write_fields_to_string(gbString str, AstNodeArray fields, char *sep) {
|
||||
gb_for_array(i, fields) {
|
||||
AstNode *field = fields[i];
|
||||
ast_node(f, Field, field);
|
||||
gbString write_params_to_string(gbString str, AstNodeArray params, char *sep) {
|
||||
gb_for_array(i, params) {
|
||||
ast_node(p, Parameter, params[i]);
|
||||
if (i > 0) {
|
||||
str = gb_string_appendc(str, sep);
|
||||
}
|
||||
|
||||
str = write_expr_to_string(str, field);
|
||||
str = write_expr_to_string(str, params[i]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
@@ -3885,19 +3922,19 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
||||
str = write_expr_to_string(str, vt->elem);
|
||||
case_end;
|
||||
|
||||
case_ast_node(f, Field, node);
|
||||
if (f->is_using) {
|
||||
case_ast_node(p, Parameter, node);
|
||||
if (p->is_using) {
|
||||
str = gb_string_appendc(str, "using ");
|
||||
}
|
||||
gb_for_array(i, f->names) {
|
||||
AstNode *name = f->names[i];
|
||||
gb_for_array(i, p->names) {
|
||||
AstNode *name = p->names[i];
|
||||
if (i > 0)
|
||||
str = gb_string_appendc(str, ", ");
|
||||
str = write_expr_to_string(str, name);
|
||||
}
|
||||
|
||||
str = gb_string_appendc(str, ": ");
|
||||
str = write_expr_to_string(str, f->type);
|
||||
str = write_expr_to_string(str, p->type);
|
||||
case_end;
|
||||
|
||||
case_ast_node(ce, CallExpr, node);
|
||||
@@ -3916,7 +3953,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
||||
|
||||
case_ast_node(pt, ProcType, node);
|
||||
str = gb_string_appendc(str, "proc(");
|
||||
str = write_fields_to_string(str, pt->params, ", ");
|
||||
str = write_params_to_string(str, pt->params, ", ");
|
||||
str = gb_string_appendc(str, ")");
|
||||
case_end;
|
||||
|
||||
@@ -3924,19 +3961,37 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
||||
str = gb_string_appendc(str, "struct ");
|
||||
if (st->is_packed) str = gb_string_appendc(str, "#packed ");
|
||||
if (st->is_ordered) str = gb_string_appendc(str, "#ordered ");
|
||||
// str = write_fields_to_string(str, st->decl_list, ", ");
|
||||
gb_for_array(i, st->decls) {
|
||||
if (i > 0) {
|
||||
str = gb_string_appendc(str, "; ");
|
||||
}
|
||||
str = write_expr_to_string(str, st->decls[i]);
|
||||
}
|
||||
// str = write_params_to_string(str, st->decl_list, ", ");
|
||||
str = gb_string_appendc(str, "}");
|
||||
case_end;
|
||||
|
||||
case_ast_node(st, RawUnionType, node);
|
||||
str = gb_string_appendc(str, "raw_union {");
|
||||
// str = write_fields_to_string(str, st->decl_list, ", ");
|
||||
gb_for_array(i, st->decls) {
|
||||
if (i > 0) {
|
||||
str = gb_string_appendc(str, "; ");
|
||||
}
|
||||
str = write_expr_to_string(str, st->decls[i]);
|
||||
}
|
||||
// str = write_params_to_string(str, st->decl_list, ", ");
|
||||
str = gb_string_appendc(str, "}");
|
||||
case_end;
|
||||
|
||||
case_ast_node(st, UnionType, node);
|
||||
str = gb_string_appendc(str, "union {");
|
||||
// str = write_fields_to_string(str, st->decl_list, ", ");
|
||||
gb_for_array(i, st->decls) {
|
||||
if (i > 0) {
|
||||
str = gb_string_appendc(str, "; ");
|
||||
}
|
||||
str = write_expr_to_string(str, st->decls[i]);
|
||||
}
|
||||
// str = write_params_to_string(str, st->decl_list, ", ");
|
||||
str = gb_string_appendc(str, "}");
|
||||
case_end;
|
||||
|
||||
|
||||
+33
-19
@@ -11,14 +11,19 @@ void check_stmt(Checker *c, AstNode *node, u32 flags);
|
||||
void check_proc_decl(Checker *c, Entity *e, DeclInfo *d);
|
||||
|
||||
void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
|
||||
if (stmts == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
struct Delay {
|
||||
Entity *e;
|
||||
DeclInfo *d;
|
||||
};
|
||||
gbArray(Delay) delayed_const; gb_array_init(delayed_const, gb_heap_allocator());
|
||||
gbArray(Delay) delayed_type; gb_array_init(delayed_type, gb_heap_allocator());
|
||||
defer (gb_array_free(delayed_const));
|
||||
defer (gb_array_free(delayed_type));
|
||||
gbArray(Delay) delayed_const; gb_array_init_reserve(delayed_const, c->tmp_allocator, gb_array_count(stmts));
|
||||
gbArray(Delay) delayed_type; gb_array_init_reserve(delayed_type, c->tmp_allocator, gb_array_count(stmts));
|
||||
|
||||
gb_for_array(i, stmts) {
|
||||
AstNode *node = stmts[i];
|
||||
@@ -312,8 +317,8 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
||||
// NOTE(bill): Use the type of the operand
|
||||
Type *t = operand->type;
|
||||
if (is_type_untyped(t)) {
|
||||
if (t == t_invalid) {
|
||||
error(e->token, "Use of untyped thing in %.*s", LIT(context_name));
|
||||
if (t == t_invalid || is_type_untyped_nil(t)) {
|
||||
error(e->token, "Use of untyped nil in %.*s", LIT(context_name));
|
||||
e->type = t_invalid;
|
||||
return NULL;
|
||||
}
|
||||
@@ -331,13 +336,17 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
|
||||
}
|
||||
|
||||
void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArray inits, String context_name) {
|
||||
if ((lhs == NULL || lhs_count == 0) && gb_array_count(inits) == 0)
|
||||
if ((lhs == NULL || lhs_count == 0) && (inits == NULL || gb_array_count(inits) == 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(bill): Do not use heap allocation here if I can help it
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
|
||||
// an extra allocation
|
||||
gbArray(Operand) operands;
|
||||
gb_array_init_reserve(operands, gb_heap_allocator(), 2*lhs_count);
|
||||
defer (gb_array_free(operands));
|
||||
gb_array_init_reserve(operands, c->tmp_allocator, 2*lhs_count);
|
||||
|
||||
gb_for_array(i, inits) {
|
||||
AstNode *rhs = inits[i];
|
||||
@@ -907,10 +916,13 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(bill): Do not use heap allocation here if I can help it
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
|
||||
// an extra allocation
|
||||
gbArray(Operand) operands;
|
||||
gb_array_init(operands, gb_heap_allocator());
|
||||
defer (gb_array_free(operands));
|
||||
gb_array_init_reserve(operands, c->tmp_allocator, 2 * gb_array_count(as->lhs));
|
||||
|
||||
gb_for_array(i, as->rhs) {
|
||||
AstNode *rhs = as->rhs[i];
|
||||
@@ -1091,8 +1103,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
AstNode *stmt = bs->stmts[i];
|
||||
AstNode *default_stmt = NULL;
|
||||
if (stmt->kind == AstNode_CaseClause) {
|
||||
ast_node(c, CaseClause, stmt);
|
||||
if (gb_array_count(c->list) == 0) {
|
||||
ast_node(cc, CaseClause, stmt);
|
||||
if (gb_array_count(cc->list) == 0) {
|
||||
default_stmt = stmt;
|
||||
}
|
||||
} else {
|
||||
@@ -1158,9 +1170,11 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
HashKey key = hash_exact_value(y.value);
|
||||
auto *found = map_get(&seen, key);
|
||||
if (found != NULL) {
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
|
||||
isize count = multi_map_count(&seen, key);
|
||||
TypeAndToken *taps = gb_alloc_array(gb_heap_allocator(), TypeAndToken, count);
|
||||
defer (gb_free(gb_heap_allocator(), taps));
|
||||
TypeAndToken *taps = gb_alloc_array(c->tmp_allocator, TypeAndToken, count);
|
||||
|
||||
multi_map_get_all(&seen, key, taps);
|
||||
b32 continue_outer = false;
|
||||
@@ -1227,8 +1241,8 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
AstNode *stmt = bs->stmts[i];
|
||||
AstNode *default_stmt = NULL;
|
||||
if (stmt->kind == AstNode_CaseClause) {
|
||||
ast_node(c, CaseClause, stmt);
|
||||
if (gb_array_count(c->list) == 0) {
|
||||
ast_node(cc, CaseClause, stmt);
|
||||
if (gb_array_count(cc->list) == 0) {
|
||||
default_stmt = stmt;
|
||||
}
|
||||
} else {
|
||||
|
||||
+47
-10
@@ -22,9 +22,9 @@ enum BasicKind {
|
||||
Basic_UntypedBool,
|
||||
Basic_UntypedInteger,
|
||||
Basic_UntypedFloat,
|
||||
Basic_UntypedPointer,
|
||||
Basic_UntypedString,
|
||||
Basic_UntypedRune,
|
||||
Basic_UntypedNil,
|
||||
|
||||
Basic_Count,
|
||||
|
||||
@@ -309,9 +309,9 @@ gb_global Type basic_types[] = {
|
||||
{Type_Basic, 0, {Basic_UntypedBool, BasicFlag_Boolean | BasicFlag_Untyped, STR_LIT("untyped bool")}},
|
||||
{Type_Basic, 0, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, STR_LIT("untyped integer")}},
|
||||
{Type_Basic, 0, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, STR_LIT("untyped float")}},
|
||||
{Type_Basic, 0, {Basic_UntypedPointer, BasicFlag_Pointer | BasicFlag_Untyped, STR_LIT("untyped pointer")}},
|
||||
{Type_Basic, 0, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, STR_LIT("untyped string")}},
|
||||
{Type_Basic, 0, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, STR_LIT("untyped rune")}},
|
||||
{Type_Basic, 0, {Basic_UntypedNil, BasicFlag_Untyped, STR_LIT("untyped nil")}},
|
||||
};
|
||||
|
||||
gb_global Type basic_type_aliases[] = {
|
||||
@@ -339,9 +339,9 @@ gb_global Type *t_any = &basic_types[Basic_any];
|
||||
gb_global Type *t_untyped_bool = &basic_types[Basic_UntypedBool];
|
||||
gb_global Type *t_untyped_integer = &basic_types[Basic_UntypedInteger];
|
||||
gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat];
|
||||
gb_global Type *t_untyped_pointer = &basic_types[Basic_UntypedPointer];
|
||||
gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString];
|
||||
gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune];
|
||||
gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil];
|
||||
gb_global Type *t_byte = &basic_type_aliases[0];
|
||||
gb_global Type *t_rune = &basic_type_aliases[1];
|
||||
|
||||
@@ -548,6 +548,11 @@ b32 is_type_any(Type *t) {
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_Basic && t->Basic.kind == Basic_any);
|
||||
}
|
||||
b32 is_type_untyped_nil(Type *t) {
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_Basic && t->Basic.kind == Basic_UntypedNil);
|
||||
}
|
||||
|
||||
|
||||
|
||||
b32 is_type_indexable(Type *t) {
|
||||
@@ -555,12 +560,31 @@ b32 is_type_indexable(Type *t) {
|
||||
}
|
||||
|
||||
|
||||
b32 type_has_nil(Type *t) {
|
||||
t = base_type(t);
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
return is_type_rawptr(t);
|
||||
|
||||
case Type_Tuple:
|
||||
return false;
|
||||
|
||||
case Type_Record:
|
||||
switch (t->Record.kind) {
|
||||
case TypeRecord_Enum:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
b32 is_type_comparable(Type *t) {
|
||||
t = base_type(t);
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
return true;
|
||||
return t->kind != Basic_UntypedNil;
|
||||
case Type_Pointer:
|
||||
return true;
|
||||
case Type_Record: {
|
||||
@@ -681,12 +705,12 @@ b32 are_types_identical(Type *x, Type *y) {
|
||||
Type *default_type(Type *type) {
|
||||
if (type->kind == Type_Basic) {
|
||||
switch (type->Basic.kind) {
|
||||
case Basic_UntypedBool: return &basic_types[Basic_bool];
|
||||
case Basic_UntypedInteger: return &basic_types[Basic_int];
|
||||
case Basic_UntypedFloat: return &basic_types[Basic_f64];
|
||||
case Basic_UntypedString: return &basic_types[Basic_string];
|
||||
case Basic_UntypedRune: return &basic_types[Basic_rune];
|
||||
case Basic_UntypedPointer: return &basic_types[Basic_rawptr];
|
||||
case Basic_UntypedBool: return t_bool;
|
||||
case Basic_UntypedInteger: return t_int;
|
||||
case Basic_UntypedFloat: return t_f64;
|
||||
case Basic_UntypedString: return t_string;
|
||||
case Basic_UntypedRune: return t_rune;
|
||||
// case Basic_UntypedPointer: return &basic_types[Basic_rawptr];
|
||||
}
|
||||
}
|
||||
return type;
|
||||
@@ -952,6 +976,17 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
||||
return gb_clamp(size, 1, s.max_align);
|
||||
} break;
|
||||
|
||||
case Type_Tuple: {
|
||||
i64 max = 1;
|
||||
for (isize i = 0; i < t->Tuple.variable_count; i++) {
|
||||
i64 align = type_align_of(s, allocator, t->Tuple.variables[i]->type);
|
||||
if (max < align) {
|
||||
max = align;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
} break;
|
||||
|
||||
case Type_Record: {
|
||||
switch (t->Record.kind) {
|
||||
case TypeRecord_Struct:
|
||||
@@ -964,6 +999,8 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
||||
}
|
||||
}
|
||||
return max;
|
||||
} else if (t->Record.field_count > 0) {
|
||||
return type_align_of(s, allocator, t->Record.fields[0]->type);
|
||||
}
|
||||
break;
|
||||
case TypeRecord_Union: {
|
||||
|
||||
+12
-11
@@ -21,8 +21,9 @@ b32 ssa_gen_init(ssaGen *s, Checker *c) {
|
||||
// TODO(bill): generate appropriate output name
|
||||
int pos = cast(int)string_extension_position(c->parser->init_fullpath);
|
||||
gbFileError err = gb_file_create(&s->output_file, gb_bprintf("%.*s.ll", pos, c->parser->init_fullpath.text));
|
||||
if (err != gbFileError_None)
|
||||
if (err != gbFileError_None) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -434,10 +435,10 @@ void ssa_gen_tree(ssaGen *s) {
|
||||
ssaValue *ordered = ssa_make_const_bool(a, t->Record.struct_is_ordered);
|
||||
ssaValue *size = ssa_make_const_int(a, type_size_of(m->sizes, a, t));
|
||||
ssaValue *align = ssa_make_const_int(a, type_align_of(m->sizes, a, t));
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 1, t_bool_ptr), packed);
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 2, t_bool_ptr), ordered);
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 3, t_int_ptr), size);
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 4, t_int_ptr), align);
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 1, t_int_ptr), size);
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 2, t_int_ptr), align);
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 3, t_bool_ptr), packed);
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 4, t_bool_ptr), ordered);
|
||||
}
|
||||
|
||||
ssaValue *memory = type_info_member_offset(proc, type_info_member_data, t->Record.field_count, &type_info_member_index);
|
||||
@@ -481,8 +482,8 @@ void ssa_gen_tree(ssaGen *s) {
|
||||
{
|
||||
ssaValue *size = ssa_make_const_int(a, type_size_of(m->sizes, a, t));
|
||||
ssaValue *align = ssa_make_const_int(a, type_align_of(m->sizes, a, t));
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 3, t_int_ptr), size);
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 4, t_int_ptr), align);
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 1, t_int_ptr), size);
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 2, t_int_ptr), align);
|
||||
}
|
||||
break;
|
||||
case TypeRecord_RawUnion: {
|
||||
@@ -490,8 +491,8 @@ void ssa_gen_tree(ssaGen *s) {
|
||||
{
|
||||
ssaValue *size = ssa_make_const_int(a, type_size_of(m->sizes, a, t));
|
||||
ssaValue *align = ssa_make_const_int(a, type_align_of(m->sizes, a, t));
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 3, t_int_ptr), size);
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 4, t_int_ptr), align);
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 1, t_int_ptr), size);
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 2, t_int_ptr), align);
|
||||
}
|
||||
|
||||
ssaValue *memory = type_info_member_offset(proc, type_info_member_data, t->Record.field_count, &type_info_member_index);
|
||||
@@ -605,8 +606,8 @@ void ssa_gen_tree(ssaGen *s) {
|
||||
tag = ssa_add_local_generated(proc, t_type_info_tuple);
|
||||
|
||||
{
|
||||
ssaValue *align = ssa_make_const_int(a, type_align_of(m->sizes, a, t));
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 4, t_int_ptr), align);
|
||||
ssaValue *align = ssa_make_const_int(a, type_align_of(m->sizes, a, t));
|
||||
ssa_emit_store(proc, ssa_emit_struct_gep(proc, tag, 2, t_int_ptr), align);
|
||||
}
|
||||
|
||||
ssaValue *memory = type_info_member_offset(proc, type_info_member_data, t->Tuple.variable_count, &type_info_member_index);
|
||||
|
||||
+16
-10
@@ -157,13 +157,7 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) {
|
||||
case Basic_string: ssa_fprintf(f, "%%..string"); break;
|
||||
case Basic_uint: ssa_fprintf(f, "i%lld", word_bits); break;
|
||||
case Basic_int: ssa_fprintf(f, "i%lld", word_bits); break;
|
||||
case Basic_any:
|
||||
ssa_fprintf(f, "{");
|
||||
ssa_print_type(f, m, t_type_info_ptr);
|
||||
ssa_fprintf(f, ", ");
|
||||
ssa_print_type(f, m, t_rawptr);
|
||||
ssa_fprintf(f, "}");
|
||||
break;
|
||||
case Basic_any: ssa_fprintf(f, "%%..any"); break;
|
||||
}
|
||||
break;
|
||||
case Type_Array:
|
||||
@@ -491,7 +485,8 @@ void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Typ
|
||||
} break;
|
||||
|
||||
default:
|
||||
GB_PANIC("Invalid ExactValue: %d", value.kind);
|
||||
ssa_fprintf(f, "zeroinitializer");
|
||||
// GB_PANIC("Invalid ExactValue: %d", value.kind);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -538,6 +533,10 @@ void ssa_print_value(ssaFileBuffer *f, ssaModule *m, ssaValue *value, Type *type
|
||||
}
|
||||
} break;
|
||||
|
||||
case ssaValue_Nil:
|
||||
ssa_fprintf(f, "zeroinitializer");
|
||||
break;
|
||||
|
||||
case ssaValue_TypeName:
|
||||
ssa_print_encoded_local(f, value->TypeName.name);
|
||||
break;
|
||||
@@ -1045,9 +1044,16 @@ void ssa_print_llvm_ir(ssaFileBuffer *f, ssaModule *m) {
|
||||
ssa_fprintf(f, " = type {i8*, ");
|
||||
ssa_print_type(f, m, t_int);
|
||||
ssa_fprintf(f, "} ; Basic_string\n");
|
||||
|
||||
ssa_print_encoded_local(f, make_string("..rawptr"));
|
||||
ssa_fprintf(f, " = type i8* ; Basic_rawptr\n\n");
|
||||
ssa_fprintf(f, " = type i8* ; Basic_rawptr\n");
|
||||
|
||||
ssa_print_encoded_local(f, make_string("..any"));
|
||||
ssa_fprintf(f, " = type {");
|
||||
ssa_print_type(f, m, t_type_info_ptr);
|
||||
ssa_fprintf(f, ", ");
|
||||
ssa_print_type(f, m, t_rawptr);
|
||||
ssa_fprintf(f, "} ; Basic_any\n");
|
||||
|
||||
|
||||
gb_for_array(member_index, m->members.entries) {
|
||||
auto *entry = &m->members.entries[member_index];
|
||||
|
||||
+24
-5
@@ -298,6 +298,7 @@ enum ssaValueKind {
|
||||
|
||||
ssaValue_Constant,
|
||||
ssaValue_ConstantSlice,
|
||||
ssaValue_Nil,
|
||||
ssaValue_TypeName,
|
||||
ssaValue_Global,
|
||||
ssaValue_Param,
|
||||
@@ -323,6 +324,9 @@ struct ssaValue {
|
||||
ssaValue *backing_array;
|
||||
i64 count;
|
||||
} ConstantSlice;
|
||||
struct {
|
||||
Type *type;
|
||||
} Nil;
|
||||
struct {
|
||||
String name;
|
||||
Type * type;
|
||||
@@ -540,6 +544,8 @@ Type *ssa_type(ssaValue *value) {
|
||||
return value->Constant.type;
|
||||
case ssaValue_ConstantSlice:
|
||||
return value->ConstantSlice.type;
|
||||
case ssaValue_Nil:
|
||||
return value->Nil.type;
|
||||
case ssaValue_TypeName:
|
||||
return value->TypeName.type;
|
||||
case ssaValue_Global:
|
||||
@@ -643,6 +649,12 @@ ssaValue *ssa_make_value_param(gbAllocator a, ssaProcedure *parent, Entity *e) {
|
||||
v->Param.type = e->type;
|
||||
return v;
|
||||
}
|
||||
ssaValue *ssa_make_value_nil(gbAllocator a, Type *type) {
|
||||
ssaValue *v = ssa_alloc_value(a, ssaValue_Nil);
|
||||
v->Nil.type = type;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
ssaValue *ssa_make_instr_local(ssaProcedure *p, Entity *e, b32 zero_initialized) {
|
||||
@@ -975,11 +987,8 @@ ssaValue *ssa_emit_comment(ssaProcedure *p, String text) {
|
||||
ssaValue *ssa_add_local(ssaProcedure *proc, Entity *e, b32 zero_initialized = true) {
|
||||
ssaBlock *b = proc->decl_block; // all variables must be in the first block
|
||||
ssaValue *instr = ssa_make_instr_local(proc, e, zero_initialized);
|
||||
ssaValue *zero = ssa_make_instr_zero_init(proc, instr);
|
||||
instr->Instr.parent = b;
|
||||
zero ->Instr.parent = b;
|
||||
gb_array_append(b->instrs, instr);
|
||||
gb_array_append(b->instrs, zero);
|
||||
|
||||
// if (zero_initialized) {
|
||||
ssa_emit_zero_init(proc, instr);
|
||||
@@ -1301,9 +1310,9 @@ ssaValue *ssa_emit_comp(ssaProcedure *proc, Token op, ssaValue *left, ssaValue *
|
||||
|
||||
if (are_types_identical(a, b)) {
|
||||
// NOTE(bill): No need for a conversion
|
||||
} else if (left->kind == ssaValue_Constant) {
|
||||
} else if (left->kind == ssaValue_Constant || left->kind == ssaValue_Nil) {
|
||||
left = ssa_emit_conv(proc, left, ssa_type(right));
|
||||
} else if (right->kind == ssaValue_Constant) {
|
||||
} else if (right->kind == ssaValue_Constant || right->kind == ssaValue_Nil) {
|
||||
right = ssa_emit_conv(proc, right, ssa_type(left));
|
||||
}
|
||||
|
||||
@@ -1880,6 +1889,10 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
|
||||
if (is_type_any(dst)) {
|
||||
ssaValue *result = ssa_add_local_generated(proc, t_any);
|
||||
|
||||
if (is_type_untyped_nil(src)) {
|
||||
return ssa_emit_load(proc, result);
|
||||
}
|
||||
|
||||
ssaValue *data = NULL;
|
||||
if (value->kind == ssaValue_Instr &&
|
||||
value->Instr.kind == ssaInstr_Load) {
|
||||
@@ -1905,6 +1918,10 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
|
||||
return ssa_emit_load(proc, result);
|
||||
}
|
||||
|
||||
if (is_type_untyped_nil(src) && type_has_nil(dst)) {
|
||||
return ssa_make_value_nil(proc->module->allocator, t);
|
||||
}
|
||||
|
||||
|
||||
gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t));
|
||||
gb_printf_err("Not Identical %s != %s\n", type_to_string(src), type_to_string(dst));
|
||||
@@ -2035,6 +2052,8 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
"\t at %.*s(%td:%td)", LIT(builtin_procs[e->Builtin.id].name),
|
||||
LIT(token.pos.file), token.pos.line, token.pos.column);
|
||||
return NULL;
|
||||
} else if (e->kind == Entity_Nil) {
|
||||
return ssa_make_value_nil(proc->module->allocator, tv->type);
|
||||
}
|
||||
|
||||
auto *found = map_get(&proc->module->values, hash_pointer(e));
|
||||
|
||||
@@ -275,6 +275,8 @@ ExactValue exact_binary_operator_value(Token op, ExactValue x, ExactValue y) {
|
||||
switch (op.kind) {
|
||||
case Token_CmpAnd: return make_exact_value_bool(x.value_bool && y.value_bool);
|
||||
case Token_CmpOr: return make_exact_value_bool(x.value_bool || y.value_bool);
|
||||
case Token_And: return make_exact_value_bool(x.value_bool & y.value_bool);
|
||||
case Token_Or: return make_exact_value_bool(x.value_bool | y.value_bool);
|
||||
default: goto error;
|
||||
}
|
||||
break;
|
||||
|
||||
+90
-80
@@ -131,7 +131,7 @@ AST_NODE_KIND(_ExprBegin, "", struct{}) \
|
||||
AST_NODE_KIND(DerefExpr, "dereference expression", struct { Token op; AstNode *expr; }) \
|
||||
AST_NODE_KIND(CallExpr, "call expression", struct { \
|
||||
AstNode *proc; \
|
||||
gbArray(AstNode *) args; \
|
||||
AstNodeArray args; \
|
||||
Token open, close; \
|
||||
Token ellipsis; \
|
||||
CallExprKind kind; \
|
||||
@@ -256,7 +256,7 @@ AST_NODE_KIND(_DeclBegin, "", struct{}) \
|
||||
AST_NODE_KIND(ForeignSystemLibrary, "foreign system library", struct { Token token, filepath; }) \
|
||||
AST_NODE_KIND(_DeclEnd, "", struct{}) \
|
||||
AST_NODE_KIND(_TypeBegin, "", struct{}) \
|
||||
AST_NODE_KIND(Field, "field", struct { \
|
||||
AST_NODE_KIND(Parameter, "parameter", struct { \
|
||||
AstNodeArray names; \
|
||||
AstNode *type; \
|
||||
b32 is_using; \
|
||||
@@ -444,11 +444,11 @@ Token ast_node_token(AstNode *node) {
|
||||
return node->ImportDecl.token;
|
||||
case AstNode_ForeignSystemLibrary:
|
||||
return node->ForeignSystemLibrary.token;
|
||||
case AstNode_Field: {
|
||||
if (node->Field.names)
|
||||
return ast_node_token(node->Field.names[0]);
|
||||
case AstNode_Parameter: {
|
||||
if (node->Parameter.names)
|
||||
return ast_node_token(node->Parameter.names[0]);
|
||||
else
|
||||
return ast_node_token(node->Field.type);
|
||||
return ast_node_token(node->Parameter.type);
|
||||
}
|
||||
case AstNode_ProcType:
|
||||
return node->ProcType.token;
|
||||
@@ -545,7 +545,7 @@ gb_inline AstNode *make_paren_expr(AstFile *f, AstNode *expr, Token open, Token
|
||||
return result;
|
||||
}
|
||||
|
||||
gb_inline AstNode *make_call_expr(AstFile *f, AstNode *proc, gbArray(AstNode *)args, Token open, Token close, Token ellipsis) {
|
||||
gb_inline AstNode *make_call_expr(AstFile *f, AstNode *proc, AstNodeArray args, Token open, Token close, Token ellipsis) {
|
||||
AstNode *result = make_node(f, AstNode_CallExpr);
|
||||
result->CallExpr.proc = proc;
|
||||
result->CallExpr.args = args;
|
||||
@@ -823,11 +823,11 @@ gb_inline AstNode *make_const_decl(AstFile *f, AstNodeArray names, AstNode *type
|
||||
return result;
|
||||
}
|
||||
|
||||
gb_inline AstNode *make_field(AstFile *f, AstNodeArray names, AstNode *type, b32 is_using) {
|
||||
AstNode *result = make_node(f, AstNode_Field);
|
||||
result->Field.names = names;
|
||||
result->Field.type = type;
|
||||
result->Field.is_using = is_using;
|
||||
gb_inline AstNode *make_parameter(AstFile *f, AstNodeArray names, AstNode *type, b32 is_using) {
|
||||
AstNode *result = make_node(f, AstNode_Parameter);
|
||||
result->Parameter.names = names;
|
||||
result->Parameter.type = type;
|
||||
result->Parameter.is_using = is_using;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -961,6 +961,19 @@ gb_inline Token expect_token(AstFile *f, TokenKind kind) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
gb_inline Token expect_token_after(AstFile *f, TokenKind kind, char *msg) {
|
||||
Token prev = f->curr_token;
|
||||
if (prev.kind != kind) {
|
||||
syntax_error(f->curr_token, "Expected `%.*s` after %s, got `%.*s`",
|
||||
LIT(token_strings[kind]),
|
||||
msg,
|
||||
LIT(token_strings[prev.kind]));
|
||||
}
|
||||
next_token(f);
|
||||
return prev;
|
||||
}
|
||||
|
||||
|
||||
gb_inline Token expect_operator(AstFile *f) {
|
||||
Token prev = f->curr_token;
|
||||
if (!gb_is_between(prev.kind, Token__OperatorBegin+1, Token__OperatorEnd-1)) {
|
||||
@@ -1650,7 +1663,7 @@ AstNode *parse_binary_expr(AstFile *f, b32 lhs, i32 prec_in) {
|
||||
|
||||
expression = call;
|
||||
} else */{
|
||||
AstNode *right = parse_binary_expr(f, false, prec+1);
|
||||
right = parse_binary_expr(f, false, prec+1);
|
||||
gbArray(AstNode *) args;
|
||||
gb_array_init_reserve(args, gb_arena_allocator(&f->arena), 2);
|
||||
gb_array_append(args, expression);
|
||||
@@ -1841,58 +1854,54 @@ AstNode *parse_proc_type(AstFile *f) {
|
||||
return make_proc_type(f, proc_token, params, results);
|
||||
}
|
||||
|
||||
AstNode *parse_field_decl(AstFile *f) {
|
||||
b32 is_using = false;
|
||||
if (allow_token(f, Token_using)) {
|
||||
is_using = true;
|
||||
}
|
||||
|
||||
AstNodeArray names = parse_lhs_expr_list(f);
|
||||
if (gb_array_count(names) == 0) {
|
||||
syntax_error(f->curr_token, "Empty field declaration");
|
||||
}
|
||||
|
||||
if (gb_array_count(names) > 1 && is_using) {
|
||||
syntax_error(f->curr_token, "Cannot apply `using` to more than one of the same type");
|
||||
is_using = false;
|
||||
}
|
||||
|
||||
|
||||
expect_token(f, Token_Colon);
|
||||
|
||||
AstNode *type = NULL;
|
||||
if (f->curr_token.kind == Token_Ellipsis) {
|
||||
Token ellipsis = f->curr_token;
|
||||
next_token(f);
|
||||
type = parse_type_attempt(f);
|
||||
if (type == NULL) {
|
||||
syntax_error(f->curr_token, "variadic parameter is missing a type after `..`");
|
||||
type = make_bad_expr(f, ellipsis, f->curr_token);
|
||||
} else {
|
||||
if (gb_array_count(names) > 1) {
|
||||
syntax_error(f->curr_token, "mutliple variadic parameters, only `..`");
|
||||
} else {
|
||||
type = make_ellipsis(f, ellipsis, type);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
type = parse_type_attempt(f);
|
||||
}
|
||||
|
||||
if (type == NULL) {
|
||||
syntax_error(f->curr_token, "Expected a type for this field declaration");
|
||||
}
|
||||
|
||||
AstNode *field = make_field(f, names, type, is_using);
|
||||
return field;
|
||||
}
|
||||
|
||||
AstNodeArray parse_parameter_list(AstFile *f) {
|
||||
AstNodeArray params = make_ast_node_array(f);
|
||||
|
||||
while (f->curr_token.kind == Token_Identifier ||
|
||||
f->curr_token.kind == Token_using) {
|
||||
AstNode *field = parse_field_decl(f);
|
||||
gb_array_append(params, field);
|
||||
b32 is_using = false;
|
||||
if (allow_token(f, Token_using)) {
|
||||
is_using = true;
|
||||
}
|
||||
|
||||
AstNodeArray names = parse_lhs_expr_list(f);
|
||||
if (gb_array_count(names) == 0) {
|
||||
syntax_error(f->curr_token, "Empty parameter declaration");
|
||||
}
|
||||
|
||||
if (gb_array_count(names) > 1 && is_using) {
|
||||
syntax_error(f->curr_token, "Cannot apply `using` to more than one of the same type");
|
||||
is_using = false;
|
||||
}
|
||||
|
||||
expect_token_after(f, Token_Colon, "parameter list");
|
||||
|
||||
AstNode *type = NULL;
|
||||
if (f->curr_token.kind == Token_Ellipsis) {
|
||||
Token ellipsis = f->curr_token;
|
||||
next_token(f);
|
||||
type = parse_type_attempt(f);
|
||||
if (type == NULL) {
|
||||
syntax_error(f->curr_token, "variadic parameter is missing a type after `..`");
|
||||
type = make_bad_expr(f, ellipsis, f->curr_token);
|
||||
} else {
|
||||
if (gb_array_count(names) > 1) {
|
||||
syntax_error(f->curr_token, "mutliple variadic parameters, only `..`");
|
||||
} else {
|
||||
type = make_ellipsis(f, ellipsis, type);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
type = parse_type_attempt(f);
|
||||
}
|
||||
|
||||
|
||||
if (type == NULL) {
|
||||
syntax_error(f->curr_token, "Expected a type for this parameter declaration");
|
||||
}
|
||||
|
||||
gb_array_append(params, make_parameter(f, names, type, is_using));
|
||||
if (f->curr_token.kind != Token_Comma) {
|
||||
break;
|
||||
}
|
||||
@@ -2011,7 +2020,7 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) {
|
||||
b32 is_packed = false;
|
||||
b32 is_ordered = false;
|
||||
while (allow_token(f, Token_Hash)) {
|
||||
Token tag = expect_token(f, Token_Identifier);
|
||||
Token tag = expect_token_after(f, Token_Identifier, "`#`");
|
||||
if (tag.string == "packed") {
|
||||
if (is_packed) {
|
||||
syntax_error(tag, "Duplicate struct tag `#%.*s`", LIT(tag.string));
|
||||
@@ -2031,7 +2040,7 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) {
|
||||
syntax_error(token, "`#ordered` is not needed with `#packed` which implies ordering");
|
||||
}
|
||||
|
||||
Token open = expect_token(f, Token_OpenBrace);
|
||||
Token open = expect_token_after(f, Token_OpenBrace, "`struct`");
|
||||
isize decl_count = 0;
|
||||
AstNodeArray decls = parse_struct_params(f, &decl_count, true);
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
@@ -2041,7 +2050,7 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) {
|
||||
|
||||
case Token_union: {
|
||||
Token token = expect_token(f, Token_union);
|
||||
Token open = expect_token(f, Token_OpenBrace);
|
||||
Token open = expect_token_after(f, Token_OpenBrace, "`union`");
|
||||
isize decl_count = 0;
|
||||
AstNodeArray decls = parse_struct_params(f, &decl_count, false);
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
@@ -2050,7 +2059,7 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) {
|
||||
}
|
||||
|
||||
case Token_raw_union: {
|
||||
Token token = expect_token(f, Token_raw_union);
|
||||
Token token = expect_token_after(f, Token_OpenBrace, "`raw_union`");
|
||||
Token open = expect_token(f, Token_OpenBrace);
|
||||
isize decl_count = 0;
|
||||
AstNodeArray decls = parse_struct_params(f, &decl_count, true);
|
||||
@@ -2070,7 +2079,7 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) {
|
||||
|
||||
AstNodeArray fields = make_ast_node_array(f);
|
||||
|
||||
open = expect_token(f, Token_OpenBrace);
|
||||
open = expect_token_after(f, Token_OpenBrace, "`enum`");
|
||||
|
||||
while (f->curr_token.kind != Token_CloseBrace &&
|
||||
f->curr_token.kind != Token_EOF) {
|
||||
@@ -2161,7 +2170,7 @@ Token parse_procedure_signature(AstFile *f,
|
||||
Token proc_token = expect_token(f, Token_proc);
|
||||
expect_token(f, Token_OpenParen);
|
||||
*params = parse_parameter_list(f);
|
||||
expect_token(f, Token_CloseParen);
|
||||
expect_token_after(f, Token_CloseParen, "parameter list");
|
||||
*results = parse_results(f);
|
||||
return proc_token;
|
||||
}
|
||||
@@ -2210,17 +2219,17 @@ AstNode *parse_decl(AstFile *f, AstNodeArray names) {
|
||||
AstNodeArray values = NULL;
|
||||
AstNode *type = NULL;
|
||||
|
||||
gb_for_array(i, names) {
|
||||
AstNode *name = names[i];
|
||||
if (name->kind == AstNode_Ident) {
|
||||
String n = name->Ident.string;
|
||||
// NOTE(bill): Check for reserved identifiers
|
||||
if (n == "context") {
|
||||
syntax_error(ast_node_token(name), "`context` is a reserved identifier");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// gb_for_array(i, names) {
|
||||
// AstNode *name = names[i];
|
||||
// if (name->kind == AstNode_Ident) {
|
||||
// String n = name->Ident.string;
|
||||
// // NOTE(bill): Check for reserved identifiers
|
||||
// if (n == "context") {
|
||||
// syntax_error(ast_node_token(name), "`context` is a reserved identifier");
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
if (allow_token(f, Token_Colon)) {
|
||||
if (!allow_token(f, Token_type)) {
|
||||
@@ -2258,8 +2267,7 @@ AstNode *parse_decl(AstFile *f, AstNodeArray names) {
|
||||
// NOTE(bill): Do not fail though
|
||||
}
|
||||
|
||||
AstNode *type = parse_type(f);
|
||||
return make_type_decl(f, token, names[0], type);
|
||||
return make_type_decl(f, token, names[0], parse_type(f));
|
||||
} else if (f->curr_token.kind == Token_proc &&
|
||||
is_mutable == false) {
|
||||
// NOTE(bill): Procedure declarations
|
||||
@@ -2434,6 +2442,7 @@ AstNode *parse_case_clause(AstFile *f) {
|
||||
expect_token(f, Token_default);
|
||||
}
|
||||
expect_token(f, Token_Colon); // TODO(bill): Is this the best syntax?
|
||||
// expect_token(f, Token_ArrowRight); // TODO(bill): Is this the best syntax?
|
||||
AstNodeArray stmts = parse_stmt_list(f);
|
||||
|
||||
return make_case_clause(f, token, list, stmts);
|
||||
@@ -2449,6 +2458,7 @@ AstNode *parse_type_case_clause(AstFile *f) {
|
||||
expect_token(f, Token_default);
|
||||
}
|
||||
expect_token(f, Token_Colon); // TODO(bill): Is this the best syntax?
|
||||
// expect_token(f, Token_ArrowRight); // TODO(bill): Is this the best syntax?
|
||||
AstNodeArray stmts = parse_stmt_list(f);
|
||||
|
||||
return make_case_clause(f, token, clause, stmts);
|
||||
@@ -3069,7 +3079,7 @@ ParseFileError parse_files(Parser *p, char *init_filename) {
|
||||
p->init_fullpath = init_fullpath;
|
||||
|
||||
{
|
||||
String s = get_fullpath_core(gb_heap_allocator(), make_string("runtime.odin"));
|
||||
String s = get_fullpath_core(gb_heap_allocator(), make_string("_preload.odin"));
|
||||
ImportedFile runtime_file = {s, s, init_pos};
|
||||
gb_array_append(p->imports, runtime_file);
|
||||
}
|
||||
|
||||
+4
-4
@@ -190,11 +190,11 @@ void print_ast(AstNode *node, isize indent) {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case AstNode_Field:
|
||||
gb_for_array(i, node->Field.names) {
|
||||
print_ast(node->Field.names[i], indent+1);
|
||||
case AstNode_Parameter:
|
||||
gb_for_array(i, node->Parameter.names) {
|
||||
print_ast(node->Parameter.names[i], indent+1);
|
||||
}
|
||||
print_ast(node->Field.type, indent);
|
||||
print_ast(node->Parameter.type, indent);
|
||||
break;
|
||||
case AstNode_PointerType:
|
||||
print_indent(indent);
|
||||
|
||||
+7548
-7544
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user