mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-26 07:25:00 -07:00
Implicit Values: context; Fix lvalue selector assignments; Fix offset_of* for using fields.
This commit is contained in:
-6755
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
||||
#import "fmt.odin"
|
||||
|
||||
main :: proc() {
|
||||
fmt.println(123)
|
||||
}
|
||||
|
||||
|
||||
+5
-9
@@ -34,7 +34,7 @@ Type_Info :: union {
|
||||
String: struct #ordered {}
|
||||
Boolean: struct #ordered {}
|
||||
Pointer: struct #ordered {
|
||||
elem: ^Type_Info
|
||||
elem: ^Type_Info // nil -> rawptr
|
||||
}
|
||||
Maybe: struct #ordered {
|
||||
elem: ^Type_Info
|
||||
@@ -138,10 +138,6 @@ Context :: struct #ordered {
|
||||
DEFAULT_ALIGNMENT :: align_of({4}f32)
|
||||
|
||||
|
||||
current_context :: proc() -> Context { // Copy of context
|
||||
return __context
|
||||
}
|
||||
|
||||
__check_context :: proc() {
|
||||
c := ^__context
|
||||
|
||||
@@ -157,27 +153,27 @@ alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_AL
|
||||
|
||||
alloc_align :: proc(size, alignment: int) -> rawptr #inline {
|
||||
__check_context()
|
||||
a := current_context().allocator
|
||||
a := context.allocator
|
||||
return a.procedure(a.data, Allocator.Mode.ALLOC, size, alignment, nil, 0, 0)
|
||||
}
|
||||
|
||||
free :: proc(ptr: rawptr) #inline {
|
||||
__check_context()
|
||||
a := current_context().allocator
|
||||
a := context.allocator
|
||||
if ptr != nil {
|
||||
a.procedure(a.data, Allocator.Mode.FREE, 0, 0, ptr, 0, 0)
|
||||
}
|
||||
}
|
||||
free_all :: proc() #inline {
|
||||
__check_context()
|
||||
a := current_context().allocator
|
||||
a := context.allocator
|
||||
a.procedure(a.data, Allocator.Mode.FREE_ALL, 0, 0, nil, 0, 0)
|
||||
}
|
||||
|
||||
|
||||
resize :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT) }
|
||||
resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline {
|
||||
a := current_context().allocator
|
||||
a := context.allocator
|
||||
return a.procedure(a.data, Allocator.Mode.RESIZE, new_size, alignment, ptr, old_size, 0)
|
||||
}
|
||||
|
||||
|
||||
+9
-2
@@ -226,7 +226,14 @@ print_type_to_buffer :: proc(buf: ^[]byte, ti: ^Type_Info) {
|
||||
case String: print_string_to_buffer(buf, "string")
|
||||
case Boolean: print_string_to_buffer(buf, "bool")
|
||||
case Pointer:
|
||||
print_string_to_buffer(buf, "^")
|
||||
if info.elem == nil {
|
||||
print_string_to_buffer(buf, "rawptr")
|
||||
} else {
|
||||
print_string_to_buffer(buf, "^")
|
||||
print_type_to_buffer(buf, info.elem)
|
||||
}
|
||||
case Maybe:
|
||||
print_string_to_buffer(buf, "?")
|
||||
print_type_to_buffer(buf, info.elem)
|
||||
case Procedure:
|
||||
print_string_to_buffer(buf, "proc")
|
||||
@@ -415,7 +422,7 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) {
|
||||
|
||||
case Maybe:
|
||||
if arg.data != nil {
|
||||
|
||||
// TODO(bill): print maybe
|
||||
} else {
|
||||
print_string_to_buffer(buf, "<nil>")
|
||||
}
|
||||
|
||||
+1
-1
@@ -131,7 +131,7 @@ init_arena_from_memory :: proc(using a: ^Arena, data: []byte) {
|
||||
}
|
||||
|
||||
init_arena_from_context :: proc(using a: ^Arena, size: int) {
|
||||
backing = current_context().allocator
|
||||
backing = context.allocator
|
||||
memory = new_slice(u8, 0, size)
|
||||
temp_count = 0
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
@echo off
|
||||
|
||||
call devenv odin.sln
|
||||
call devenv.exe odin.sln
|
||||
|
||||
+38
-39
@@ -24,7 +24,6 @@ String const addressing_mode_strings[] = {
|
||||
#undef ADDRESSING_MODE
|
||||
};
|
||||
|
||||
|
||||
struct Operand {
|
||||
AddressingMode mode;
|
||||
Type *type;
|
||||
@@ -32,7 +31,6 @@ struct Operand {
|
||||
AstNode *expr;
|
||||
BuiltinProcId builtin_id;
|
||||
};
|
||||
|
||||
b32 is_operand_nil(Operand *o) {
|
||||
return o->mode == Addressing_Value && o->type == t_untyped_nil;
|
||||
}
|
||||
@@ -58,33 +56,6 @@ struct DeclInfo {
|
||||
};
|
||||
|
||||
|
||||
void init_declaration_info(DeclInfo *d, Scope *scope) {
|
||||
d->scope = scope;
|
||||
map_init(&d->deps, gb_heap_allocator());
|
||||
}
|
||||
|
||||
DeclInfo *make_declaration_info(gbAllocator a, Scope *scope) {
|
||||
DeclInfo *d = gb_alloc_item(a, DeclInfo);
|
||||
init_declaration_info(d, scope);
|
||||
return d;
|
||||
}
|
||||
|
||||
void destroy_declaration_info(DeclInfo *d) {
|
||||
map_destroy(&d->deps);
|
||||
}
|
||||
|
||||
b32 has_init(DeclInfo *d) {
|
||||
if (d->init_expr != NULL)
|
||||
return true;
|
||||
if (d->proc_decl != NULL) {
|
||||
ast_node(pd, ProcDecl, d->proc_decl);
|
||||
if (pd->body != NULL)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
struct ExpressionInfo {
|
||||
b32 is_lhs; // Debug info
|
||||
@@ -94,11 +65,7 @@ struct ExpressionInfo {
|
||||
};
|
||||
|
||||
ExpressionInfo make_expression_info(b32 is_lhs, AddressingMode mode, Type *type, ExactValue value) {
|
||||
ExpressionInfo ei = {};
|
||||
ei.is_lhs = is_lhs;
|
||||
ei.mode = mode;
|
||||
ei.type = type;
|
||||
ei.value = value;
|
||||
ExpressionInfo ei = {is_lhs, mode, type, value};
|
||||
return ei;
|
||||
}
|
||||
|
||||
@@ -126,6 +93,7 @@ struct Scope {
|
||||
b32 is_init;
|
||||
AstFile *file;
|
||||
};
|
||||
gb_global Scope *universal_scope = NULL;
|
||||
|
||||
enum ExprKind {
|
||||
Expr_Expr,
|
||||
@@ -253,12 +221,13 @@ struct Checker {
|
||||
b32 in_defer; // TODO(bill): Actually handle correctly
|
||||
};
|
||||
|
||||
gb_global Scope *universal_scope = NULL;
|
||||
|
||||
struct CycleChecker {
|
||||
Array<Entity *> path; // Entity_TypeName
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
CycleChecker *cycle_checker_add(CycleChecker *cc, Entity *e) {
|
||||
if (cc == NULL) {
|
||||
return NULL;
|
||||
@@ -278,6 +247,36 @@ void cycle_checker_destroy(CycleChecker *cc) {
|
||||
}
|
||||
|
||||
|
||||
void init_declaration_info(DeclInfo *d, Scope *scope) {
|
||||
d->scope = scope;
|
||||
map_init(&d->deps, gb_heap_allocator());
|
||||
}
|
||||
|
||||
DeclInfo *make_declaration_info(gbAllocator a, Scope *scope) {
|
||||
DeclInfo *d = gb_alloc_item(a, DeclInfo);
|
||||
init_declaration_info(d, scope);
|
||||
return d;
|
||||
}
|
||||
|
||||
void destroy_declaration_info(DeclInfo *d) {
|
||||
map_destroy(&d->deps);
|
||||
}
|
||||
|
||||
b32 decl_info_has_init(DeclInfo *d) {
|
||||
if (d->init_expr != NULL)
|
||||
return true;
|
||||
if (d->proc_decl != NULL) {
|
||||
ast_node(pd, ProcDecl, d->proc_decl);
|
||||
if (pd->body != NULL)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Scope *make_scope(Scope *parent, gbAllocator allocator) {
|
||||
Scope *s = gb_alloc_item(allocator, Scope);
|
||||
@@ -489,8 +488,6 @@ void add_global_constant(gbAllocator a, String name, Type *type, ExactValue valu
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void init_universal_scope(void) {
|
||||
// NOTE(bill): No need to free these
|
||||
gbAllocator a = gb_heap_allocator();
|
||||
@@ -508,7 +505,7 @@ void init_universal_scope(void) {
|
||||
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));
|
||||
add_global_entity(make_entity_nil(a, make_string("nil"), t_untyped_nil));
|
||||
|
||||
// Builtin Procedures
|
||||
for (isize i = 0; i < gb_count_of(builtin_procs); i++) {
|
||||
@@ -947,6 +944,8 @@ void init_preload_types(Checker *c) {
|
||||
}
|
||||
t_context = e->type;
|
||||
t_context_ptr = make_type_pointer(c->allocator, t_context);
|
||||
|
||||
add_global_entity(make_entity_implicit_value(gb_heap_allocator(), make_string("context"), t_context));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+25
-22
@@ -1,5 +1,6 @@
|
||||
struct Scope;
|
||||
struct Checker;
|
||||
struct Type;
|
||||
enum BuiltinProcId;
|
||||
|
||||
#define ENTITY_KINDS \
|
||||
@@ -11,6 +12,7 @@ enum BuiltinProcId;
|
||||
ENTITY_KIND(Builtin), \
|
||||
ENTITY_KIND(ImportName), \
|
||||
ENTITY_KIND(Nil), \
|
||||
ENTITY_KIND(ImplicitValue), \
|
||||
ENTITY_KIND(Count),
|
||||
|
||||
|
||||
@@ -26,33 +28,27 @@ String const entity_strings[] = {
|
||||
#undef ENTITY_KIND
|
||||
};
|
||||
|
||||
|
||||
typedef struct Type Type;
|
||||
|
||||
struct Entity {
|
||||
EntityKind kind;
|
||||
|
||||
Scope * scope;
|
||||
Token token;
|
||||
Type * type;
|
||||
AstNode * identifier; // Can be NULL
|
||||
|
||||
Entity * using_parent;
|
||||
AstNode * using_expr;
|
||||
|
||||
union {
|
||||
struct {
|
||||
ExactValue value;
|
||||
} Constant;
|
||||
struct {
|
||||
b8 visited; // Cycle detection
|
||||
b8 used; // Variable is used
|
||||
b8 anonymous; // Variable is an anonymous
|
||||
b8 is_using; // `using` variable
|
||||
b8 visited; // Cycle detection
|
||||
b8 used; // Variable is used
|
||||
b8 anonymous; // Variable is an anonymous
|
||||
b8 field; // Is Record field
|
||||
b8 param; // Is procedure parameter
|
||||
|
||||
i32 field_index;
|
||||
i32 field_src_index;
|
||||
b8 is_field; // Is struct field
|
||||
} Variable;
|
||||
struct {
|
||||
b32 used;
|
||||
@@ -69,8 +65,8 @@ struct Entity {
|
||||
Scope *scope;
|
||||
b32 used;
|
||||
} ImportName;
|
||||
struct {
|
||||
} Nil;
|
||||
struct {} Nil;
|
||||
struct {} ImplicitValue;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -105,7 +101,7 @@ Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, T
|
||||
GB_ASSERT(parent != NULL);
|
||||
Entity *entity = alloc_entity(a, Entity_Variable, parent->scope, token, type);
|
||||
entity->using_parent = parent;
|
||||
entity->Variable.is_using = true;
|
||||
entity->Variable.anonymous = true;
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -121,20 +117,20 @@ Entity *make_entity_type_name(gbAllocator a, Scope *scope, Token token, Type *ty
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, b32 is_anonymous) {
|
||||
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, b32 anonymous) {
|
||||
Entity *entity = make_entity_variable(a, scope, token, type);
|
||||
entity->Variable.used = true;
|
||||
entity->Variable.anonymous = cast(b8)is_anonymous;
|
||||
entity->Variable.anonymous = cast(b8)anonymous;
|
||||
entity->Variable.param = true;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, b32 is_anonymous, i32 field_src_index) {
|
||||
Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, b32 anonymous, i32 field_src_index) {
|
||||
Entity *entity = make_entity_variable(a, scope, token, type);
|
||||
entity->Variable.field_src_index = field_src_index;
|
||||
entity->Variable.field_index = field_src_index;
|
||||
entity->Variable.is_field = true;
|
||||
entity->Variable.anonymous = cast(b8)is_anonymous;
|
||||
entity->Variable.is_using = cast(b8)is_anonymous;
|
||||
entity->Variable.field = true;
|
||||
entity->Variable.anonymous = cast(b8)anonymous;
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -158,8 +154,15 @@ 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);
|
||||
Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
|
||||
Token token = make_token_ident(name);
|
||||
Entity *entity = alloc_entity(a, Entity_Nil, NULL, token, type);
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_implicit_value(gbAllocator a, String name, Type *type) {
|
||||
Token token = make_token_ident(name);
|
||||
Entity *entity = alloc_entity(a, Entity_ImplicitValue, NULL, token, type);
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
+53
-19
@@ -973,6 +973,10 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
|
||||
o->mode = Addressing_Value;
|
||||
break;
|
||||
|
||||
case Entity_ImplicitValue:
|
||||
o->mode = Addressing_Value;
|
||||
break;
|
||||
|
||||
default:
|
||||
compiler_error("Compiler error: Unknown EntityKind");
|
||||
break;
|
||||
@@ -1708,7 +1712,7 @@ String check_down_cast_name(Type *dst_, Type *src_) {
|
||||
GB_ASSERT(is_type_struct(dst_s) || is_type_raw_union(dst_s));
|
||||
for (isize i = 0; i < dst_s->Record.field_count; i++) {
|
||||
Entity *f = dst_s->Record.fields[i];
|
||||
GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field);
|
||||
GB_ASSERT(f->kind == Entity_Variable && f->Variable.field);
|
||||
if (f->Variable.anonymous) {
|
||||
if (are_types_identical(f->type, src_)) {
|
||||
return f->token.string;
|
||||
@@ -2216,6 +2220,8 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||
|
||||
b32 check_op_expr = true;
|
||||
Entity *entity = NULL;
|
||||
Selection sel = {}; // NOTE(bill): Not used if it's an import name
|
||||
|
||||
|
||||
AstNode *op_expr = se->expr;
|
||||
AstNode *selector = unparen_expr(se->selector);
|
||||
@@ -2267,8 +2273,10 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (entity == NULL) {
|
||||
entity = lookup_field(c->allocator, operand->type, selector->Ident.string, operand->mode == Addressing_Type).entity;
|
||||
sel = lookup_field(c->allocator, operand->type, selector->Ident.string, operand->mode == Addressing_Type);
|
||||
entity = sel.entity;
|
||||
}
|
||||
if (entity == NULL) {
|
||||
gbString op_str = expr_to_string(op_expr);
|
||||
@@ -2284,15 +2292,16 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||
|
||||
add_entity_use(c, selector, entity);
|
||||
|
||||
operand->type = entity->type;
|
||||
operand->expr = node;
|
||||
switch (entity->kind) {
|
||||
case Entity_Constant:
|
||||
operand->mode = Addressing_Constant;
|
||||
operand->value = entity->Constant.value;
|
||||
break;
|
||||
case Entity_Variable:
|
||||
operand->mode = Addressing_Variable;
|
||||
// TODO(bill): This is the rule I need?
|
||||
if (sel.indirect || operand->mode != Addressing_Value) {
|
||||
operand->mode = Addressing_Variable;
|
||||
}
|
||||
break;
|
||||
case Entity_TypeName:
|
||||
operand->mode = Addressing_Type;
|
||||
@@ -2304,8 +2313,19 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||
operand->mode = Addressing_Builtin;
|
||||
operand->builtin_id = entity->Builtin.id;
|
||||
break;
|
||||
|
||||
// NOTE(bill): These cases should never be hit but are here for sanity reasons
|
||||
case Entity_Nil:
|
||||
operand->mode = Addressing_Value;
|
||||
break;
|
||||
case Entity_ImplicitValue:
|
||||
operand->mode = Addressing_Value;
|
||||
break;
|
||||
}
|
||||
|
||||
operand->type = entity->type;
|
||||
operand->expr = node;
|
||||
|
||||
return entity;
|
||||
|
||||
error:
|
||||
@@ -2473,10 +2493,6 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
error(ast_node_token(ce->args[0]), "Expected a type for `offset_of`");
|
||||
return false;
|
||||
}
|
||||
if (!is_type_struct(type)) {
|
||||
error(ast_node_token(ce->args[0]), "Expected a struct type for `offset_of`");
|
||||
return false;
|
||||
}
|
||||
|
||||
AstNode *field_arg = unparen_expr(ce->args[1]);
|
||||
if (field_arg == NULL ||
|
||||
@@ -2484,6 +2500,10 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
error(ast_node_token(field_arg), "Expected an identifier for field argument");
|
||||
return false;
|
||||
}
|
||||
if (is_type_array(type) || is_type_vector(type)) {
|
||||
error(ast_node_token(field_arg), "Invalid type for `offset_of`");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ast_node(arg, Ident, field_arg);
|
||||
@@ -2495,10 +2515,16 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
"`%s` has no field named `%.*s`", type_str, LIT(arg->string));
|
||||
return false;
|
||||
}
|
||||
if (sel.indirect) {
|
||||
gbString type_str = type_to_string(bt);
|
||||
defer (gb_string_free(type_str));
|
||||
error(ast_node_token(ce->args[0]),
|
||||
"Field `%.*s` is embedded via a pointer in `%s`", LIT(arg->string), type_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->mode = Addressing_Constant;
|
||||
// IMPORTANT TODO(bill): Fix for anonymous fields
|
||||
operand->value = make_exact_value_integer(type_offset_of(c->sizes, c->allocator, type, sel.index[0]));
|
||||
operand->value = make_exact_value_integer(type_offset_of_from_selection(c->sizes, c->allocator, type, sel));
|
||||
operand->type = t_int;
|
||||
} break;
|
||||
|
||||
@@ -2523,13 +2549,11 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
type = p->Pointer.elem;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_type_struct(type)) {
|
||||
error(ast_node_token(ce->args[0]), "Expected a struct type for `offset_of_val`");
|
||||
if (is_type_array(type) || is_type_vector(type)) {
|
||||
error(ast_node_token(arg), "Invalid type for `offset_of_val`");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ast_node(i, Ident, s->selector);
|
||||
Selection sel = lookup_field(c->allocator, type, i->string, operand->mode == Addressing_Type);
|
||||
if (sel.entity == NULL) {
|
||||
@@ -2538,10 +2562,18 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
"`%s` has no field named `%.*s`", type_str, LIT(i->string));
|
||||
return false;
|
||||
}
|
||||
if (sel.indirect) {
|
||||
gbString type_str = type_to_string(type);
|
||||
defer (gb_string_free(type_str));
|
||||
error(ast_node_token(ce->args[0]),
|
||||
"Field `%.*s` is embedded via a pointer in `%s`", LIT(i->string), type_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
operand->mode = Addressing_Constant;
|
||||
// IMPORTANT TODO(bill): Fix for anonymous fields
|
||||
operand->value = make_exact_value_integer(type_offset_of(c->sizes, c->allocator, type, sel.index[0]));
|
||||
operand->value = make_exact_value_integer(type_offset_of_from_selection(c->sizes, c->allocator, type, sel));
|
||||
operand->type = t_int;
|
||||
} break;
|
||||
|
||||
@@ -3227,7 +3259,7 @@ Entity *find_using_index_expr(Type *t) {
|
||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||
Entity *f = t->Record.fields[i];
|
||||
if (f->kind == Entity_Variable &&
|
||||
f->Variable.is_field && f->Variable.anonymous) {
|
||||
f->Variable.field && f->Variable.anonymous) {
|
||||
if (is_type_indexable(f->type)) {
|
||||
return f;
|
||||
}
|
||||
@@ -3632,8 +3664,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
if (o->mode == Addressing_Constant) {
|
||||
*max_count = o->value.value_string.len;
|
||||
}
|
||||
if (o->mode != Addressing_Variable)
|
||||
if (o->mode != Addressing_Variable) {
|
||||
o->mode = Addressing_Value;
|
||||
}
|
||||
o->type = t_u8;
|
||||
return true;
|
||||
}
|
||||
@@ -3700,8 +3733,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
PROF_SCOPED("check__expr_base - SliceExpr");
|
||||
|
||||
check_expr(c, o, se->expr);
|
||||
if (o->mode == Addressing_Invalid)
|
||||
if (o->mode == Addressing_Invalid) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
b32 valid = false;
|
||||
i64 max_count = -1;
|
||||
|
||||
+13
-5
@@ -1,5 +1,4 @@
|
||||
// Statements and Declarations
|
||||
|
||||
enum StmtFlag : u32 {
|
||||
Stmt_BreakAllowed = GB_BIT(0),
|
||||
Stmt_ContinueAllowed = GB_BIT(1),
|
||||
@@ -268,10 +267,10 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
|
||||
}
|
||||
|
||||
switch (op_b.mode) {
|
||||
case Addressing_Variable:
|
||||
break;
|
||||
case Addressing_Invalid:
|
||||
return NULL;
|
||||
case Addressing_Variable:
|
||||
break;
|
||||
default: {
|
||||
if (op_b.expr->kind == AstNode_SelectorExpr) {
|
||||
// NOTE(bill): Extra error checks
|
||||
@@ -282,7 +281,15 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
|
||||
|
||||
gbString str = expr_to_string(op_b.expr);
|
||||
defer (gb_string_free(str));
|
||||
error(ast_node_token(op_b.expr), "Cannot assign to `%s`", str);
|
||||
switch (op_b.mode) {
|
||||
case Addressing_Value:
|
||||
error(ast_node_token(op_b.expr), "Cannot assign to `%s`", str);
|
||||
break;
|
||||
default:
|
||||
error(ast_node_token(op_b.expr), "Cannot assign to `%s`", str);
|
||||
break;
|
||||
}
|
||||
|
||||
} break;
|
||||
}
|
||||
|
||||
@@ -507,8 +514,9 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod
|
||||
for (isize i = 0; i < params->variable_count; i++) {
|
||||
Entity *e = params->variables[i];
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
if (!e->Variable.anonymous)
|
||||
if (!e->Variable.anonymous) {
|
||||
continue;
|
||||
}
|
||||
String name = e->token.string;
|
||||
Type *t = base_type(type_deref(e->type));
|
||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||
|
||||
+30
-7
@@ -812,6 +812,8 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_typ
|
||||
|
||||
Type *type = type_deref(type_);
|
||||
b32 is_ptr = type != type_;
|
||||
sel.indirect = sel.indirect || is_ptr;
|
||||
|
||||
type = base_type(type);
|
||||
|
||||
if (type->kind == Type_Basic) {
|
||||
@@ -918,7 +920,6 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_typ
|
||||
String str = f->token.string;
|
||||
|
||||
if (field_name == str) {
|
||||
Selection sel = {};
|
||||
sel.entity = f;
|
||||
selection_add_index(&sel, i);
|
||||
return sel;
|
||||
@@ -932,7 +933,6 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_typ
|
||||
String str = f->token.string;
|
||||
|
||||
if (field_name == str) {
|
||||
Selection sel = {};
|
||||
sel.entity = f;
|
||||
selection_add_index(&sel, i);
|
||||
return sel;
|
||||
@@ -955,7 +955,7 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_typ
|
||||
} else if (!is_type_enum(type) && !is_type_union(type)) {
|
||||
for (isize i = 0; i < type->Record.field_count; i++) {
|
||||
Entity *f = type->Record.fields[i];
|
||||
GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field);
|
||||
GB_ASSERT(f->kind == Entity_Variable && f->Variable.field);
|
||||
String str = f->token.string;
|
||||
if (field_name == str) {
|
||||
selection_add_index(&sel, i); // HACK(bill): Leaky memory
|
||||
@@ -970,8 +970,9 @@ Selection lookup_field(gbAllocator a, Type *type_, String field_name, b32 is_typ
|
||||
sel = lookup_field(a, f->type, field_name, is_type, sel);
|
||||
|
||||
if (sel.entity != NULL) {
|
||||
if (is_type_pointer(f->type))
|
||||
if (is_type_pointer(f->type)) {
|
||||
sel.indirect = true;
|
||||
}
|
||||
return sel;
|
||||
}
|
||||
sel.index.count = prev_count;
|
||||
@@ -1199,26 +1200,48 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) {
|
||||
}
|
||||
|
||||
i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, isize index) {
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct) {
|
||||
type_set_offsets(s, allocator, t);
|
||||
if (gb_is_between(index, 0, t->Record.field_count-1)) {
|
||||
return t->Record.struct_offsets[index];
|
||||
}
|
||||
} else if (t->kind == Type_Basic) {
|
||||
gb_printf_err("here!!\n");
|
||||
if (t->Basic.kind == Basic_string) {
|
||||
switch (index) {
|
||||
case 0: return 0;
|
||||
case 1: return s.word_size;
|
||||
}
|
||||
} else if (t->Basic.kind == Basic_any) {
|
||||
switch (index) {
|
||||
case 0: return 0;
|
||||
case 1: return s.word_size;
|
||||
}
|
||||
}
|
||||
} else if (t->kind == Type_Slice) {
|
||||
switch (index) {
|
||||
case 0: return 0;
|
||||
case 1: return 1*s.word_size;
|
||||
case 2: return 2*s.word_size;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
i64 type_offset_of_from_selection(BaseTypeSizes s, gbAllocator allocator, Type *t, Selection sel) {
|
||||
GB_ASSERT(sel.indirect == false);
|
||||
|
||||
i64 offset = 0;
|
||||
for_array(i, sel.index) {
|
||||
isize index = sel.index[i];
|
||||
t = base_type(t);
|
||||
offset += type_offset_of(s, allocator, t, index);
|
||||
if (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct) {
|
||||
type_set_offsets(s, allocator, t);
|
||||
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
|
||||
offset += t->Record.struct_offsets[index];
|
||||
t = t->Record.fields[index]->type;
|
||||
} else {
|
||||
// NOTE(bill): string/any/slices don't have record fields so this case doesn't need to be handled
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
|
||||
@@ -450,7 +450,7 @@ void ssa_gen_tree(ssaGen *s) {
|
||||
Entity *f = t->Record.fields_in_src_order[i];
|
||||
ssaValue *tip = get_type_info_ptr(proc, type_info_data, f->type);
|
||||
i64 foffset = t->Record.struct_offsets[f->Variable.field_index];
|
||||
GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field);
|
||||
GB_ASSERT(f->kind == Entity_Variable && f->Variable.field);
|
||||
isize source_index = f->Variable.field_index;
|
||||
|
||||
ssaValue *field = ssa_emit_ptr_offset(proc, memory, ssa_make_const_int(a, source_index));
|
||||
|
||||
+38
-31
@@ -4,7 +4,6 @@ struct ssaBlock;
|
||||
struct ssaValue;
|
||||
struct ssaInstr;
|
||||
|
||||
|
||||
enum ssaDebugInfoKind {
|
||||
ssaDebugInfo_Invalid,
|
||||
|
||||
@@ -389,7 +388,6 @@ ssaAddr ssa_make_addr(ssaValue *addr, AstNode *expr) {
|
||||
ssaAddr v = {addr, expr, false, NULL};
|
||||
return v;
|
||||
}
|
||||
|
||||
ssaAddr ssa_make_addr_vector(ssaValue *addr, ssaValue *index, AstNode *expr) {
|
||||
ssaAddr v = {addr, expr, true, index};
|
||||
return v;
|
||||
@@ -1421,7 +1419,6 @@ void ssa_end_procedure_body(ssaProcedure *proc) {
|
||||
ssa_emit_jump(proc, proc->entry_block);
|
||||
|
||||
ssa_optimize_blocks(proc);
|
||||
#if 0
|
||||
ssa_build_referrers(proc);
|
||||
ssa_build_dom_tree(proc);
|
||||
|
||||
@@ -1431,7 +1428,7 @@ void ssa_end_procedure_body(ssaProcedure *proc) {
|
||||
// [ ] Local stored once? Replace loads with dominating store
|
||||
// [ ] Convert to phi nodes
|
||||
ssa_opt_mem2reg(proc);
|
||||
#endif
|
||||
|
||||
|
||||
// Number registers
|
||||
i32 reg_index = 0;
|
||||
@@ -2275,6 +2272,21 @@ void ssa_slice_bounds_check(ssaProcedure *proc, Token token, ssaValue *low, ssaV
|
||||
}
|
||||
}
|
||||
|
||||
ssaValue *ssa_find_global_variable(ssaProcedure *proc, String name) {
|
||||
ssaValue *value = *map_get(&proc->module->members, hash_string(name));
|
||||
return value;
|
||||
}
|
||||
|
||||
ssaValue *ssa_emit_implicit_value(ssaProcedure *proc, Entity *e) {
|
||||
String name = e->token.string;
|
||||
ssaValue *g = NULL;
|
||||
if (name == "context") {
|
||||
g = ssa_emit_load(proc, ssa_find_global_variable(proc, make_string("__context")));
|
||||
}
|
||||
GB_ASSERT(g != NULL);
|
||||
return g;
|
||||
}
|
||||
|
||||
|
||||
ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue *tv) {
|
||||
switch (expr->kind) {
|
||||
@@ -2292,13 +2304,16 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
return NULL;
|
||||
} else if (e->kind == Entity_Nil) {
|
||||
return ssa_make_value_nil(proc->module->allocator, tv->type);
|
||||
} else if (e->kind == Entity_ImplicitValue) {
|
||||
return ssa_emit_implicit_value(proc, e);
|
||||
}
|
||||
|
||||
auto *found = map_get(&proc->module->values, hash_pointer(e));
|
||||
if (found) {
|
||||
ssaValue *v = *found;
|
||||
if (v->kind == ssaValue_Proc)
|
||||
if (v->kind == ssaValue_Proc) {
|
||||
return v;
|
||||
}
|
||||
return ssa_emit_load(proc, v);
|
||||
}
|
||||
return NULL;
|
||||
@@ -3043,16 +3058,10 @@ ssaValue *ssa_build_expr(ssaProcedure *proc, AstNode *expr) {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
ssaValue *ssa_add_using_variable(ssaProcedure *proc, Entity *e) {
|
||||
GB_ASSERT(e->kind == Entity_Variable && e->Variable.is_using);
|
||||
GB_ASSERT(e->kind == Entity_Variable && e->Variable.anonymous);
|
||||
String name = e->token.string;
|
||||
Entity *parent = e->using_parent;
|
||||
ssaValue *p = NULL;
|
||||
if (parent->kind == Entity_Variable && parent->Variable.is_using) {
|
||||
p = ssa_add_using_variable(proc, parent);
|
||||
}
|
||||
|
||||
Selection sel = lookup_field(proc->module->allocator, parent->type, name, false);
|
||||
GB_ASSERT(sel.entity != NULL);
|
||||
ssaValue **pv = map_get(&proc->module->values, hash_pointer(parent));
|
||||
@@ -3077,6 +3086,9 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
||||
}
|
||||
|
||||
Entity *e = entity_of_ident(proc->module->info, expr);
|
||||
TypeAndValue *tv = map_get(&proc->module->info->types, hash_pointer(expr));
|
||||
// GB_ASSERT(tv == NULL || tv->mode == Addressing_Variable);
|
||||
|
||||
|
||||
if (e->kind == Entity_Constant) {
|
||||
if (base_type(e->type) == t_string) {
|
||||
@@ -3098,11 +3110,17 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
||||
ssaValue **found = map_get(&proc->module->values, hash_pointer(e));
|
||||
if (found) {
|
||||
v = *found;
|
||||
} else if (e->kind == Entity_Variable && e->Variable.is_using) {
|
||||
} else if (e->kind == Entity_Variable && e->Variable.anonymous) {
|
||||
v = ssa_add_using_variable(proc, e);
|
||||
} else if (e->kind == Entity_ImplicitValue) {
|
||||
ssaValue *g = ssa_emit_implicit_value(proc, e);
|
||||
// NOTE(bill): Create a copy as it's by value
|
||||
v = ssa_add_local_generated(proc, ssa_type(g));
|
||||
ssa_emit_store(proc, v, g);
|
||||
}
|
||||
|
||||
if (v == NULL) {
|
||||
GB_PANIC("Unknown value: %s, entity: %p\n", expr_to_string(expr), e);
|
||||
GB_PANIC("Unknown value: %s, entity: %p %.*s\n", expr_to_string(expr), e, LIT(entity_strings[e->kind]));
|
||||
}
|
||||
|
||||
return ssa_make_addr(v, expr);
|
||||
@@ -4151,7 +4169,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
||||
ssa_open_scope(proc);
|
||||
defer (ssa_close_scope(proc, ssaDeferExit_Default, NULL));
|
||||
|
||||
ssaValue *context_ptr = *map_get(&proc->module->members, hash_string(make_string("__context")));
|
||||
ssaValue *context_ptr = ssa_find_global_variable(proc, make_string("__context"));
|
||||
ssaValue *prev_context = ssa_add_local_generated(proc, t_context);
|
||||
ssa_emit_store(proc, prev_context, ssa_emit_load(proc, context_ptr));
|
||||
|
||||
@@ -4170,7 +4188,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
|
||||
ssa_open_scope(proc);
|
||||
defer (ssa_close_scope(proc, ssaDeferExit_Default, NULL));
|
||||
|
||||
ssaValue *context_ptr = *map_get(&proc->module->members, hash_string(make_string("__context")));
|
||||
ssaValue *context_ptr = ssa_find_global_variable(proc, make_string("__context"));
|
||||
ssaValue *prev_context = ssa_add_local_generated(proc, t_context);
|
||||
ssa_emit_store(proc, prev_context, ssa_emit_load(proc, context_ptr));
|
||||
|
||||
@@ -4257,11 +4275,6 @@ void ssa_build_proc(ssaValue *value, ssaProcedure *parent) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
b32 ssa_is_instr_jump(ssaValue *v) {
|
||||
if (v->kind != ssaValue_Instr) {
|
||||
return false;
|
||||
@@ -4289,7 +4302,6 @@ Array<ssaValue *> ssa_get_block_phi_nodes(ssaBlock *b) {
|
||||
|
||||
void ssa_remove_pred(ssaBlock *b, ssaBlock *p) {
|
||||
auto phis = ssa_get_block_phi_nodes(b);
|
||||
|
||||
isize i = 0;
|
||||
for_array(j, b->preds) {
|
||||
ssaBlock *pred = b->preds[j];
|
||||
@@ -4302,7 +4314,6 @@ void ssa_remove_pred(ssaBlock *b, ssaBlock *p) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
b->preds.count = i;
|
||||
for_array(k, phis) {
|
||||
auto *phi = &phis[k]->Instr.Phi;
|
||||
@@ -4322,7 +4333,6 @@ void ssa_remove_dead_blocks(ssaProcedure *proc) {
|
||||
b->index = j;
|
||||
proc->blocks[j++] = b;
|
||||
}
|
||||
|
||||
proc->blocks.count = j;
|
||||
}
|
||||
|
||||
@@ -4470,8 +4480,7 @@ void ssa_lt_link(ssaLTState *lt, ssaBlock *p, ssaBlock *q) {
|
||||
|
||||
i32 ssa_lt_depth_first_search(ssaLTState *lt, ssaBlock *p, i32 i, ssaBlock **preorder) {
|
||||
preorder[i] = p;
|
||||
p->dom.pre = i;
|
||||
i++;
|
||||
p->dom.pre = i++;
|
||||
lt->sdom[p->index] = p;
|
||||
ssa_lt_link(lt, NULL, p);
|
||||
for_array(index, p->succs) {
|
||||
@@ -4497,8 +4506,7 @@ ssaBlock *ssa_lt_eval(ssaLTState *lt, ssaBlock *v) {
|
||||
}
|
||||
|
||||
void ssa_number_dom_tree(ssaBlock *v, i32 pre, i32 post, i32 *pre_out, i32 *post_out) {
|
||||
v->dom.pre = pre;
|
||||
pre++;
|
||||
v->dom.pre = pre++;
|
||||
for_array(i, v->dom.children) {
|
||||
ssaBlock *child = v->dom.children[i];
|
||||
i32 new_pre = 0, new_post = 0;
|
||||
@@ -4506,8 +4514,7 @@ void ssa_number_dom_tree(ssaBlock *v, i32 pre, i32 post, i32 *pre_out, i32 *post
|
||||
pre = new_pre;
|
||||
post = new_post;
|
||||
}
|
||||
v->dom.post = post;
|
||||
post++;
|
||||
v->dom.post = post++;
|
||||
*pre_out = pre;
|
||||
*post_out = post;
|
||||
}
|
||||
@@ -4606,5 +4613,5 @@ void ssa_build_dom_tree(ssaProcedure *proc) {
|
||||
|
||||
|
||||
void ssa_opt_mem2reg(ssaProcedure *proc) {
|
||||
|
||||
// TODO(bill):
|
||||
}
|
||||
|
||||
+1
-4
@@ -7,9 +7,8 @@
|
||||
#include "checker/checker.cpp"
|
||||
#include "codegen/codegen.cpp"
|
||||
|
||||
// NOTE(bill): `name` is used in debugging and profiling modes
|
||||
i32 win32_exec_command_line_app(char *name, char *fmt, ...) {
|
||||
// PROF_SCOPED_STR(name);
|
||||
|
||||
STARTUPINFOW start_info = {gb_size_of(STARTUPINFOW)};
|
||||
PROCESS_INFORMATION pi = {};
|
||||
char cmd_line[2048] = {};
|
||||
@@ -88,8 +87,6 @@ ArchData make_arch_data(ArchKind kind) {
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
gb_printf_err("using: %s [run] <filename> \n", argv[0]);
|
||||
|
||||
+11
-11
@@ -2257,17 +2257,17 @@ AstNode *parse_decl(AstFile *f, AstNodeArray names) {
|
||||
AstNodeArray values = {};
|
||||
AstNode *type = NULL;
|
||||
|
||||
// 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;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
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)) {
|
||||
|
||||
Reference in New Issue
Block a user