浏览代码

Merge branch 'master' of https://github.com/zhiayang/Odin

zhiayang 8 年之前
父节点
当前提交
5516e80ab7
共有 12 个文件被更改,包括 257 次插入246 次删除
  1. 10 0
      code/demo.odin
  2. 18 15
      code/old_demos/demo001.odin
  3. 20 0
      core/_preload.odin
  4. 2 2
      core/utf8.odin
  5. 1 1
      src/build.c
  6. 18 0
      src/check_expr.c
  7. 16 54
      src/checker.c
  8. 2 0
      src/entity.c
  9. 25 19
      src/ir.c
  10. 89 143
      src/parser.c
  11. 6 2
      src/tokenizer.c
  12. 50 10
      src/types.c

+ 10 - 0
code/demo.odin

@@ -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);

+ 18 - 15
code/old_demos/demo001.odin

@@ -6,21 +6,24 @@
 // #import "punity.odin" as pn;
 
 main :: proc() {
-	// struct_padding()
-	// bounds_checking()
-	// type_introspection()
-	// any_type()
-	// crazy_introspection()
-	// namespaces_and_files()
-	// miscellany()
-	// ht.run()
-	// game.run()
-	// {
-	// 	init :: proc(c: ^pn.Core) {}
-	// 	step :: proc(c: ^pn.Core) {}
-
-	// 	pn.run(init, step)
-	// }
+	struct_padding();
+	bounds_checking();
+	type_introspection();
+	any_type();
+	crazy_introspection();
+	namespaces_and_files();
+	miscellany();
+
+	/*
+	ht.run();
+	game.run();
+	{
+		init :: proc(c: ^pn.Core) {}
+		step :: proc(c: ^pn.Core) {}
+
+		pn.run(init, step);
+	}
+	*/
 }
 
 struct_padding :: proc() {

+ 20 - 0
core/_preload.odin

@@ -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);

+ 2 - 2
core/utf8.odin

@@ -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

+ 1 - 1
src/build.c

@@ -237,7 +237,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)

+ 18 - 0
src/check_expr.c

@@ -880,6 +880,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("_"))) {
@@ -3991,6 +3992,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;

+ 16 - 54
src/checker.c

@@ -227,7 +227,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 {
@@ -1019,37 +1018,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));
@@ -1062,6 +1050,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");
 		}
@@ -1105,21 +1094,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);
 	}
@@ -1720,26 +1702,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"

+ 2 - 0
src/entity.c

@@ -158,6 +158,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);

+ 25 - 19
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));
 

+ 89 - 143
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_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_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_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, &params, &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);

+ 6 - 2
src/tokenizer.c

@@ -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, "")

+ 50 - 10
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;