mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-18 20:40:28 +00:00
Change internals of context; Disable immutable
This commit is contained in:
@@ -1,6 +1,16 @@
|
||||
#import "fmt.odin";
|
||||
#import "atomic.odin";
|
||||
#import "hash.odin";
|
||||
#import "math.odin";
|
||||
#import "mem.odin";
|
||||
#import "opengl.odin";
|
||||
#import "os.odin";
|
||||
#import "sync.odin";
|
||||
#import "utf8.odin";
|
||||
|
||||
main :: proc() {
|
||||
i: int;
|
||||
|
||||
x: [dynamic]f64;
|
||||
defer free(x);
|
||||
append(^x, 2_000_000.500_000, 3, 5, 7);
|
||||
|
||||
@@ -321,6 +321,21 @@ __string_decode_rune :: proc(s: string) -> (rune, int) #inline {
|
||||
}
|
||||
|
||||
|
||||
Raw_Any :: struct #ordered {
|
||||
type_info: ^Type_Info,
|
||||
data: rawptr,
|
||||
}
|
||||
|
||||
Raw_String :: struct #ordered {
|
||||
data: ^byte,
|
||||
count: int,
|
||||
};
|
||||
|
||||
Raw_Slice :: struct #ordered {
|
||||
data: rawptr,
|
||||
count: int,
|
||||
};
|
||||
|
||||
Raw_Dynamic_Array :: struct #ordered {
|
||||
data: rawptr,
|
||||
count: int,
|
||||
@@ -360,6 +375,11 @@ __dynamic_array_append :: proc(array_: rawptr, elem_size, elem_align: int,
|
||||
items: rawptr, item_count: int) -> int {
|
||||
array := cast(^Raw_Dynamic_Array)array_;
|
||||
|
||||
if item_count <= 0 || items == nil {
|
||||
return array.count;
|
||||
}
|
||||
|
||||
|
||||
ok := true;
|
||||
if array.capacity <= array.count+item_count {
|
||||
capacity := 2 * array.capacity + max(8, item_count);
|
||||
|
||||
@@ -30,7 +30,7 @@ HICB :: 0b1011_1111;
|
||||
|
||||
Accept_Range :: struct { lo, hi: u8 }
|
||||
|
||||
immutable accept_ranges := [5]Accept_Range{
|
||||
accept_ranges := [5]Accept_Range{
|
||||
{0x80, 0xbf},
|
||||
{0xa0, 0xbf},
|
||||
{0x80, 0x9f},
|
||||
@@ -38,7 +38,7 @@ immutable accept_ranges := [5]Accept_Range{
|
||||
{0x80, 0x8f},
|
||||
};
|
||||
|
||||
immutable accept_sizes := [256]byte{
|
||||
accept_sizes := [256]byte{
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x00-0x0f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x10-0x1f
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // 0x20-0x2f
|
||||
|
||||
@@ -148,7 +148,7 @@ String get_filepath_extension(String path) {
|
||||
|
||||
void init_build_context(BuildContext *bc) {
|
||||
bc->ODIN_VENDOR = str_lit("odin");
|
||||
bc->ODIN_VERSION = str_lit("0.0.6b");
|
||||
bc->ODIN_VERSION = str_lit("0.1.0");
|
||||
bc->ODIN_ROOT = odin_root_dir();
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
|
||||
@@ -876,6 +876,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Type
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = n;
|
||||
String name = n->Ident.string;
|
||||
|
||||
Entity *e = scope_lookup_entity(c->context.scope, name);
|
||||
if (e == NULL) {
|
||||
if (str_eq(name, str_lit("_"))) {
|
||||
@@ -3987,6 +3988,23 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
goto error;
|
||||
case_end;
|
||||
|
||||
case_ast_node(i, Implicit, node)
|
||||
switch (i->kind) {
|
||||
case Token_context:
|
||||
if (c->context.proc_name.len == 0) {
|
||||
error_node(node, "`context` is only allowed within procedures");
|
||||
goto error;
|
||||
}
|
||||
|
||||
o->mode = Addressing_Value;
|
||||
o->type = t_context;
|
||||
break;
|
||||
default:
|
||||
error_node(node, "Illegal implicit name `%.*s`", LIT(i->string));
|
||||
goto error;
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(i, Ident, node);
|
||||
check_identifier(c, o, node, NULL, type_hint);
|
||||
case_end;
|
||||
|
||||
@@ -275,7 +275,6 @@ typedef struct CheckerInfo {
|
||||
MapAstFile files; // Key: String (full path)
|
||||
MapIsize type_info_map; // Key: Type *
|
||||
isize type_info_count;
|
||||
Entity * implicit_values[ImplicitValue_Count];
|
||||
} CheckerInfo;
|
||||
|
||||
typedef struct Checker {
|
||||
@@ -1067,37 +1066,26 @@ MapEntity generate_minimum_dependency_map(CheckerInfo *info, Entity *start) {
|
||||
}
|
||||
|
||||
|
||||
void add_implicit_value(Checker *c, ImplicitValueId id, String name, String backing_name, Type *type) {
|
||||
ImplicitValueInfo info = {name, backing_name, type};
|
||||
Entity *value = make_entity_implicit_value(c->allocator, info.name, info.type, id);
|
||||
Entity *prev = scope_insert_entity(c->global_scope, value);
|
||||
GB_ASSERT(prev == NULL);
|
||||
implicit_value_infos[id] = info;
|
||||
c->info.implicit_values[id] = value;
|
||||
Entity *find_core_entity(Checker *c, String name) {
|
||||
Entity *e = current_scope_lookup_entity(c->global_scope, name);
|
||||
if (e == NULL) {
|
||||
compiler_error("Could not find type declaration for `%.*s`\n"
|
||||
"Is `_preload.odin` missing from the `core` directory relative to odin.exe?", LIT(name));
|
||||
// NOTE(bill): This will exit the program as it's cannot continue without it!
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
void init_preload(Checker *c) {
|
||||
if (c->done_preload) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (t_type_info == NULL) {
|
||||
Entity *type_info_entity = current_scope_lookup_entity(c->global_scope, str_lit("Type_Info"));
|
||||
if (type_info_entity == NULL) {
|
||||
compiler_error("Could not find type declaration for `Type_Info`\n"
|
||||
"Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
|
||||
}
|
||||
Entity *type_info_member_entity = current_scope_lookup_entity(c->global_scope, str_lit("Type_Info_Member"));
|
||||
if (type_info_entity == NULL) {
|
||||
compiler_error("Could not find type declaration for `Type_Info_Member`\n"
|
||||
"Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
|
||||
}
|
||||
Entity *type_info_enum_value_entity = current_scope_lookup_entity(c->global_scope, str_lit("Type_Info_Enum_Value"));
|
||||
if (type_info_entity == NULL) {
|
||||
compiler_error("Could not find type declaration for `Type_Info_Enum_Value`\n"
|
||||
"Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
|
||||
}
|
||||
Entity *type_info_entity = find_core_entity(c, str_lit("Type_Info"));
|
||||
Entity *type_info_member_entity = find_core_entity(c, str_lit("Type_Info_Member"));
|
||||
Entity *type_info_enum_value_entity = find_core_entity(c, str_lit("Type_Info_Enum_Value"));
|
||||
|
||||
t_type_info = type_info_entity->type;
|
||||
t_type_info_ptr = make_type_pointer(c->allocator, t_type_info);
|
||||
GB_ASSERT(is_type_union(type_info_entity->type));
|
||||
@@ -1110,6 +1098,7 @@ void init_preload(Checker *c) {
|
||||
t_type_info_enum_value_ptr = make_type_pointer(c->allocator, t_type_info_enum_value);
|
||||
|
||||
|
||||
|
||||
if (record->field_count != 19) {
|
||||
compiler_error("Invalid `Type_Info` layout");
|
||||
}
|
||||
@@ -1153,21 +1142,14 @@ void init_preload(Checker *c) {
|
||||
}
|
||||
|
||||
if (t_allocator == NULL) {
|
||||
Entity *e = current_scope_lookup_entity(c->global_scope, str_lit("Allocator"));
|
||||
if (e == NULL) {
|
||||
compiler_error("Could not find type declaration for `Allocator`\n"
|
||||
"Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
|
||||
}
|
||||
Entity *e = find_core_entity(c, str_lit("Allocator"));
|
||||
t_allocator = e->type;
|
||||
t_allocator_ptr = make_type_pointer(c->allocator, t_allocator);
|
||||
}
|
||||
|
||||
if (t_context == NULL) {
|
||||
Entity *e = current_scope_lookup_entity(c->global_scope, str_lit("Context"));
|
||||
if (e == NULL) {
|
||||
compiler_error("Could not find type declaration for `Context`\n"
|
||||
"Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
|
||||
}
|
||||
Entity *e = find_core_entity(c, str_lit("Context"));
|
||||
e_context = e;
|
||||
t_context = e->type;
|
||||
t_context_ptr = make_type_pointer(c->allocator, t_context);
|
||||
}
|
||||
@@ -1768,26 +1750,6 @@ void check_parsed_files(Checker *c) {
|
||||
|
||||
check_all_global_entities(c);
|
||||
init_preload(c); // NOTE(bill): This could be setup previously through the use of `type_info(_of_val)`
|
||||
// NOTE(bill): Nothing in the global scope _should_ depend on this implicit value as implicit
|
||||
// values are only useful within procedures
|
||||
add_implicit_value(c, ImplicitValue_context, str_lit("context"), str_lit("__context"), t_context);
|
||||
|
||||
// Initialize implicit values with backing variables
|
||||
// TODO(bill): Are implicit values "too implicit"?
|
||||
for (isize i = 1; i < ImplicitValue_Count; i++) {
|
||||
// NOTE(bill): 0th is invalid
|
||||
Entity *e = c->info.implicit_values[i];
|
||||
GB_ASSERT(e->kind == Entity_ImplicitValue);
|
||||
|
||||
ImplicitValueInfo *ivi = &implicit_value_infos[i];
|
||||
Entity *backing = scope_lookup_entity(e->scope, ivi->backing_name);
|
||||
// GB_ASSERT(backing != NULL);
|
||||
if (backing == NULL) {
|
||||
gb_exit(1);
|
||||
}
|
||||
e->ImplicitValue.backing = backing;
|
||||
}
|
||||
|
||||
|
||||
// Check procedure bodies
|
||||
// NOTE(bill): Nested procedures bodies will be added to this "queue"
|
||||
|
||||
@@ -101,6 +101,8 @@ struct Entity {
|
||||
};
|
||||
};
|
||||
|
||||
gb_global Entity *e_context = NULL;
|
||||
|
||||
|
||||
Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
|
||||
Entity *entity = gb_alloc_item(a, Entity);
|
||||
|
||||
44
src/ir.c
44
src/ir.c
@@ -1425,6 +1425,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
|
||||
Type *t_right = ir_type(right);
|
||||
|
||||
if (is_type_vector(t_left)) {
|
||||
ir_emit_comment(proc, str_lit("vector.arith.begin"));
|
||||
// IMPORTANT TODO(bill): This is very wasteful with regards to stack memory
|
||||
Type *tl = base_type(t_left);
|
||||
irValue *lhs = ir_address_from_load_or_generate_local(proc, left);
|
||||
@@ -1439,7 +1440,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
|
||||
irValue *z = ir_emit_arith(proc, op, x, y, elem_type);
|
||||
ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z);
|
||||
}
|
||||
|
||||
ir_emit_comment(proc, str_lit("vector.arith.end"));
|
||||
return ir_emit_load(proc, res);
|
||||
}
|
||||
|
||||
@@ -1533,7 +1534,7 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
|
||||
}
|
||||
|
||||
if (is_type_vector(a)) {
|
||||
// IMPORTANT TODO(bill): This is very wasteful with regards to stack memory
|
||||
ir_emit_comment(proc, str_lit("vector.comp.begin"));
|
||||
Type *tl = base_type(a);
|
||||
irValue *lhs = ir_address_from_load_or_generate_local(proc, left);
|
||||
irValue *rhs = ir_address_from_load_or_generate_local(proc, right);
|
||||
@@ -1549,6 +1550,7 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
|
||||
ir_emit_store(proc, ir_emit_array_epi(proc, res, i), z);
|
||||
}
|
||||
|
||||
ir_emit_comment(proc, str_lit("vector.comp.end"));
|
||||
return ir_emit_load(proc, res);
|
||||
}
|
||||
|
||||
@@ -2560,15 +2562,6 @@ irValue *ir_find_global_variable(irProcedure *proc, String name) {
|
||||
return *value;
|
||||
}
|
||||
|
||||
irValue *ir_find_implicit_value_backing(irProcedure *proc, ImplicitValueId id) {
|
||||
Entity *e = proc->module->info->implicit_values[id];
|
||||
GB_ASSERT(e->kind == Entity_ImplicitValue);
|
||||
Entity *backing = e->ImplicitValue.backing;
|
||||
irValue **value = map_ir_value_get(&proc->module->values, hash_pointer(backing));
|
||||
GB_ASSERT_MSG(value != NULL, "Unable to find implicit value backing `%.*s`", LIT(backing->token.string));
|
||||
return *value;
|
||||
}
|
||||
|
||||
void ir_build_stmt_list(irProcedure *proc, AstNodeArray stmts);
|
||||
|
||||
irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv) {
|
||||
@@ -2584,6 +2577,10 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
||||
GB_PANIC("Non-constant basic literal %.*s(%td:%td) - %.*s", LIT(pos.file), pos.line, pos.column, LIT(bd->name));
|
||||
case_end;
|
||||
|
||||
case_ast_node(i, Implicit, expr);
|
||||
return ir_addr_load(proc, ir_build_addr(proc, expr));
|
||||
case_end;
|
||||
|
||||
case_ast_node(i, Ident, expr);
|
||||
Entity *e = *map_entity_get(&proc->module->info->uses, hash_pointer(expr));
|
||||
if (e->kind == Entity_Builtin) {
|
||||
@@ -2595,7 +2592,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
||||
} else if (e->kind == Entity_Nil) {
|
||||
return ir_make_value_nil(proc->module->allocator, tv->type);
|
||||
} else if (e->kind == Entity_ImplicitValue) {
|
||||
return ir_emit_load(proc, ir_find_implicit_value_backing(proc, e->ImplicitValue.id));
|
||||
GB_PANIC("Illegal use of implicit value");
|
||||
}
|
||||
|
||||
irValue **found = map_ir_value_get(&proc->module->values, hash_pointer(e));
|
||||
@@ -3171,7 +3168,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
||||
return len;
|
||||
} break;
|
||||
case BuiltinProc_swizzle: {
|
||||
ir_emit_comment(proc, str_lit("swizzle"));
|
||||
ir_emit_comment(proc, str_lit("swizzle.begin"));
|
||||
irAddr vector_addr = ir_build_addr(proc, ce->args.e[0]);
|
||||
isize index_count = ce->args.count-1;
|
||||
if (index_count == 0) {
|
||||
@@ -3193,7 +3190,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
|
||||
|
||||
ir_emit_store(proc, dst_elem, ir_emit_load(proc, src_elem));
|
||||
}
|
||||
|
||||
ir_emit_comment(proc, str_lit("swizzle.end"));
|
||||
return ir_emit_load(proc, dst);
|
||||
// return ir_emit(proc, ir_make_instr_vector_shuffle(proc, vector, indices, index_count));
|
||||
} break;
|
||||
@@ -3423,9 +3420,6 @@ irAddr ir_build_addr_from_entity(irProcedure *proc, Entity *e, AstNode *expr) {
|
||||
v = *found;
|
||||
} else if (e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous) {
|
||||
v = ir_add_using_variable(proc, e);
|
||||
} else if (e->kind == Entity_ImplicitValue) {
|
||||
// TODO(bill): Should a copy be made?
|
||||
v = ir_find_implicit_value_backing(proc, e->ImplicitValue.id);
|
||||
}
|
||||
|
||||
if (v == NULL) {
|
||||
@@ -3437,6 +3431,18 @@ irAddr ir_build_addr_from_entity(irProcedure *proc, Entity *e, AstNode *expr) {
|
||||
|
||||
irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
||||
switch (expr->kind) {
|
||||
case_ast_node(i, Implicit, expr);
|
||||
irValue *v = NULL;
|
||||
switch (i->kind) {
|
||||
case Token_context:
|
||||
v = ir_find_global_variable(proc, str_lit("__context"));
|
||||
break;
|
||||
}
|
||||
|
||||
GB_ASSERT(v != NULL);
|
||||
return ir_make_addr(v, expr);
|
||||
case_end;
|
||||
|
||||
case_ast_node(i, Ident, expr);
|
||||
if (ir_is_blank_ident(expr)) {
|
||||
irAddr val = {0};
|
||||
@@ -5063,7 +5069,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
||||
ir_emit_comment(proc, str_lit("PushAllocator"));
|
||||
ir_open_scope(proc);
|
||||
|
||||
irValue *context_ptr = ir_find_implicit_value_backing(proc, ImplicitValue_context);
|
||||
irValue *context_ptr = ir_find_global_variable(proc, str_lit("__context"));
|
||||
irValue *prev_context = ir_add_local_generated(proc, t_context);
|
||||
ir_emit_store(proc, prev_context, ir_emit_load(proc, context_ptr));
|
||||
|
||||
@@ -5082,7 +5088,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
||||
ir_emit_comment(proc, str_lit("PushContext"));
|
||||
ir_open_scope(proc);
|
||||
|
||||
irValue *context_ptr = ir_find_implicit_value_backing(proc, ImplicitValue_context);
|
||||
irValue *context_ptr = ir_find_global_variable(proc, str_lit("__context"));
|
||||
irValue *prev_context = ir_add_local_generated(proc, t_context);
|
||||
ir_emit_store(proc, prev_context, ir_emit_load(proc, context_ptr));
|
||||
|
||||
|
||||
228
src/parser.c
228
src/parser.c
@@ -114,6 +114,7 @@ AstNodeArray make_ast_node_array(AstFile *f) {
|
||||
|
||||
#define AST_NODE_KINDS \
|
||||
AST_NODE_KIND(Ident, "identifier", Token) \
|
||||
AST_NODE_KIND(Implicit, "implicit", Token) \
|
||||
AST_NODE_KIND(BasicLit, "basic literal", Token) \
|
||||
AST_NODE_KIND(BasicDirective, "basic directive", struct { \
|
||||
Token token; \
|
||||
@@ -432,110 +433,65 @@ gb_inline bool is_ast_node_when_stmt(AstNode *node) {
|
||||
|
||||
Token ast_node_token(AstNode *node) {
|
||||
switch (node->kind) {
|
||||
case AstNode_Ident:
|
||||
return node->Ident;
|
||||
case AstNode_BasicLit:
|
||||
return node->BasicLit;
|
||||
case AstNode_BasicDirective:
|
||||
return node->BasicDirective.token;
|
||||
case AstNode_ProcLit:
|
||||
return ast_node_token(node->ProcLit.type);
|
||||
case AstNode_Ident: return node->Ident;
|
||||
case AstNode_Implicit: return node->Implicit;
|
||||
case AstNode_BasicLit: return node->BasicLit;
|
||||
case AstNode_BasicDirective: return node->BasicDirective.token;
|
||||
case AstNode_ProcLit: return ast_node_token(node->ProcLit.type);
|
||||
case AstNode_CompoundLit:
|
||||
if (node->CompoundLit.type != NULL) {
|
||||
return ast_node_token(node->CompoundLit.type);
|
||||
}
|
||||
return node->CompoundLit.open;
|
||||
case AstNode_TagExpr:
|
||||
return node->TagExpr.token;
|
||||
case AstNode_RunExpr:
|
||||
return node->RunExpr.token;
|
||||
case AstNode_BadExpr:
|
||||
return node->BadExpr.begin;
|
||||
case AstNode_UnaryExpr:
|
||||
return node->UnaryExpr.op;
|
||||
case AstNode_BinaryExpr:
|
||||
return ast_node_token(node->BinaryExpr.left);
|
||||
case AstNode_ParenExpr:
|
||||
return node->ParenExpr.open;
|
||||
case AstNode_CallExpr:
|
||||
return ast_node_token(node->CallExpr.proc);
|
||||
case AstNode_MacroCallExpr:
|
||||
return ast_node_token(node->MacroCallExpr.macro);
|
||||
case AstNode_TagExpr: return node->TagExpr.token;
|
||||
case AstNode_RunExpr: return node->RunExpr.token;
|
||||
case AstNode_BadExpr: return node->BadExpr.begin;
|
||||
case AstNode_UnaryExpr: return node->UnaryExpr.op;
|
||||
case AstNode_BinaryExpr: return ast_node_token(node->BinaryExpr.left);
|
||||
case AstNode_ParenExpr: return node->ParenExpr.open;
|
||||
case AstNode_CallExpr: return ast_node_token(node->CallExpr.proc);
|
||||
case AstNode_MacroCallExpr: return ast_node_token(node->MacroCallExpr.macro);
|
||||
case AstNode_SelectorExpr:
|
||||
if (node->SelectorExpr.selector != NULL) {
|
||||
return ast_node_token(node->SelectorExpr.selector);
|
||||
}
|
||||
return node->SelectorExpr.token;
|
||||
case AstNode_IndexExpr:
|
||||
return node->IndexExpr.open;
|
||||
case AstNode_SliceExpr:
|
||||
return node->SliceExpr.open;
|
||||
case AstNode_Ellipsis:
|
||||
return node->Ellipsis.token;
|
||||
case AstNode_CastExpr:
|
||||
return node->CastExpr.token;
|
||||
case AstNode_FieldValue:
|
||||
return node->FieldValue.eq;
|
||||
case AstNode_DerefExpr:
|
||||
return node->DerefExpr.op;
|
||||
case AstNode_DemaybeExpr:
|
||||
return node->DemaybeExpr.op;
|
||||
case AstNode_BlockExpr:
|
||||
return node->BlockExpr.open;
|
||||
case AstNode_GiveExpr:
|
||||
return node->GiveExpr.token;
|
||||
case AstNode_IfExpr:
|
||||
return node->IfExpr.token;
|
||||
case AstNode_IntervalExpr:
|
||||
return ast_node_token(node->IntervalExpr.left);
|
||||
case AstNode_IndexExpr: return node->IndexExpr.open;
|
||||
case AstNode_SliceExpr: return node->SliceExpr.open;
|
||||
case AstNode_Ellipsis: return node->Ellipsis.token;
|
||||
case AstNode_CastExpr: return node->CastExpr.token;
|
||||
case AstNode_FieldValue: return node->FieldValue.eq;
|
||||
case AstNode_DerefExpr: return node->DerefExpr.op;
|
||||
case AstNode_DemaybeExpr: return node->DemaybeExpr.op;
|
||||
case AstNode_BlockExpr: return node->BlockExpr.open;
|
||||
case AstNode_GiveExpr: return node->GiveExpr.token;
|
||||
case AstNode_IfExpr: return node->IfExpr.token;
|
||||
case AstNode_IntervalExpr: return ast_node_token(node->IntervalExpr.left);
|
||||
|
||||
case AstNode_BadStmt:
|
||||
return node->BadStmt.begin;
|
||||
case AstNode_EmptyStmt:
|
||||
return node->EmptyStmt.token;
|
||||
case AstNode_ExprStmt:
|
||||
return ast_node_token(node->ExprStmt.expr);
|
||||
case AstNode_TagStmt:
|
||||
return node->TagStmt.token;
|
||||
case AstNode_AssignStmt:
|
||||
return node->AssignStmt.op;
|
||||
case AstNode_BlockStmt:
|
||||
return node->BlockStmt.open;
|
||||
case AstNode_IfStmt:
|
||||
return node->IfStmt.token;
|
||||
case AstNode_WhenStmt:
|
||||
return node->WhenStmt.token;
|
||||
case AstNode_ReturnStmt:
|
||||
return node->ReturnStmt.token;
|
||||
case AstNode_ForStmt:
|
||||
return node->ForStmt.token;
|
||||
case AstNode_RangeStmt:
|
||||
return node->RangeStmt.token;
|
||||
case AstNode_MatchStmt:
|
||||
return node->MatchStmt.token;
|
||||
case AstNode_CaseClause:
|
||||
return node->CaseClause.token;
|
||||
case AstNode_DeferStmt:
|
||||
return node->DeferStmt.token;
|
||||
case AstNode_BranchStmt:
|
||||
return node->BranchStmt.token;
|
||||
case AstNode_UsingStmt:
|
||||
return node->UsingStmt.token;
|
||||
case AstNode_AsmStmt:
|
||||
return node->AsmStmt.token;
|
||||
case AstNode_PushAllocator:
|
||||
return node->PushAllocator.token;
|
||||
case AstNode_PushContext:
|
||||
return node->PushContext.token;
|
||||
case AstNode_BadStmt: return node->BadStmt.begin;
|
||||
case AstNode_EmptyStmt: return node->EmptyStmt.token;
|
||||
case AstNode_ExprStmt: return ast_node_token(node->ExprStmt.expr);
|
||||
case AstNode_TagStmt: return node->TagStmt.token;
|
||||
case AstNode_AssignStmt: return node->AssignStmt.op;
|
||||
case AstNode_BlockStmt: return node->BlockStmt.open;
|
||||
case AstNode_IfStmt: return node->IfStmt.token;
|
||||
case AstNode_WhenStmt: return node->WhenStmt.token;
|
||||
case AstNode_ReturnStmt: return node->ReturnStmt.token;
|
||||
case AstNode_ForStmt: return node->ForStmt.token;
|
||||
case AstNode_RangeStmt: return node->RangeStmt.token;
|
||||
case AstNode_MatchStmt: return node->MatchStmt.token;
|
||||
case AstNode_CaseClause: return node->CaseClause.token;
|
||||
case AstNode_DeferStmt: return node->DeferStmt.token;
|
||||
case AstNode_BranchStmt: return node->BranchStmt.token;
|
||||
case AstNode_UsingStmt: return node->UsingStmt.token;
|
||||
case AstNode_AsmStmt: return node->AsmStmt.token;
|
||||
case AstNode_PushAllocator: return node->PushAllocator.token;
|
||||
case AstNode_PushContext: return node->PushContext.token;
|
||||
|
||||
case AstNode_BadDecl:
|
||||
return node->BadDecl.begin;
|
||||
case AstNode_ValueDecl:
|
||||
return ast_node_token(node->ValueDecl.names.e[0]);
|
||||
case AstNode_ImportDecl:
|
||||
return node->ImportDecl.token;
|
||||
case AstNode_ForeignLibrary:
|
||||
return node->ForeignLibrary.token;
|
||||
case AstNode_BadDecl: return node->BadDecl.begin;
|
||||
case AstNode_ValueDecl: return ast_node_token(node->ValueDecl.names.e[0]);
|
||||
case AstNode_ImportDecl: return node->ImportDecl.token;
|
||||
case AstNode_ForeignLibrary: return node->ForeignLibrary.token;
|
||||
|
||||
|
||||
case AstNode_Field: {
|
||||
@@ -547,28 +503,17 @@ Token ast_node_token(AstNode *node) {
|
||||
}
|
||||
|
||||
|
||||
case AstNode_HelperType:
|
||||
return node->HelperType.token;
|
||||
case AstNode_ProcType:
|
||||
return node->ProcType.token;
|
||||
case AstNode_PointerType:
|
||||
return node->PointerType.token;
|
||||
case AstNode_MaybeType:
|
||||
return node->MaybeType.token;
|
||||
case AstNode_ArrayType:
|
||||
return node->ArrayType.token;
|
||||
case AstNode_DynamicArrayType:
|
||||
return node->DynamicArrayType.token;
|
||||
case AstNode_VectorType:
|
||||
return node->VectorType.token;
|
||||
case AstNode_StructType:
|
||||
return node->StructType.token;
|
||||
case AstNode_UnionType:
|
||||
return node->UnionType.token;
|
||||
case AstNode_RawUnionType:
|
||||
return node->RawUnionType.token;
|
||||
case AstNode_EnumType:
|
||||
return node->EnumType.token;
|
||||
case AstNode_HelperType: return node->HelperType.token;
|
||||
case AstNode_ProcType: return node->ProcType.token;
|
||||
case AstNode_PointerType: return node->PointerType.token;
|
||||
case AstNode_MaybeType: return node->MaybeType.token;
|
||||
case AstNode_ArrayType: return node->ArrayType.token;
|
||||
case AstNode_DynamicArrayType: return node->DynamicArrayType.token;
|
||||
case AstNode_VectorType: return node->VectorType.token;
|
||||
case AstNode_StructType: return node->StructType.token;
|
||||
case AstNode_UnionType: return node->UnionType.token;
|
||||
case AstNode_RawUnionType: return node->RawUnionType.token;
|
||||
case AstNode_EnumType: return node->EnumType.token;
|
||||
}
|
||||
|
||||
return empty_token;
|
||||
@@ -766,6 +711,13 @@ AstNode *make_ident(AstFile *f, Token token) {
|
||||
return result;
|
||||
}
|
||||
|
||||
AstNode *make_implicit(AstFile *f, Token token) {
|
||||
AstNode *result = make_node(f, AstNode_Implicit);
|
||||
result->Implicit = token;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
AstNode *make_basic_lit(AstFile *f, Token basic_lit) {
|
||||
AstNode *result = make_node(f, AstNode_BasicLit);
|
||||
result->BasicLit = basic_lit;
|
||||
@@ -1284,7 +1236,9 @@ void fix_advance_to_next_stmt(AstFile *f) {
|
||||
case Token_defer:
|
||||
case Token_asm:
|
||||
case Token_using:
|
||||
case Token_immutable:
|
||||
case Token_thread_local:
|
||||
case Token_no_alias:
|
||||
// case Token_immutable:
|
||||
|
||||
case Token_break:
|
||||
case Token_continue:
|
||||
@@ -1400,7 +1354,7 @@ void parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray
|
||||
|
||||
|
||||
|
||||
AstNode *parse_identifier(AstFile *f) {
|
||||
AstNode *parse_ident(AstFile *f) {
|
||||
Token token = f->curr_token;
|
||||
if (token.kind == Token_Ident) {
|
||||
next_token(f);
|
||||
@@ -1553,7 +1507,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, AstNode **foreign_library_token, Str
|
||||
|
||||
if (str_eq(tag_name, str_lit("foreign"))) {
|
||||
check_proc_add_tag(f, tag_expr, tags, ProcTag_foreign, tag_name);
|
||||
*foreign_library_token = parse_identifier(f);
|
||||
*foreign_library_token = parse_ident(f);
|
||||
if (f->curr_token.kind == Token_String) {
|
||||
*foreign_name = f->curr_token.string;
|
||||
// TODO(bill): Check if valid string
|
||||
@@ -1735,12 +1689,15 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
AstNode *operand = NULL; // Operand
|
||||
switch (f->curr_token.kind) {
|
||||
case Token_Ident:
|
||||
operand = parse_identifier(f);
|
||||
operand = parse_ident(f);
|
||||
if (!lhs) {
|
||||
// TODO(bill): Handle?
|
||||
}
|
||||
return operand;
|
||||
|
||||
case Token_context:
|
||||
return make_implicit(f, expect_token(f, Token_context));
|
||||
|
||||
case Token_Integer:
|
||||
case Token_Float:
|
||||
case Token_Rune:
|
||||
@@ -1965,7 +1922,7 @@ AstNode *parse_atom_expr(AstFile *f, bool lhs) {
|
||||
next_token(f);
|
||||
switch (f->curr_token.kind) {
|
||||
case Token_Ident:
|
||||
operand = make_selector_expr(f, token, operand, parse_identifier(f));
|
||||
operand = make_selector_expr(f, token, operand, parse_ident(f));
|
||||
break;
|
||||
// case Token_Integer:
|
||||
// operand = make_selector_expr(f, token, operand, parse_expr(f, lhs));
|
||||
@@ -2190,7 +2147,7 @@ AstNodeArray parse_ident_list(AstFile *f) {
|
||||
AstNodeArray list = make_ast_node_array(f);
|
||||
|
||||
do {
|
||||
array_add(&list, parse_identifier(f));
|
||||
array_add(&list, parse_ident(f));
|
||||
if (f->curr_token.kind != Token_Comma ||
|
||||
f->curr_token.kind == Token_EOF) {
|
||||
break;
|
||||
@@ -2201,19 +2158,6 @@ AstNodeArray parse_ident_list(AstFile *f) {
|
||||
return list;
|
||||
}
|
||||
|
||||
void parse_check_name_list_for_reserves(AstFile *f, AstNodeArray names) {
|
||||
for_array(i, names) {
|
||||
AstNode *name = names.e[i];
|
||||
if (name->kind == AstNode_Ident) {
|
||||
String n = name->Ident.string;
|
||||
// NOTE(bill): Check for reserved identifiers
|
||||
if (str_eq(n, str_lit("context"))) {
|
||||
syntax_error_node(name, "`context` is a reserved identifier");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AstNode *parse_type_attempt(AstFile *f) {
|
||||
AstNode *type = parse_type_or_ident(f);
|
||||
@@ -2236,8 +2180,6 @@ AstNode *parse_type(AstFile *f) {
|
||||
|
||||
|
||||
AstNode *parse_value_decl(AstFile *f, AstNodeArray lhs) {
|
||||
parse_check_name_list_for_reserves(f, lhs);
|
||||
|
||||
AstNode *type = NULL;
|
||||
AstNodeArray values = {0};
|
||||
bool is_mutable = true;
|
||||
@@ -2455,7 +2397,7 @@ u32 parse_field_prefixes(AstFile *f) {
|
||||
default: loop = false; break;
|
||||
case Token_using: using_count += 1; next_token(f); break;
|
||||
case Token_no_alias: no_alias_count += 1; next_token(f); break;
|
||||
case Token_immutable: immutable_count += 1; next_token(f); break;
|
||||
// case Token_immutable: immutable_count += 1; next_token(f); break;
|
||||
}
|
||||
}
|
||||
if (using_count > 1) syntax_error(f->curr_token, "Multiple `using` in this field list");
|
||||
@@ -2575,12 +2517,13 @@ AstNodeArray parse_record_fields(AstFile *f, isize *field_count_, u32 flags, Str
|
||||
|
||||
AstNode *parse_type_or_ident(AstFile *f) {
|
||||
switch (f->curr_token.kind) {
|
||||
case Token_Ident: {
|
||||
AstNode *e = parse_identifier(f);
|
||||
case Token_Ident:
|
||||
{
|
||||
AstNode *e = parse_ident(f);
|
||||
while (f->curr_token.kind == Token_Period) {
|
||||
Token token = f->curr_token;
|
||||
next_token(f);
|
||||
AstNode *sel = parse_identifier(f);
|
||||
AstNode *sel = parse_ident(f);
|
||||
e = make_selector_expr(f, token, e, sel);
|
||||
}
|
||||
if (f->curr_token.kind == Token_OpenParen) {
|
||||
@@ -2794,7 +2737,7 @@ AstNode *parse_proc_decl(AstFile *f) {
|
||||
AstNodeArray results = {0};
|
||||
|
||||
Token proc_token = expect_token(f, Token_proc);
|
||||
AstNode *name = parse_identifier(f);
|
||||
AstNode *name = parse_ident(f);
|
||||
parse_proc_signature(f, ¶ms, &results);
|
||||
|
||||
u64 tags = 0;
|
||||
@@ -3118,7 +3061,7 @@ AstNode *parse_match_stmt(AstFile *f) {
|
||||
isize prev_level = f->expr_level;
|
||||
f->expr_level = -1;
|
||||
|
||||
AstNode *var = parse_identifier(f);
|
||||
AstNode *var = parse_ident(f);
|
||||
expect_token_after(f, Token_in, "match type name");
|
||||
tag = parse_simple_stmt(f, false);
|
||||
|
||||
@@ -3230,6 +3173,7 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
Token token = f->curr_token;
|
||||
switch (token.kind) {
|
||||
// Operands
|
||||
case Token_context:
|
||||
case Token_Ident:
|
||||
case Token_Integer:
|
||||
case Token_Float:
|
||||
@@ -3294,6 +3238,7 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
return make_bad_stmt(f, token, f->curr_token);
|
||||
} break;
|
||||
|
||||
#if 0
|
||||
case Token_immutable: {
|
||||
Token token = expect_token(f, Token_immutable);
|
||||
AstNode *node = parse_stmt(f);
|
||||
@@ -3309,6 +3254,7 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
syntax_error(token, "`immutable` may only be applied to a variable declaration");
|
||||
return make_bad_stmt(f, token, f->curr_token);
|
||||
} break;
|
||||
#endif
|
||||
|
||||
case Token_thread_local: {
|
||||
Token token = expect_token(f, Token_thread_local);
|
||||
|
||||
@@ -80,6 +80,7 @@ TOKEN_KIND(Token__ComparisonEnd, "_ComparisonEnd"), \
|
||||
TOKEN_KIND(Token__OperatorEnd, "_OperatorEnd"), \
|
||||
\
|
||||
TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||
/* TODO(bill): So of these keywords are not used but "reserved", why not remove them? */ \
|
||||
TOKEN_KIND(Token_when, "when"), \
|
||||
TOKEN_KIND(Token_if, "if"), \
|
||||
TOKEN_KIND(Token_else, "else"), \
|
||||
@@ -102,17 +103,20 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
|
||||
TOKEN_KIND(Token_raw_union, "raw_union"), \
|
||||
TOKEN_KIND(Token_enum, "enum"), \
|
||||
TOKEN_KIND(Token_vector, "vector"), \
|
||||
TOKEN_KIND(Token_static, "static"), \
|
||||
TOKEN_KIND(Token_dynamic, "dynamic"), \
|
||||
TOKEN_KIND(Token_using, "using"), \
|
||||
TOKEN_KIND(Token_no_alias, "no_alias"), \
|
||||
TOKEN_KIND(Token_immutable, "immutable"), \
|
||||
/* TOKEN_KIND(Token_mutable, "mutable"), */\
|
||||
/* TOKEN_KIND(Token_immutable, "immutable"), */\
|
||||
TOKEN_KIND(Token_thread_local, "thread_local"), \
|
||||
TOKEN_KIND(Token_cast, "cast"), \
|
||||
TOKEN_KIND(Token_transmute, "transmute"), \
|
||||
TOKEN_KIND(Token_down_cast, "down_cast"), \
|
||||
TOKEN_KIND(Token_union_cast, "union_cast"), \
|
||||
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
|
||||
TOKEN_KIND(Token_context, "context"), \
|
||||
TOKEN_KIND(Token_push_context, "push_context"), \
|
||||
TOKEN_KIND(Token_push_allocator, "push_allocator"), \
|
||||
TOKEN_KIND(Token_asm, "asm"), \
|
||||
TOKEN_KIND(Token__KeywordEnd, "_KeywordEnd"), \
|
||||
TOKEN_KIND(Token_Count, "")
|
||||
|
||||
60
src/types.c
60
src/types.c
@@ -166,6 +166,7 @@ typedef struct BaseTypeSizes {
|
||||
i64 max_align;
|
||||
} BaseTypeSizes;
|
||||
|
||||
|
||||
typedef Array(isize) Array_isize;
|
||||
|
||||
typedef struct Selection {
|
||||
@@ -263,6 +264,7 @@ gb_global Type *t_int_ptr = NULL;
|
||||
gb_global Type *t_i64_ptr = NULL;
|
||||
gb_global Type *t_f64_ptr = NULL;
|
||||
|
||||
|
||||
gb_global Type *t_type_info = NULL;
|
||||
gb_global Type *t_type_info_member = NULL;
|
||||
gb_global Type *t_type_info_enum_value = NULL;
|
||||
@@ -892,6 +894,9 @@ bool is_type_cte_safe(Type *type) {
|
||||
case Type_Array:
|
||||
return is_type_cte_safe(type->Array.elem);
|
||||
|
||||
case Type_DynamicArray:
|
||||
return false;
|
||||
|
||||
case Type_Vector: // NOTE(bill): This should always to be true but this is for sanity reasons
|
||||
return is_type_cte_safe(type->Vector.elem);
|
||||
|
||||
@@ -1745,20 +1750,26 @@ i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, isize index)
|
||||
} else if (t->kind == Type_Basic) {
|
||||
if (t->Basic.kind == Basic_string) {
|
||||
switch (index) {
|
||||
case 0: return 0;
|
||||
case 1: return s.word_size;
|
||||
case 0: return 0; // data
|
||||
case 1: return s.word_size; // count
|
||||
}
|
||||
} else if (t->Basic.kind == Basic_any) {
|
||||
switch (index) {
|
||||
case 0: return 0;
|
||||
case 1: return s.word_size;
|
||||
case 0: return 0; // type_info
|
||||
case 1: return s.word_size; // data
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
case 0: return 0; // data
|
||||
case 1: return 1*s.word_size; // count
|
||||
}
|
||||
} else if (t->kind == Type_DynamicArray) {
|
||||
switch (index) {
|
||||
case 0: return 0; // data
|
||||
case 1: return 1*s.word_size; // count
|
||||
case 2: return 2*s.word_size; // capacity
|
||||
case 3: return 3*s.word_size; // allocator
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -1777,7 +1788,36 @@ i64 type_offset_of_from_selection(BaseTypeSizes s, gbAllocator allocator, Type *
|
||||
if (t->kind == Type_Record && t->Record.kind == TypeRecord_Struct) {
|
||||
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
|
||||
// NOTE(bill): No need to worry about custom types, just need the alignment
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
if (t->Basic.kind == Basic_string) {
|
||||
switch (index) {
|
||||
case 0: t = t_rawptr; break;
|
||||
case 1: t = t_int; break;
|
||||
}
|
||||
} else if (t->Basic.kind == Basic_any) {
|
||||
switch (index) {
|
||||
case 0: t = t_type_info_ptr; break;
|
||||
case 1: t = t_rawptr; break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Type_DynamicArray:
|
||||
switch (index) {
|
||||
case 0: t = t_rawptr; break;
|
||||
case 1: t = t_int; break;
|
||||
case 2: t = t_int; break;
|
||||
case 3: t = t_allocator; break;
|
||||
}
|
||||
break;
|
||||
case Type_Slice:
|
||||
switch (index) {
|
||||
case 0: t = t_rawptr; break;
|
||||
case 1: t = t_int; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
@@ -1806,12 +1846,12 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
break;
|
||||
|
||||
case Type_Array:
|
||||
str = gb_string_appendc(str, gb_bprintf("[%td]", type->Array.count));
|
||||
str = gb_string_appendc(str, gb_bprintf("[%lld]", type->Array.count));
|
||||
str = write_type_to_string(str, type->Array.elem);
|
||||
break;
|
||||
|
||||
case Type_Vector:
|
||||
str = gb_string_appendc(str, gb_bprintf("[vector %td]", type->Vector.count));
|
||||
str = gb_string_appendc(str, gb_bprintf("[vector %lld]", type->Vector.count));
|
||||
str = write_type_to_string(str, type->Vector.elem);
|
||||
break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user