Browse Source

Support import files as modules (i.e. import only once)

gingerBill 9 years ago
parent
commit
cbd82e3c02
17 changed files with 932 additions and 1105 deletions
  1. 5 36
      build.bat
  2. 3 0
      examples/other.odin
  3. 11 0
      examples/test.odin
  4. 12 0
      run.bat
  5. 161 173
      src/checker/checker.cpp
  6. 2 2
      src/checker/entity.cpp
  7. 230 223
      src/checker/expression.cpp
  8. 60 55
      src/checker/statements.cpp
  9. 3 1
      src/checker/type.cpp
  10. 103 103
      src/exact_value.cpp
  11. 6 1
      src/gb/gb.h
  12. 0 82
      src/generator.cpp
  13. 12 12
      src/main.cpp
  14. 272 270
      src/parser.cpp
  15. 0 26
      src/test.odin
  16. 22 22
      src/tokenizer.cpp
  17. 30 99
      todo.md

+ 5 - 36
build.bat

@@ -1,6 +1,5 @@
 @echo off
 
-set base_dir=W:\Odin
 :: Make sure this is a decent name and not generic
 set exe_name=odin.exe
 
@@ -23,38 +22,8 @@ set compiler_warnings= ^
 	-wd4480 ^
 	-wd4505 -wd4512 -wd4550
 
-set compiler_includes=-I"C:\Program Files\LLVM\include"
-
-set libs= kernel32.lib user32.lib gdi32.lib opengl32.lib ^
-	-libpath:"C:\Program Files\LLVM\lib"
-
-	rem LLVMX86Disassembler.lib ^
-	rem LLVMX86AsmParser.lib ^
-	rem LLVMX86CodeGen.lib ^
-	rem LLVMSelectionDAG.lib ^
-	rem LLVMAsmPrinter.lib ^
-	rem LLVMCodeGen.lib ^
-	rem LLVMTarget.lib ^
-	rem LLVMScalarOpts.lib ^
-	rem LLVMInstCombine.lib ^
-	rem LLVMInstrumentation.lib ^
-	rem LLVMProfileData.lib ^
-	rem LLVMTransformUtils.lib ^
-	rem LLVMBitWriter.lib ^
-	rem LLVMAnalysis.lib ^
-	rem LLVMX86Desc.lib ^
-	rem LLVMObject.lib ^
-	rem LLVMMCParser.lib ^
-	rem LLVMBitReader.lib ^
-	rem LLVMMCDisassembler.lib ^
-	rem LLVMX86Info.lib ^
-	rem LLVMX86AsmPrinter.lib ^
-	rem LLVMMC.lib ^
-	rem LLVMX86Utils.lib ^
-	rem LLVMCore.lib ^
-	rem LLVMSupport.lib
-
-
+set compiler_includes=
+set libs= kernel32.lib user32.lib gdi32.lib opengl32.lib
 
 set linker_flags= -incremental:no -opt:ref -subsystem:console
 
@@ -65,7 +34,7 @@ set compiler_settings=%compiler_includes% %compiler_flags% %compiler_warnings%
 set linker_settings=%libs% %linker_flags%
 
 
-set build_dir= "%base_dir%\bin\"
+set build_dir= "bin\"
 if not exist %build_dir% mkdir %build_dir%
 pushd %build_dir%
 	del *.pdb > NUL 2> NUL
@@ -74,9 +43,9 @@ pushd %build_dir%
 	del ..\misc\*.pdb > NUL 2> NUL
 	del ..\misc\*.ilk > NUL 2> NUL
 
-	cl %compiler_settings% "%base_dir%\src\main.cpp" ^
+	cl %compiler_settings% "..\src\main.cpp" ^
 		/link %linker_settings% -OUT:%exe_name% ^
-		&& call run.bat
+		&& call ..\run.bat
 
 	:do_not_compile_exe
 popd

+ 3 - 0
examples/other.odin

@@ -0,0 +1,3 @@
+add :: proc(a, b: int) -> int {
+	return a + b;
+}

+ 11 - 0
examples/test.odin

@@ -0,0 +1,11 @@
+import "other"
+
+TAU :: 6.28;
+PI :: PI/2;
+
+main :: proc() {
+	x : int = 2;
+	x = x * 3;
+
+	y := add(1, x);
+}

+ 12 - 0
run.bat

@@ -0,0 +1,12 @@
+@echo off
+
+
+rem del "..\examples\test.bc"
+call ..\bin\odin.exe ..\examples/test.odin
+rem clang -S -emit-llvm ..\examples/test.c -o ..\examples/test.ll
+call llvm-as < ..\examples/test.ll
+rem call lli ..\examples/test.ll
+
+rem call lli ..\examples/test.bc rem JIT
+rem llc ..\examples/test.bc -march=x86-64 -o ..\examples/test.exe
+

+ 161 - 173
src/checker/checker.cpp

@@ -1,4 +1,4 @@
-#include "value.cpp"
+#include "../exact_value.cpp"
 #include "entity.cpp"
 #include "type.cpp"
 
@@ -18,7 +18,7 @@ enum AddressingMode {
 struct Operand {
 	AddressingMode mode;
 	Type *type;
-	Value value;
+	ExactValue value;
 
 	AstNode *expression;
 	BuiltinProcedureId builtin_id;
@@ -27,7 +27,7 @@ struct Operand {
 struct TypeAndValue {
 	AddressingMode mode;
 	Type *type;
-	Value value;
+	ExactValue value;
 };
 
 struct DeclarationInfo {
@@ -44,10 +44,15 @@ struct DeclarationInfo {
 	i32 mark;
 };
 
-DeclarationInfo *make_declaration_info(gbAllocator a, Scope *scope) {
-	DeclarationInfo *d = gb_alloc_item(a, DeclarationInfo);
+
+void init_declaration_info(DeclarationInfo *d, Scope *scope) {
 	d->scope = scope;
 	map_init(&d->deps, gb_heap_allocator());
+}
+
+DeclarationInfo *make_declaration_info(gbAllocator a, Scope *scope) {
+	DeclarationInfo *d = gb_alloc_item(a, DeclarationInfo);
+	init_declaration_info(d, scope);
 	return d;
 }
 
@@ -71,10 +76,10 @@ struct ExpressionInfo {
 	b32 is_lhs; // Debug info
 	AddressingMode mode;
 	Type *type; // Type_Basic
-	Value value;
+	ExactValue value;
 };
 
-ExpressionInfo make_expression_info(b32 is_lhs, AddressingMode mode, Type *type, Value value) {
+ExpressionInfo make_expression_info(b32 is_lhs, AddressingMode mode, Type *type, ExactValue value) {
 	ExpressionInfo ei = {};
 	ei.is_lhs = is_lhs;
 	ei.mode   = mode;
@@ -84,6 +89,7 @@ ExpressionInfo make_expression_info(b32 is_lhs, AddressingMode mode, Type *type,
 }
 
 struct ProcedureInfo {
+	AstFile *file;
 	Token            token;
 	DeclarationInfo *decl;
 	Type *           type; // Type_Procedure
@@ -155,8 +161,9 @@ struct Checker {
 	Map<ExpressionInfo>    untyped;     // Key: AstNode * | Expression -> ExpressionInfo
 	Map<DeclarationInfo *> entities;    // Key: Entity *
 
+	AstFile *              curr_ast_file;
 	BaseTypeSizes          sizes;
-	Scope *                file_scope;
+	Scope *                global_scope;
 	gbArray(ProcedureInfo) procedures; // NOTE(bill): Procedures to check
 
 	gbArena     arena;
@@ -168,21 +175,20 @@ struct Checker {
 	gbArray(Type *) procedure_stack;
 	b32 in_defer; // TODO(bill): Actually handle correctly
 
-#define MAX_CHECKER_ERROR_COUNT 10
 	isize error_prev_line;
 	isize error_prev_column;
 	isize error_count;
 };
 
 
-gb_global Scope *global_scope = NULL;
+gb_global Scope *universal_scope = NULL;
 
 
 Scope *make_scope(Scope *parent, gbAllocator allocator) {
 	Scope *s = gb_alloc_item(allocator, Scope);
 	s->parent = parent;
 	map_init(&s->elements, gb_heap_allocator());
-	if (parent != NULL && parent != global_scope) {
+	if (parent != NULL && parent != universal_scope) {
 		DLIST_APPEND(parent->first_child, parent->last_child, s);
 	}
 	return s;
@@ -258,12 +264,12 @@ void add_global_entity(Entity *entity) {
 	if (gb_memchr(name.text, ' ', name.len)) {
 		return; // NOTE(bill): `untyped thing`
 	}
-	if (scope_insert_entity(global_scope, entity)) {
+	if (scope_insert_entity(universal_scope, entity)) {
 		GB_PANIC("Compiler error: double declaration");
 	}
 }
 
-void add_global_constant(gbAllocator a, String name, Type *type, Value value) {
+void add_global_constant(gbAllocator a, String name, Type *type, ExactValue value) {
 	Token token = {Token_Identifier};
 	token.string = name;
 	Entity *entity = alloc_entity(a, Entity_Constant, NULL, token, type);
@@ -271,10 +277,10 @@ void add_global_constant(gbAllocator a, String name, Type *type, Value value) {
 	add_global_entity(entity);
 }
 
-void init_global_scope(void) {
+void init_universal_scope(void) {
 	// NOTE(bill): No need to free these
 	gbAllocator a = gb_heap_allocator();
-	global_scope = make_scope(NULL, a);
+	universal_scope = make_scope(NULL, a);
 
 // Types
 	for (isize i = 0; i < gb_count_of(basic_types); i++) {
@@ -289,9 +295,9 @@ void init_global_scope(void) {
 	}
 
 // Constants
-	add_global_constant(a, make_string("true"),  &basic_types[Basic_UntypedBool],    make_value_bool(true));
-	add_global_constant(a, make_string("false"), &basic_types[Basic_UntypedBool],    make_value_bool(false));
-	add_global_constant(a, make_string("null"),  &basic_types[Basic_UntypedPointer], make_value_pointer(NULL));
+	add_global_constant(a, make_string("true"),  &basic_types[Basic_UntypedBool],    make_exact_value_bool(true));
+	add_global_constant(a, make_string("false"), &basic_types[Basic_UntypedBool],    make_exact_value_bool(false));
+	add_global_constant(a, make_string("null"),  &basic_types[Basic_UntypedPointer], make_exact_value_pointer(NULL));
 
 // Builtin Procedures
 	for (isize i = 0; i < gb_count_of(builtin_procedures); i++) {
@@ -329,12 +335,17 @@ void init_checker(Checker *c, Parser *parser) {
 
 	// NOTE(bill): Is this big enough or too small?
 	isize item_size = gb_max(gb_max(gb_size_of(Entity), gb_size_of(Type)), gb_size_of(Scope));
-	isize arena_size = 2 * item_size * gb_array_count(c->parser->tokens);
+	isize total_token_count = 0;
+	for (isize i = 0; i < gb_array_count(c->parser->files); i++) {
+		AstFile *f = &c->parser->files[i];
+		total_token_count += gb_array_count(f->tokens);
+	}
+	isize arena_size = 2 * item_size * total_token_count;
 	gb_arena_init_from_allocator(&c->arena, a, arena_size);
 	c->allocator = gb_arena_allocator(&c->arena);
 
-	c->file_scope = make_scope(global_scope, c->allocator);
-	c->curr_scope = c->file_scope;
+	c->global_scope = make_scope(universal_scope, c->allocator);
+	c->curr_scope = c->global_scope;
 }
 
 void destroy_checker(Checker *c) {
@@ -344,7 +355,7 @@ void destroy_checker(Checker *c) {
 	map_destroy(&c->scopes);
 	map_destroy(&c->untyped);
 	map_destroy(&c->entities);
-	destroy_scope(c->file_scope);
+	destroy_scope(c->global_scope);
 	gb_array_free(c->procedure_stack);
 	gb_array_free(c->procedures);
 
@@ -353,8 +364,8 @@ void destroy_checker(Checker *c) {
 
 
 
-#define print_checker_error(p, token, fmt, ...) print_checker_error_(p, __FUNCTION__, token, fmt, ##__VA_ARGS__)
-void print_checker_error_(Checker *c, char *function, Token token, char *fmt, ...) {
+#define checker_err(p, token, fmt, ...) checker_err_(p, __FUNCTION__, token, fmt, ##__VA_ARGS__)
+void checker_err_(Checker *c, char *function, Token token, char *fmt, ...) {
 
 
 	// NOTE(bill): Duplicate error, skip it
@@ -368,20 +379,20 @@ void print_checker_error_(Checker *c, char *function, Token token, char *fmt, ..
 
 		va_list va;
 		va_start(va, fmt);
-		gb_printf_err("%s(%td:%td) %s\n",
-		              c->parser->tokenizer.fullpath, token.line, token.column,
+		gb_printf_err("%.*s(%td:%td) %s\n",
+		              LIT(c->curr_ast_file->tokenizer.fullpath), token.line, token.column,
 		              gb_bprintf_va(fmt, va));
 		va_end(va);
 
 	}
 	c->error_count++;
 	// NOTE(bill): If there are too many errors, just quit
-	if (c->error_count > MAX_CHECKER_ERROR_COUNT) {
-		gb_exit(1);
-		return;
-	}
 }
 
+TypeAndValue *type_and_value_of_expression(Checker *c, AstNode *expression) {
+	TypeAndValue *found = map_get(&c->types, hash_pointer(expression));
+	return found;
+}
 
 
 Entity *entity_of_identifier(Checker *c, AstNode *identifier) {
@@ -397,7 +408,7 @@ Entity *entity_of_identifier(Checker *c, AstNode *identifier) {
 }
 
 Type *type_of_expression(Checker *c, AstNode *expression) {
-	TypeAndValue *found = map_get(&c->types, hash_pointer(expression));
+	TypeAndValue *found = type_and_value_of_expression(c, expression);
 	if (found)
 		return found->type;
 	if (expression->kind == AstNode_Identifier) {
@@ -410,19 +421,19 @@ Type *type_of_expression(Checker *c, AstNode *expression) {
 }
 
 
-void add_untyped(Checker *c, AstNode *expression, b32 lhs, AddressingMode mode, Type *basic_type, Value value) {
+void add_untyped(Checker *c, AstNode *expression, b32 lhs, AddressingMode mode, Type *basic_type, ExactValue value) {
 	map_set(&c->untyped, hash_pointer(expression), make_expression_info(lhs, mode, basic_type, value));
 }
 
 
-void add_type_and_value(Checker *c, AstNode *expression, AddressingMode mode, Type *type, Value value) {
+void add_type_and_value(Checker *c, AstNode *expression, AddressingMode mode, Type *type, ExactValue value) {
 	GB_ASSERT(expression != NULL);
 	GB_ASSERT(type != NULL);
 	if (mode == Addressing_Invalid)
 		return;
 
 	if (mode == Addressing_Constant) {
-		GB_ASSERT(value.kind != Value_Invalid);
+		GB_ASSERT(value.kind != ExactValue_Invalid);
 		GB_ASSERT(type == &basic_types[Basic_Invalid] || is_type_constant_type(type));
 	}
 
@@ -443,7 +454,7 @@ void add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
 	if (!are_strings_equal(entity->token.string, make_string("_"))) {
 		Entity *insert_entity = scope_insert_entity(scope, entity);
 		if (insert_entity) {
-			print_checker_error(c, entity->token, "Redeclared entity in this scope: %.*s", LIT(entity->token.string));
+			checker_err(c, entity->token, "Redeclared entity in this scope: %.*s", LIT(entity->token.string));
 			return;
 		}
 	}
@@ -463,14 +474,15 @@ void add_file_entity(Checker *c, AstNode *identifier, Entity *e, DeclarationInfo
 	GB_ASSERT(are_strings_equal(identifier->identifier.token.string, e->token.string));
 
 
-	add_entity(c, c->file_scope, identifier, e);
+	add_entity(c, c->global_scope, identifier, e);
 	map_set(&c->entities, hash_pointer(e), d);
 	e->order = gb_array_count(c->entities.entries);
 }
 
 
-void check_procedure_later(Checker *c, Token token, DeclarationInfo *decl, Type *type, AstNode *body) {
+void check_procedure_later(Checker *c, AstFile *file, Token token, DeclarationInfo *decl, Type *type, AstNode *body) {
 	ProcedureInfo info = {};
+	info.file = file;
 	info.token = token;
 	info.decl  = decl;
 	info.type  = type;
@@ -506,6 +518,12 @@ void pop_procedure(Checker *c) {
 }
 
 
+void add_curr_ast_file(Checker *c, AstFile *file) {
+	c->error_prev_line = 0;
+	c->error_prev_column = 0;
+	c->curr_ast_file = file;
+}
+
 
 
 
@@ -523,162 +541,115 @@ GB_COMPARE_PROC(entity_order_cmp) {
 	return p->order < q->order ? -1 : p->order > q->order;
 }
 
-void check_file(Checker *c, AstNode *file_node) {
-
-// Collect Entities
-	for (AstNode *decl = file_node; decl != NULL; decl = decl->next) {
-		if (!is_ast_node_declaration(decl))
-			continue;
-
-		switch (decl->kind) {
-		case AstNode_BadDeclaration:
-			break;
-
-		case AstNode_VariableDeclaration: {
-			auto *vd = &decl->variable_declaration;
-
-			switch (vd->kind) {
-			case Declaration_Immutable: {
-				for (AstNode *name = vd->name_list, *value = vd->value_list;
-				     name != NULL && value != NULL;
-				     name = name->next, value = value->next) {
-					GB_ASSERT(name->kind == AstNode_Identifier);
-					Value v = {Value_Invalid};
-					Entity *e = make_entity_constant(c->allocator, c->curr_scope, name->identifier.token, NULL, v);
-					DeclarationInfo *di = make_declaration_info(c->allocator, c->file_scope);
-					di->type_expr = vd->type_expression;
-					di->init_expr = value;
-					add_file_entity(c, name, e, di);
-				}
-
-				isize lhs_count = vd->name_list_count;
-				isize rhs_count = vd->value_list_count;
-
-				if (rhs_count == 0 && vd->type_expression == NULL) {
-					print_checker_error(c, ast_node_token(decl), "Missing type or initial expression");
-				} else if (lhs_count < rhs_count) {
-					print_checker_error(c, ast_node_token(decl), "Extra initial expression");
-				}
-			} break;
-
-			case Declaration_Mutable: {
-				isize entity_count = vd->name_list_count;
-				isize entity_index = 0;
-				Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
-				DeclarationInfo *di = NULL;
-				if (vd->value_list_count == 1) {
-					di = make_declaration_info(gb_heap_allocator(), c->file_scope);
-					di->entities = entities;
-					di->entity_count = entity_count;
-					di->type_expr = vd->type_expression;
-					di->init_expr = vd->value_list;
-				}
-
-				AstNode *value = vd->value_list;
-				for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
-					Entity *e = make_entity_variable(c->allocator, c->file_scope, name->identifier.token, NULL);
-					entities[entity_index++] = e;
-
-					DeclarationInfo *d = di;
-					if (d == NULL) {
-						AstNode *init_expr = value;
-						d = make_declaration_info(gb_heap_allocator(), c->file_scope);
-						d->type_expr = vd->type_expression;
-						d->init_expr = init_expr;
+void check_parsed_files(Checker *c) {
+	// Collect Entities
+	for (isize i = 0; i < gb_array_count(c->parser->files); i++) {
+		AstFile *f = &c->parser->files[i];
+		add_curr_ast_file(c, f);
+		for (AstNode *decl = f->declarations; decl != NULL; decl = decl->next) {
+			if (!is_ast_node_declaration(decl))
+				continue;
+
+			switch (decl->kind) {
+			case AstNode_BadDeclaration:
+				break;
+
+			case AstNode_VariableDeclaration: {
+				auto *vd = &decl->variable_declaration;
+
+				switch (vd->kind) {
+				case Declaration_Immutable: {
+					for (AstNode *name = vd->name_list, *value = vd->value_list;
+					     name != NULL && value != NULL;
+					     name = name->next, value = value->next) {
+						GB_ASSERT(name->kind == AstNode_Identifier);
+						ExactValue v = {ExactValue_Invalid};
+						Entity *e = make_entity_constant(c->allocator, c->curr_scope, name->identifier.token, NULL, v);
+						DeclarationInfo *di = make_declaration_info(c->allocator, c->global_scope);
+						di->type_expr = vd->type_expression;
+						di->init_expr = value;
+						add_file_entity(c, name, e, di);
 					}
 
-					add_file_entity(c, name, e, d);
+					isize lhs_count = vd->name_list_count;
+					isize rhs_count = vd->value_list_count;
 
-					if (value != NULL)
-						value = value->next;
-				}
+					if (rhs_count == 0 && vd->type_expression == NULL) {
+						checker_err(c, ast_node_token(decl), "Missing type or initial expression");
+					} else if (lhs_count < rhs_count) {
+						checker_err(c, ast_node_token(decl), "Extra initial expression");
+					}
+				} break;
+
+				case Declaration_Mutable: {
+					isize entity_count = vd->name_list_count;
+					isize entity_index = 0;
+					Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
+					DeclarationInfo *di = NULL;
+					if (vd->value_list_count == 1) {
+						di = make_declaration_info(gb_heap_allocator(), c->global_scope);
+						di->entities = entities;
+						di->entity_count = entity_count;
+						di->type_expr = vd->type_expression;
+						di->init_expr = vd->value_list;
+					}
 
-#if 0
-				for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
-					Entity *entity = NULL;
-					Token token = name->identifier.token;
-					if (name->kind == AstNode_Identifier) {
-						String str = token.string;
-						Entity *found = NULL;
-						// NOTE(bill): Ignore assignments to `_`
-						b32 can_be_ignored = are_strings_equal(str, make_string("_"));
-						if (!can_be_ignored) {
-							found = current_scope_lookup_entity(c->file_scope, str);
-						}
-						if (found == NULL) {
-							entity = make_entity_variable(c->allocator, c->file_scope, token, NULL);
-							if (!can_be_ignored) {
-								new_entities[new_entity_count++] = entity;
-							}
-							add_entity_definition(c, name, entity);
-						} else {
-							entity = found;
+					AstNode *value = vd->value_list;
+					for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
+						Entity *e = make_entity_variable(c->allocator, c->global_scope, name->identifier.token, NULL);
+						entities[entity_index++] = e;
+
+						DeclarationInfo *d = di;
+						if (d == NULL) {
+							AstNode *init_expr = value;
+							d = make_declaration_info(gb_heap_allocator(), c->global_scope);
+							d->type_expr = vd->type_expression;
+							d->init_expr = init_expr;
 						}
-					} else {
-						print_checker_error(c, token, "A variable declaration must be an identifier");
-					}
-					if (entity == NULL)
-						entity = make_entity_dummy_variable(c, token);
-					entities[entity_index++] = entity;
-				}
 
-				Type *init_type = NULL;
-				if (vd->type_expression) {
-					init_type = check_type(c, vd->type_expression, NULL);
-					if (init_type == NULL)
-						init_type = &basic_types[Basic_Invalid];
-				}
+						add_file_entity(c, name, e, d);
 
-				for (isize i = 0; i < entity_count; i++) {
-					Entity *e = entities[i];
-					GB_ASSERT(e != NULL);
-					if (e->variable.visited) {
-						e->type = &basic_types[Basic_Invalid];
-						continue;
+						if (value != NULL)
+							value = value->next;
 					}
-					e->variable.visited = true;
-
-					if (e->type == NULL)
-						e->type = init_type;
+				} break;
 				}
 
 
-				check_init_variables(c, entities, entity_count, vd->value_list, vd->value_list_count, make_string("variable declaration"));
-#endif
 			} break;
-			}
 
+			case AstNode_TypeDeclaration: {
+				AstNode *identifier = decl->type_declaration.name;
+				Entity *e = make_entity_type_name(c->allocator, c->global_scope, identifier->identifier.token, NULL);
+				DeclarationInfo *d = make_declaration_info(c->allocator, e->parent);
+				d->type_expr = decl->type_declaration.type_expression;
+				add_file_entity(c, identifier, e, d);
+			} break;
 
-		} break;
-
-		case AstNode_TypeDeclaration: {
-			AstNode *identifier = decl->type_declaration.name;
-			Entity *e = make_entity_type_name(c->allocator, c->file_scope, identifier->identifier.token, NULL);
-			DeclarationInfo *d = make_declaration_info(c->allocator, e->parent);
-			d->type_expr = decl->type_declaration.type_expression;
-			add_file_entity(c, identifier, e, d);
-		} break;
+			case AstNode_ProcedureDeclaration: {
+				AstNode *identifier = decl->procedure_declaration.name;
+				Token token = identifier->identifier.token;
+				Entity *e = make_entity_procedure(c->allocator, c->global_scope, token, NULL);
+				add_entity(c, c->global_scope, identifier, e);
+				DeclarationInfo *d = make_declaration_info(c->allocator, e->parent);
+				d->proc_decl = decl;
+				map_set(&c->entities, hash_pointer(e), d);
+				e->order = gb_array_count(c->entities.entries);
 
-		case AstNode_ProcedureDeclaration: {
-			AstNode *identifier = decl->procedure_declaration.name;
-			Token token = identifier->identifier.token;
-			Entity *e = make_entity_procedure(c->allocator, c->file_scope, token, NULL);
-			add_entity(c, c->file_scope, identifier, e);
-			DeclarationInfo *d = make_declaration_info(c->allocator, e->parent);
-			d->proc_decl = decl;
-			map_set(&c->entities, hash_pointer(e), d);
-			e->order = gb_array_count(c->entities.entries);
+			} break;
 
-		} break;
+			case AstNode_ImportDeclaration:
+				// NOTE(bill): ignore
+				break;
 
-		default:
-			print_checker_error(c, ast_node_token(decl), "Only declarations are allowed at file scope");
-			break;
+			default:
+				checker_err(c, ast_node_token(decl), "Only declarations are allowed at file scope");
+				break;
+			}
 		}
 	}
 
-// Order entities
-	{
+	{ // Order entities
 		gbArray(Entity *) entities;
 		isize count = gb_array_count(c->entities.entries);
 		gb_array_init_reserve(entities, gb_heap_allocator(), count);
@@ -698,10 +669,27 @@ void check_file(Checker *c, AstNode *file_node) {
 	}
 
 
+	// Check procedure bodies
 	for (isize i = 0; i < gb_array_count(c->procedures); i++) {
 		ProcedureInfo *pi = &c->procedures[i];
+		add_curr_ast_file(c, pi->file);
 		check_procedure_body(c, pi->token, pi->decl, pi->type, pi->body);
 	}
+
+
+	{ // Add untyped expression values
+		isize count = gb_array_count(c->untyped.entries);
+		for (isize i = 0; i < count; i++) {
+			auto *entry = c->untyped.entries + i;
+			u64 key = entry->key;
+			AstNode *expr = cast(AstNode *)cast(uintptr)key;
+			ExpressionInfo *info = &entry->value;
+			if (is_type_typed(info->type)) {
+				GB_PANIC("%s (type %s) is typed!", expression_to_string(expr), info->type);
+			}
+			add_type_and_value(c, expr, info->mode, info->type, info->value);
+		}
+	}
 }
 
 

+ 2 - 2
src/checker/entity.cpp

@@ -26,7 +26,7 @@ struct Entity {
 	isize order;
 
 	union {
-		struct { Value value; } constant;
+		struct { ExactValue value; } constant;
 		struct {
 			b8 visited;
 			b8 is_field;
@@ -59,7 +59,7 @@ Entity *make_entity_variable(gbAllocator a, Scope *parent, Token token, Type *ty
 	return entity;
 }
 
-Entity *make_entity_constant(gbAllocator a, Scope *parent, Token token, Type *type, Value value) {
+Entity *make_entity_constant(gbAllocator a, Scope *parent, Token token, Type *type, ExactValue value) {
 	Entity *entity = alloc_entity(a, Entity_Constant, parent, token, type);
 	entity->constant.value = value;
 	return entity;

File diff suppressed because it is too large
+ 230 - 223
src/checker/expression.cpp


+ 60 - 55
src/checker/statements.cpp

@@ -131,16 +131,19 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
 		if (!check_is_assignable_to(c, operand, type)) {
 			gbString type_string = type_to_string(type);
 			gbString op_type_string = type_to_string(operand->type);
+			gbString expr_str = expression_to_string(operand->expression);
 			defer (gb_string_free(type_string));
 			defer (gb_string_free(op_type_string));
+			defer (gb_string_free(expr_str));
+
 
 			// TODO(bill): is this a good enough error message?
-			print_checker_error(c, ast_node_token(operand->expression),
-			                    "Cannot assign value `%.*s` of type `%s` to `%s` in %.*s",
-			                    LIT(ast_node_token(operand->expression).string),
-			                    op_type_string,
-			                    type_string,
-			                    LIT(context_name));
+			checker_err(c, ast_node_token(operand->expression),
+			            "Cannot assign value `%s` of type `%s` to `%s` in %.*s",
+			            expr_str,
+			            op_type_string,
+			            type_string,
+			            LIT(context_name));
 
 			operand->mode = Addressing_Invalid;
 		}
@@ -200,8 +203,7 @@ Type *check_assign_variable(Checker *c, Operand *op_a, AstNode *lhs) {
 
 		gbString str = expression_to_string(op_b.expression);
 		defer (gb_string_free(str));
-		print_checker_error(c, ast_node_token(op_b.expression),
-		                    "Cannot assign to `%s`", str);
+		checker_err(c, ast_node_token(op_b.expression), "Cannot assign to `%s`", str);
 	} break;
 	}
 
@@ -254,7 +256,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
 		Type *t = operand->type;
 		if (is_type_untyped(t)) {
 			if (t == &basic_types[Basic_Invalid]) {
-				print_checker_error(c, e->token, "Use of untyped thing in %.*s", LIT(context_name));
+				checker_err(c, e->token, "Use of untyped thing in %.*s", LIT(context_name));
 				e->type = &basic_types[Basic_Invalid];
 				return NULL;
 			}
@@ -297,9 +299,9 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNode *in
 
 	if (i < lhs_count && i < init_count) {
 		if (lhs[i]->type == NULL)
-			print_checker_error(c, lhs[i]->token, "Too few values on the right hand side of the declaration");
+			checker_err(c, lhs[i]->token, "Too few values on the right hand side of the declaration");
 	} else if (rhs != NULL) {
-		print_checker_error(c, ast_node_token(rhs), "Too many values on the right hand side of the declaration");
+		checker_err(c, ast_node_token(rhs), "Too many values on the right hand side of the declaration");
 	}
 }
 
@@ -314,8 +316,8 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
 
 	if (operand->mode != Addressing_Constant) {
 		// TODO(bill): better error
-		print_checker_error(c, ast_node_token(operand->expression),
-		                    "`%.*s` is not a constant", LIT(ast_node_token(operand->expression).string));
+		checker_err(c, ast_node_token(operand->expression),
+		            "`%.*s` is not a constant", LIT(ast_node_token(operand->expression).string));
 		if (e->type == NULL)
 			e->type = &basic_types[Basic_Invalid];
 		return;
@@ -350,8 +352,8 @@ void check_constant_declaration(Checker *c, Entity *e, AstNode *type_expr, AstNo
 		if (!is_type_constant_type(t)) {
 			gbString str = type_to_string(t);
 			defer (gb_string_free(str));
-			print_checker_error(c, ast_node_token(type_expr),
-			                    "Invalid constant type `%s`", str);
+			checker_err(c, ast_node_token(type_expr),
+			            "Invalid constant type `%s`", str);
 			e->type = &basic_types[Basic_Invalid];
 			return;
 		}
@@ -383,10 +385,9 @@ void check_procedure_body(Checker *c, Token token, DeclarationInfo *decl, Type *
 	c->curr_scope = decl->scope;
 	push_procedure(c, type);
 	check_statement_list(c, body->block_statement.list);
-	if (decl->type_expr != NULL &&
-	    decl->type_expr->procedure_type.result_count > 0) {
+	if (type->procedure.results_count > 0) {
 		if (!check_is_terminating(c, body)) {
-			print_checker_error(c, body->block_statement.close, "Missing return statement at the end of the procedure");
+			checker_err(c, body->block_statement.close, "Missing return statement at the end of the procedure");
 		}
 	}
 	pop_procedure(c);
@@ -403,7 +404,7 @@ void check_procedure_declaration(Checker *c, Entity *e, DeclarationInfo *d, b32
 
 #if 1
 	Scope *origin_curr_scope = c->curr_scope;
-	c->curr_scope = c->file_scope;
+	c->curr_scope = c->global_scope;
 	check_open_scope(c, pd->procedure_type);
 #endif
 	check_procedure_type(c, proc_type, pd->procedure_type);
@@ -421,27 +422,27 @@ void check_procedure_declaration(Checker *c, Entity *e, DeclarationInfo *d, b32
 		} else if (are_strings_equal(tag_name, make_string("no_inline"))) {
 			is_no_inline = true;
 		} else {
-			print_checker_error(c, ast_node_token(tag), "Unknown procedure tag");
+			checker_err(c, ast_node_token(tag), "Unknown procedure tag");
 		}
 		// TODO(bill): Other tags
 	}
 
 	if (is_inline && is_no_inline) {
-		print_checker_error(c, ast_node_token(pd->tag_list),
-		                    "You cannot apply both `inline` and `no_inline` to a procedure");
+		checker_err(c, ast_node_token(pd->tag_list),
+		            "You cannot apply both `inline` and `no_inline` to a procedure");
 	}
 
 	if (pd->body != NULL) {
 		if (is_foreign) {
-			print_checker_error(c, ast_node_token(pd->body),
-			                    "A procedure tagged as `#foreign` cannot have a body");
+			checker_err(c, ast_node_token(pd->body),
+			            "A procedure tagged as `#foreign` cannot have a body");
 		}
 
 		d->scope = c->curr_scope;
 
 		GB_ASSERT(pd->body->kind == AstNode_BlockStatement);
 		if (check_body_later) {
-			check_procedure_later(c, e->token, d, proc_type, pd->body);
+			check_procedure_later(c, c->curr_ast_file, e->token, d, proc_type, pd->body);
 		} else {
 			check_procedure_body(c, e->token, d, proc_type, pd->body);
 		}
@@ -533,19 +534,19 @@ void check_statement(Checker *c, AstNode *node) {
 		ExpressionKind kind = check_expression_base(c, &operand, node->expression_statement.expression);
 		switch (operand.mode) {
 		case Addressing_Type:
-			print_checker_error(c, ast_node_token(node), "Is not an expression");
+			checker_err(c, ast_node_token(node), "Is not an expression");
 			break;
 		default:
 			if (kind == Expression_Statement)
 				return;
-			print_checker_error(c, ast_node_token(node), "Expression is not used");
+			checker_err(c, ast_node_token(node), "Expression is not used");
 			break;
 		}
 	} break;
 
 	case AstNode_TagStatement:
 		// TODO(bill): Tag Statements
-		print_checker_error(c, ast_node_token(node), "Tag statements are not supported yet");
+		checker_err(c, ast_node_token(node), "Tag statements are not supported yet");
 		check_statement(c, node->tag_statement.statement);
 		break;
 
@@ -563,7 +564,7 @@ void check_statement(Checker *c, AstNode *node) {
 			op.string.len = 1;
 			break;
 		default:
-			print_checker_error(c, s->op, "Unknown inc/dec operation %.*s", LIT(s->op.string));
+			checker_err(c, s->op, "Unknown inc/dec operation %.*s", LIT(s->op.string));
 			return;
 		}
 
@@ -572,7 +573,7 @@ void check_statement(Checker *c, AstNode *node) {
 		if (operand.mode == Addressing_Invalid)
 			return;
 		if (!is_type_numeric(operand.type)) {
-			print_checker_error(c, s->op, "Non numeric type");
+			checker_err(c, s->op, "Non numeric type");
 			return;
 		}
 
@@ -592,7 +593,7 @@ void check_statement(Checker *c, AstNode *node) {
 		switch (node->assign_statement.op.kind) {
 		case Token_Eq:
 			if (node->assign_statement.lhs_count == 0) {
-				print_checker_error(c, node->assign_statement.op, "Missing lhs in assignment statement");
+				checker_err(c, node->assign_statement.op, "Missing lhs in assignment statement");
 				return;
 			}
 			check_assign_variables(c,
@@ -604,8 +605,11 @@ void check_statement(Checker *c, AstNode *node) {
 			Token op = node->assign_statement.op;
 			if (node->assign_statement.lhs_count != 1 ||
 			    node->assign_statement.rhs_count != 1) {
-				print_checker_error(c, op,
-				                    "assignment operation `%.*s` requires single-valued expressions", LIT(op.string));
+				checker_err(c, op, "Assignment operation `%.*s` requires single-valued expressions", LIT(op.string));
+				return;
+			}
+			if (!gb_is_between(op.kind, Token_AddEq, Token_ModEq)) {
+				checker_err(c, op, "Unknown Assignment operation `%.*s`", LIT(op.string));
 				return;
 			}
 			// TODO(bill): Check if valid assignment operator
@@ -636,8 +640,8 @@ void check_statement(Checker *c, AstNode *node) {
 		check_expression(c, &operand, node->if_statement.cond);
 		if (operand.mode != Addressing_Invalid &&
 		    !is_type_boolean(operand.type)) {
-			print_checker_error(c, ast_node_token(node->if_statement.cond),
-			                    "Non-boolean condition in `if` statement");
+			checker_err(c, ast_node_token(node->if_statement.cond),
+			            "Non-boolean condition in `if` statement");
 		}
 		check_statement(c, node->if_statement.body);
 
@@ -648,8 +652,8 @@ void check_statement(Checker *c, AstNode *node) {
 				check_statement(c, node->if_statement.else_statement);
 				break;
 			default:
-				print_checker_error(c, ast_node_token(node->if_statement.else_statement),
-				                    "Invalid `else` statement in `if` statement");
+				checker_err(c, ast_node_token(node->if_statement.else_statement),
+				            "Invalid `else` statement in `if` statement");
 				break;
 			}
 		}
@@ -660,7 +664,7 @@ void check_statement(Checker *c, AstNode *node) {
 		GB_ASSERT(gb_array_count(c->procedure_stack) > 0);
 
 		if (c->in_defer) {
-			print_checker_error(c, rs->token, "You cannot `return` within a defer statement");
+			checker_err(c, rs->token, "You cannot `return` within a defer statement");
 			// TODO(bill): Should I break here?
 			break;
 		}
@@ -670,10 +674,10 @@ void check_statement(Checker *c, AstNode *node) {
 		if (proc_type->procedure.results)
 			result_count = proc_type->procedure.results->tuple.variable_count;
 		if (result_count != rs->result_count) {
-			print_checker_error(c, rs->token, "Expected %td return %s, got %td",
-			                    result_count,
-			                    (result_count != 1 ? "values" : "value"),
-			                    rs->result_count);
+			checker_err(c, rs->token, "Expected %td return %s, got %td",
+			            result_count,
+			            (result_count != 1 ? "values" : "value"),
+			            rs->result_count);
 		} else if (result_count > 0) {
 			auto *tuple = &proc_type->procedure.results->tuple;
 			check_init_variables(c, tuple->variables, tuple->variable_count,
@@ -691,8 +695,8 @@ void check_statement(Checker *c, AstNode *node) {
 			check_expression(c, &operand, node->for_statement.cond);
 			if (operand.mode != Addressing_Invalid &&
 			    !is_type_boolean(operand.type)) {
-				print_checker_error(c, ast_node_token(node->for_statement.cond),
-				                    "Non-boolean condition in `for` statement");
+				checker_err(c, ast_node_token(node->for_statement.cond),
+				            "Non-boolean condition in `for` statement");
 			}
 		}
 		check_statement(c, node->for_statement.end);
@@ -702,7 +706,7 @@ void check_statement(Checker *c, AstNode *node) {
 	case AstNode_DeferStatement: {
 		auto *ds = &node->defer_statement;
 		if (is_ast_node_declaration(ds->statement)) {
-			print_checker_error(c, ds->token, "You cannot defer a declaration");
+			checker_err(c, ds->token, "You cannot defer a declaration");
 		} else {
 			b32 out_in_defer = c->in_defer;
 			c->in_defer = true;
@@ -744,10 +748,10 @@ void check_statement(Checker *c, AstNode *node) {
 						entity = found;
 					}
 				} else {
-					print_checker_error(c, token, "A variable declaration must be an identifier");
+					checker_err(c, token, "A variable declaration must be an identifier");
 				}
 				if (entity == NULL)
-					entity = make_entity_dummy_variable(c->allocator, c->file_scope, token);
+					entity = make_entity_dummy_variable(c->allocator, c->global_scope, token);
 				entities[entity_index++] = entity;
 			}
 
@@ -786,7 +790,7 @@ void check_statement(Checker *c, AstNode *node) {
 			     name != NULL && value != NULL;
 			     name = name->next, value = value->next) {
 				GB_ASSERT(name->kind == AstNode_Identifier);
-				Value v = {Value_Invalid};
+				ExactValue v = {ExactValue_Invalid};
 				Entity *e = make_entity_constant(c->allocator, c->curr_scope, name->identifier.token, NULL, v);
 				entities[entity_index++] = e;
 				check_constant_declaration(c, e, vd->type_expression, value);
@@ -797,9 +801,9 @@ void check_statement(Checker *c, AstNode *node) {
 
 			// TODO(bill): Better error messages or is this good enough?
 			if (rhs_count == 0 && vd->type_expression == NULL) {
-				print_checker_error(c, ast_node_token(node), "Missing type or initial expression");
+				checker_err(c, ast_node_token(node), "Missing type or initial expression");
 			} else if (lhs_count < rhs_count) {
-				print_checker_error(c, ast_node_token(node), "Extra initial expression");
+				checker_err(c, ast_node_token(node), "Extra initial expression");
 			}
 
 			AstNode *name = vd->name_list;
@@ -809,7 +813,7 @@ void check_statement(Checker *c, AstNode *node) {
 		} break;
 
 		default:
-			print_checker_error(c, ast_node_token(node), "Unknown variable declaration kind. Probably an invalid AST.");
+			checker_err(c, ast_node_token(node), "Unknown variable declaration kind. Probably an invalid AST.");
 			return;
 		}
 	} break;
@@ -819,10 +823,11 @@ void check_statement(Checker *c, AstNode *node) {
 		Entity *e = make_entity_procedure(c->allocator, c->curr_scope, pd->name->identifier.token, NULL);
 		add_entity(c, c->curr_scope, pd->name, e);
 
-		DeclarationInfo *decl = make_declaration_info(gb_heap_allocator(), e->parent);
-		decl->proc_decl = node;
-		check_procedure_declaration(c, e, decl, false);
-		destroy_declaration_info(decl);
+		DeclarationInfo decl = {};
+		init_declaration_info(&decl, e->parent);
+		decl.proc_decl = node;
+		check_procedure_declaration(c, e, &decl, false);
+		destroy_declaration_info(&decl);
 	} break;
 
 	case AstNode_TypeDeclaration: {

+ 3 - 1
src/checker/type.cpp

@@ -26,6 +26,7 @@ enum BasicKind {
 
 	Basic_Count,
 
+	Basic_byte = Basic_u8,
 	Basic_rune = Basic_i32,
 };
 
@@ -204,7 +205,8 @@ gb_global Type basic_types[] = {
 };
 
 gb_global Type basic_type_aliases[] = {
-	{Type_Basic, {Basic_rune, BasicFlag_Integer,  STR_LIT("rune")}},
+	{Type_Basic, {Basic_byte, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("byte")}},
+	{Type_Basic, {Basic_rune, BasicFlag_Integer,                      STR_LIT("rune")}},
 };
 
 

+ 103 - 103
src/checker/value.cpp → src/exact_value.cpp

@@ -3,20 +3,20 @@
 // TODO(bill): Big numbers
 // IMPORTANT TODO(bill): This needs to be completely fixed!!!!!!!!
 
-enum ValueKind {
-	Value_Invalid,
+enum ExactValueKind {
+	ExactValue_Invalid,
 
-	Value_Bool,
-	Value_String,
-	Value_Integer,
-	Value_Float,
-	Value_Pointer, // TODO(bill): Handle Value_Pointer correctly
+	ExactValue_Bool,
+	ExactValue_String,
+	ExactValue_Integer,
+	ExactValue_Float,
+	ExactValue_Pointer, // TODO(bill): Handle ExactValue_Pointer correctly
 
-	Value_Count,
+	ExactValue_Count,
 };
 
-struct Value {
-	ValueKind kind;
+struct ExactValue {
+	ExactValueKind kind;
 	union {
 		b32    value_bool;
 		String value_string;
@@ -26,22 +26,22 @@ struct Value {
 	};
 };
 
-Value make_value_bool(b32 b) {
-	Value result = {Value_Bool};
+ExactValue make_exact_value_bool(b32 b) {
+	ExactValue result = {ExactValue_Bool};
 	result.value_bool = (b != 0);
 	return result;
 }
 
-Value make_value_string(String string) {
+ExactValue make_exact_value_string(String string) {
 	// TODO(bill): Allow for numbers with underscores in them
-	Value result = {Value_String};
+	ExactValue result = {ExactValue_String};
 	result.value_string = string;
 	return result;
 }
 
-Value make_value_integer(String string) {
+ExactValue make_exact_value_integer(String string) {
 	// TODO(bill): Allow for numbers with underscores in them
-	Value result = {Value_Integer};
+	ExactValue result = {ExactValue_Integer};
 	i32 base = 10;
 	if (string.text[0] == '0') {
 		switch (string.text[1]) {
@@ -57,91 +57,91 @@ Value make_value_integer(String string) {
 	return result;
 }
 
-Value make_value_integer(i64 i) {
-	Value result = {Value_Integer};
+ExactValue make_exact_value_integer(i64 i) {
+	ExactValue result = {ExactValue_Integer};
 	result.value_integer = i;
 	return result;
 }
 
-Value make_value_float(String string) {
+ExactValue make_exact_value_float(String string) {
 	// TODO(bill): Allow for numbers with underscores in them
-	Value result = {Value_Float};
+	ExactValue result = {ExactValue_Float};
 	result.value_float = gb_str_to_f64(cast(char *)string.text, NULL);
 	return result;
 }
 
-Value make_value_float(f64 f) {
-	Value result = {Value_Float};
+ExactValue make_exact_value_float(f64 f) {
+	ExactValue result = {ExactValue_Float};
 	result.value_float = f;
 	return result;
 }
 
-Value make_value_pointer(void *ptr) {
-	Value result = {Value_Pointer};
+ExactValue make_exact_value_pointer(void *ptr) {
+	ExactValue result = {ExactValue_Pointer};
 	result.value_pointer = ptr;
 	return result;
 }
 
-Value make_value_from_basic_literal(Token token) {
+ExactValue make_exact_value_from_basic_literal(Token token) {
 	switch (token.kind) {
-	case Token_String:  return make_value_string(token.string);
-	case Token_Integer: return make_value_integer(token.string);
-	case Token_Float:   return make_value_float(token.string);
-	case Token_Rune:    return make_value_integer(token.string);
+	case Token_String:  return make_exact_value_string(token.string);
+	case Token_Integer: return make_exact_value_integer(token.string);
+	case Token_Float:   return make_exact_value_float(token.string);
+	case Token_Rune:    return make_exact_value_integer(token.string);
 	default:
 		GB_PANIC("Invalid token for basic literal");
 		break;
 	}
 
-	Value result = {Value_Invalid};
+	ExactValue result = {ExactValue_Invalid};
 	return result;
 }
 
-Value value_to_integer(Value v) {
+ExactValue exact_value_to_integer(ExactValue v) {
 	switch (v.kind) {
-	case Value_Integer:
+	case ExactValue_Integer:
 		return v;
-	case Value_Float:
-		return make_value_integer(cast(i64)v.value_float);
+	case ExactValue_Float:
+		return make_exact_value_integer(cast(i64)v.value_float);
 	}
-	Value r = {Value_Invalid};
+	ExactValue r = {ExactValue_Invalid};
 	return r;
 }
 
-Value value_to_float(Value v) {
+ExactValue exact_value_to_float(ExactValue v) {
 	switch (v.kind) {
-	case Value_Integer:
-		return make_value_float(cast(i64)v.value_integer);
-	case Value_Float:
+	case ExactValue_Integer:
+		return make_exact_value_float(cast(i64)v.value_integer);
+	case ExactValue_Float:
 		return v;
 	}
-	Value r = {Value_Invalid};
+	ExactValue r = {ExactValue_Invalid};
 	return r;
 }
 
 
-Value unary_operator_value(Token op, Value v, i32 precision) {
+ExactValue exact_unary_operator_value(Token op, ExactValue v, i32 precision) {
 	switch (op.kind) {
 	case Token_Add:	{
 		switch (v.kind) {
-		case Value_Invalid:
-		case Value_Integer:
-		case Value_Float:
+		case ExactValue_Invalid:
+		case ExactValue_Integer:
+		case ExactValue_Float:
 			return v;
 		}
 	} break;
 
 	case Token_Sub:	{
 		switch (v.kind) {
-		case Value_Invalid:
+		case ExactValue_Invalid:
 			return v;
-		case Value_Integer: {
-			Value i = v;
+		case ExactValue_Integer: {
+			ExactValue i = v;
 			i.value_integer = -i.value_integer;
 			return i;
 		}
-		case Value_Float: {
-			Value i = v;
+		case ExactValue_Float: {
+			ExactValue i = v;
 			i.value_float = -i.value_float;
 			return i;
 		}
@@ -151,9 +151,9 @@ Value unary_operator_value(Token op, Value v, i32 precision) {
 	case Token_Xor: {
 		i64 i = 0;
 		switch (v.kind) {
-		case Value_Invalid:
+		case ExactValue_Invalid:
 			return v;
-		case Value_Integer:
+		case ExactValue_Integer:
 			i = v.value_integer;
 			i = ~i;
 			break;
@@ -166,14 +166,14 @@ Value unary_operator_value(Token op, Value v, i32 precision) {
 		if (precision > 0)
 			i &= ~((~0ll)<<precision);
 
-		return make_value_integer(i);
+		return make_exact_value_integer(i);
 	} break;
 
 	case Token_Not: {
 		switch (v.kind) {
-		case Value_Invalid: return v;
-		case Value_Bool:
-			return make_value_bool(!v.value_bool);
+		case ExactValue_Invalid: return v;
+		case ExactValue_Bool:
+			return make_exact_value_bool(!v.value_bool);
 		}
 	} break;
 	}
@@ -181,23 +181,23 @@ Value unary_operator_value(Token op, Value v, i32 precision) {
 failure:
 	GB_PANIC("Invalid unary operation, %s", token_kind_to_string(op.kind));
 
-	Value error_value = {};
+	ExactValue error_value = {};
 	return error_value;
 }
 
 // NOTE(bill): Make sure things are evaluated in correct order
-i32 value_order(Value v) {
+i32 exact_value_order(ExactValue v) {
 	switch (v.kind) {
-	case Value_Invalid:
+	case ExactValue_Invalid:
 		return 0;
-	case Value_Bool:
-	case Value_String:
+	case ExactValue_Bool:
+	case ExactValue_String:
 		return 1;
-	case Value_Integer:
+	case ExactValue_Integer:
 		return 2;
-	case Value_Float:
+	case ExactValue_Float:
 		return 3;
-	case Value_Pointer:
+	case ExactValue_Pointer:
 		return 4;
 
 	default:
@@ -206,58 +206,58 @@ i32 value_order(Value v) {
 	}
 }
 
-void match_values(Value *x, Value *y) {
-	if (value_order(*y) < value_order(*x)) {
-		match_values(y, x);
+void match_exact_values(ExactValue *x, ExactValue *y) {
+	if (exact_value_order(*y) < exact_value_order(*x)) {
+		match_exact_values(y, x);
 		return;
 	}
 
 	switch (x->kind) {
-	case Value_Invalid:
+	case ExactValue_Invalid:
 		*y = *x;
 		return;
 
-	case Value_Bool:
-	case Value_String:
+	case ExactValue_Bool:
+	case ExactValue_String:
 		return;
 
-	case Value_Integer:
+	case ExactValue_Integer:
 		switch (y->kind) {
-		case Value_Integer:
+		case ExactValue_Integer:
 			return;
-		case Value_Float:
+		case ExactValue_Float:
 			// TODO(bill): Is this good enough?
-			*x = make_value_float(cast(f64)x->value_integer);
+			*x = make_exact_value_float(cast(f64)x->value_integer);
 			return;
 		}
 		break;
 
-	case Value_Float:
-		if (y->kind == Value_Float)
+	case ExactValue_Float:
+		if (y->kind == ExactValue_Float)
 			return;
 		break;
 	}
 
-	GB_PANIC("How'd you get here? Invalid Value.kind");
+	GB_PANIC("How'd you get here? Invalid ExactValueKind");
 }
 
 // TODO(bill): Allow for pointer arithmetic? Or are pointer slices good enough?
-Value binary_operator_value(Token op, Value x, Value y) {
-	match_values(&x, &y);
+ExactValue exact_binary_operator_value(Token op, ExactValue x, ExactValue y) {
+	match_exact_values(&x, &y);
 
 	switch (x.kind) {
-	case Value_Invalid:
+	case ExactValue_Invalid:
 		return x;
 
-	case Value_Bool:
+	case ExactValue_Bool:
 		switch (op.kind) {
-		case Token_CmpAnd: return make_value_bool(x.value_bool && y.value_bool);
-		case Token_CmpOr:  return make_value_bool(x.value_bool || y.value_bool);
+		case Token_CmpAnd: return make_exact_value_bool(x.value_bool && y.value_bool);
+		case Token_CmpOr:  return make_exact_value_bool(x.value_bool || y.value_bool);
 		default: goto error;
 		}
 		break;
 
-	case Value_Integer: {
+	case ExactValue_Integer: {
 		i64 a = x.value_integer;
 		i64 b = y.value_integer;
 		i64 c = 0;
@@ -265,7 +265,7 @@ Value binary_operator_value(Token op, Value x, Value y) {
 		case Token_Add:    c = a + b;  break;
 		case Token_Sub:    c = a - b;  break;
 		case Token_Mul:    c = a * b;  break;
-		case Token_Quo:    return make_value_float(fmod(cast(f64)a, cast(f64)b));
+		case Token_Quo:    return make_exact_value_float(fmod(cast(f64)a, cast(f64)b));
 		case Token_QuoEq:  c = a / b;  break; // NOTE(bill): Integer division
 		case Token_Mod:    c = a % b;  break;
 		case Token_And:    c = a & b;  break;
@@ -274,53 +274,53 @@ Value binary_operator_value(Token op, Value x, Value y) {
 		case Token_AndNot: c = a&(~b); break;
 		default: goto error;
 		}
-		return make_value_integer(c);
+		return make_exact_value_integer(c);
 	} break;
 
-	case Value_Float: {
+	case ExactValue_Float: {
 		f64 a = x.value_float;
 		f64 b = y.value_float;
 		switch (op.kind) {
-		case Token_Add: return make_value_float(a + b);
-		case Token_Sub: return make_value_float(a - b);
-		case Token_Mul: return make_value_float(a * b);
-		case Token_Quo: return make_value_float(a / b);
+		case Token_Add: return make_exact_value_float(a + b);
+		case Token_Sub: return make_exact_value_float(a - b);
+		case Token_Mul: return make_exact_value_float(a * b);
+		case Token_Quo: return make_exact_value_float(a / b);
 		default: goto error;
 		}
 	} break;
 	}
 
 error:
-	Value error_value = {};
-	GB_PANIC("Invalid binary operation: %s", token_kind_to_string(op.kind));
+	ExactValue error_value = {};
+	// gb_printf_err("Invalid binary operation: %s\n", token_kind_to_string(op.kind));
 	return error_value;
 }
 
-gb_inline Value value_add(Value x, Value y) { Token op = {Token_Add}; return binary_operator_value(op, x, y); }
-gb_inline Value value_sub(Value x, Value y) { Token op = {Token_Sub}; return binary_operator_value(op, x, y); }
-gb_inline Value value_mul(Value x, Value y) { Token op = {Token_Mul}; return binary_operator_value(op, x, y); }
-gb_inline Value value_quo(Value x, Value y) { Token op = {Token_Quo}; return binary_operator_value(op, x, y); }
+gb_inline ExactValue exact_value_add(ExactValue x, ExactValue y) { Token op = {Token_Add}; return exact_binary_operator_value(op, x, y); }
+gb_inline ExactValue exact_value_sub(ExactValue x, ExactValue y) { Token op = {Token_Sub}; return exact_binary_operator_value(op, x, y); }
+gb_inline ExactValue exact_value_mul(ExactValue x, ExactValue y) { Token op = {Token_Mul}; return exact_binary_operator_value(op, x, y); }
+gb_inline ExactValue exact_value_quo(ExactValue x, ExactValue y) { Token op = {Token_Quo}; return exact_binary_operator_value(op, x, y); }
 
 
 i32 cmp_f64(f64 a, f64 b) {
 	return (a > b) - (a < b);
 }
 
-b32 compare_values(Token op, Value x, Value y) {
-	match_values(&x, &y);
+b32 compare_exact_values(Token op, ExactValue x, ExactValue y) {
+	match_exact_values(&x, &y);
 
 	switch (x.kind) {
-	case Value_Invalid:
+	case ExactValue_Invalid:
 		return false;
 
-	case Value_Bool:
+	case ExactValue_Bool:
 		switch (op.kind) {
 		case Token_CmpEq: return x.value_bool == y.value_bool;
 		case Token_NotEq: return x.value_bool != y.value_bool;
 		}
 		break;
 
-	case Value_Integer: {
+	case ExactValue_Integer: {
 		i64 a = x.value_integer;
 		i64 b = y.value_integer;
 		switch (op.kind) {
@@ -333,7 +333,7 @@ b32 compare_values(Token op, Value x, Value y) {
 		}
 	} break;
 
-	case Value_Float: {
+	case ExactValue_Float: {
 		f64 a = x.value_float;
 		f64 b = y.value_float;
 		switch (op.kind) {
@@ -346,7 +346,7 @@ b32 compare_values(Token op, Value x, Value y) {
 		}
 	} break;
 
-	case Value_String: {
+	case ExactValue_String: {
 		String a = x.value_string;
 		String b = y.value_string;
 		isize len = gb_min(a.len, b.len);

+ 6 - 1
src/gb/gb.h

@@ -1631,7 +1631,8 @@ GB_STATIC_ASSERT(GB_ARRAY_GROW_FORMULA(0) > 0);
 	void **gb__array_ = cast(void **)&(x); \
 	gbArrayHeader *gb__ah = cast(gbArrayHeader *)gb_alloc(allocator_, gb_size_of(gbArrayHeader)+gb_size_of(*(x))*(cap)); \
 	gb__ah->allocator = allocator_; \
-	gb__ah->count = gb__ah->capacity = 0; \
+	gb__ah->count = 0; \
+	gb__ah->capacity = cap; \
 	*gb__array_ = cast(void *)(gb__ah+1); \
 } while (0)
 
@@ -8122,6 +8123,10 @@ gb_no_inline isize gb_snprintf_va(char *text, isize max_len, char const *fmt, va
 			info.flags |= (gbFmt_Lower|gbFmt_Unsigned|gbFmt_Alt|gbFmt_Intptr);
 			break;
 
+		case '%':
+			len = gb__print_char(text, remaining, &info, '%');
+			break;
+
 		default: fmt--; break;
 		}
 

+ 0 - 82
src/generator.cpp

@@ -1,82 +0,0 @@
-#include <llvm-c/Core.h>
-#include <llvm-c/BitWriter.h>
-
-struct Generator {
-	Checker *checker;
-	String output_path;
-
-#define MAX_GENERATOR_ERROR_COUNT 10
-	isize error_prev_line;
-	isize error_prev_column;
-	isize error_count;
-};
-
-#define print_generator_error(p, token, fmt, ...) print_generator_error_(p, __FUNCTION__, token, fmt, ##__VA_ARGS__)
-void print_generator_error_(Generator *g, char *function, Token token, char *fmt, ...) {
-
-	// NOTE(bill): Duplicate error, skip it
-	if (g->error_prev_line != token.line || g->error_prev_column != token.column) {
-		va_list va;
-
-		g->error_prev_line = token.line;
-		g->error_prev_column = token.column;
-
-	#if 0
-		gb_printf_err("%s()\n", function);
-	#endif
-		va_start(va, fmt);
-		gb_printf_err("%s(%td:%td) %s\n",
-		              g->checker->parser->tokenizer.fullpath, token.line, token.column,
-		              gb_bprintf_va(fmt, va));
-		va_end(va);
-
-	}
-	g->error_count++;
-}
-
-
-b32 init_generator(Generator *g, Checker *checker) {
-	if (checker->error_count > 0)
-		return false;
-	gb_zero_item(g);
-	g->checker = checker;
-
-	char *fullpath = checker->parser->tokenizer.fullpath;
-	char const *ext = gb_path_extension(fullpath);
-	isize len = ext-fullpath;
-	u8 *text = gb_alloc_array(gb_heap_allocator(), u8, len);
-	gb_memcopy(text, fullpath, len);
-	g->output_path = make_string(text, len);
-
-	return true;
-}
-
-void destroy_generator(Generator *g) {
-	if (g->error_count > 0) {
-
-	}
-
-	if (g->output_path.text)
-		gb_free(gb_heap_allocator(), g->output_path.text);
-}
-
-
-void emit_var_decl(Generator *g, String name, Type *type) {
-	// gb_printf("%.*s: %s;\n", LIT(name), type_to_string(type));
-}
-
-
-void generate_code(Generator *g, AstNode *file_node) {
-	// if (file_node->kind == AstNode_VariableDeclaration) {
-	// 	auto *vd = &file_node->variable_declaration;
-	// 	if (vd->kind == Declaration_Mutable) {
-	// 		for (AstNode *name_item = vd->name_list; name_item != NULL; name_item = name_item->next) {
-	// 			String name = name_item->identifier.token.string;
-	// 			Entity *entity = entity_of_identifier(g->checker, name_item);
-	// 			Type *type = entity->type;
-	// 			emit_var_decl(g, name, type);
-	// 		}
-	// 	}
-	// }
-
-}

+ 12 - 12
src/main.cpp

@@ -3,7 +3,7 @@
 #include "parser.cpp"
 #include "printer.cpp"
 #include "checker/checker.cpp"
-#include "generator.cpp"
+// #include "codegen/codegen.cpp"
 
 
 int main(int argc, char **argv) {
@@ -12,29 +12,29 @@ int main(int argc, char **argv) {
 		return 1;
 	}
 
-	init_global_scope();
+	init_universal_scope();
 
 	for (int arg_index = 1; arg_index < argc; arg_index++) {
 		char *arg = argv[arg_index];
-		char *filename = arg;
+		char *init_filename = arg;
 		Parser parser = {0};
 
-		if (init_parser(&parser, filename)) {
+		if (init_parser(&parser)) {
 			defer (destroy_parser(&parser));
-			AstNode *file_node = parse_statement_list(&parser, NULL);
-			// print_ast(file_node, 0);
+
+			parse_files(&parser, init_filename);
 
 			Checker checker = {};
 			init_checker(&checker, &parser);
 			defer (destroy_checker(&checker));
 
-			check_file(&checker, file_node);
+			check_parsed_files(&checker);
+#if 0
+			Codegen codegen = {};
+			if (init_codegen(&codegen, &checker)) {
+				defer (destroy_codegen(&codegen));
 
-#if 1
-			Generator generator = {};
-			if (init_generator(&generator, &checker)) {
-				defer (destroy_generator(&generator));
-				generate_code(&generator, file_node);
+				generate_code(&codegen, file_node);
 			}
 #endif
 		}

File diff suppressed because it is too large
+ 272 - 270
src/parser.cpp


+ 0 - 26
src/test.odin

@@ -1,26 +0,0 @@
-main :: proc() {
-	x := "Yep";
-
-	thing :: proc(n: int) -> (int, f32) {
-		return n*n, 13.37;
-	}
-
-	thang(thing(1), x);
-
-	v: Vec2;
-}
-
-thang :: proc(a: int, b: f32, s: string) {
-	a = 1;
-	b = 2;
-	s = "Hello";
-}
-
-z := y;
-y := x;
-x := 1;
-
-type Vec2: struct {
-	x, y: f32;
-}
-

+ 22 - 22
src/tokenizer.cpp

@@ -103,7 +103,6 @@ Token__OperatorEnd,
 Token__KeywordBegin,
 	Token_type,
 	Token_proc,
-
 	Token_match, // TODO(bill): switch vs match?
 	Token_break,
 	Token_continue,
@@ -275,7 +274,7 @@ gb_inline void print_token(Token t) { gb_printf("%.*s\n", LIT(t.string)); }
 
 typedef struct Tokenizer Tokenizer;
 struct Tokenizer {
-	char *fullpath;
+	String fullpath;
 	u8 *start;
 	u8 *end;
 
@@ -289,8 +288,8 @@ struct Tokenizer {
 };
 
 
-#define tokenizer_error(t, msg, ...) tokenizer_error_(t, __FUNCTION__, msg, ##__VA_ARGS__)
-void tokenizer_error_(Tokenizer *t, char *function, char *msg, ...) {
+#define tokenizer_err(t, msg, ...) tokenizer_err_(t, __FUNCTION__, msg, ##__VA_ARGS__)
+void tokenizer_err_(Tokenizer *t, char *function, char *msg, ...) {
 	va_list va;
 	isize column = t->read_curr - t->line+1;
 	if (column < 1)
@@ -322,13 +321,13 @@ void advance_to_next_rune(Tokenizer *t) {
 		}
 		rune = *t->read_curr;
 		if (rune == 0) {
-			tokenizer_error(t, "Illegal character NUL");
+			tokenizer_err(t, "Illegal character NUL");
 		} else if (rune >= 0x80) { // not ASCII
 			width = gb_utf8_decode(t->read_curr, t->end-t->read_curr, &rune);
 			if (rune == GB_RUNE_INVALID && width == 1)
-				tokenizer_error(t, "Illegal UTF-8 encoding");
+				tokenizer_err(t, "Illegal UTF-8 encoding");
 			else if (rune == GB_RUNE_BOM && t->curr-t->start > 0)
-				tokenizer_error(t, "Illegal byte order mark");
+				tokenizer_err(t, "Illegal byte order mark");
 		}
 		t->read_curr += width;
 		t->curr_rune = rune;
@@ -342,15 +341,20 @@ void advance_to_next_rune(Tokenizer *t) {
 	}
 }
 
-b32 init_tokenizer(Tokenizer *t, char *filename) {
-	gbFileContents fc = gb_file_read_contents(gb_heap_allocator(), true, filename);
+b32 init_tokenizer(Tokenizer *t, String fullpath) {
+	char *c_str = gb_alloc_array(gb_heap_allocator(), char, fullpath.len+1);
+	memcpy(c_str, fullpath.text, fullpath.len);
+	c_str[fullpath.len] = '\0';
+	defer (gb_free(gb_heap_allocator(), c_str));
+
+	gbFileContents fc = gb_file_read_contents(gb_heap_allocator(), true, c_str);
 	gb_zero_item(t);
 	if (fc.data) {
 		t->start = cast(u8 *)fc.data;
 		t->line = t->read_curr = t->curr = t->start;
 		t->end = t->start + fc.size;
 
-		t->fullpath = gb_path_get_full_name(gb_heap_allocator(), filename);
+		t->fullpath = fullpath;
 
 		t->line_count = 1;
 
@@ -527,9 +531,9 @@ b32 scan_escape(Tokenizer *t, Rune quote) {
 		len = 8; base = 16; max = GB_RUNE_MAX;
 	} else {
 		if (t->curr_rune < 0)
-			tokenizer_error(t, "Escape sequence was not terminated");
+			tokenizer_err(t, "Escape sequence was not terminated");
 		else
-			tokenizer_error(t, "Unknown escape sequence");
+			tokenizer_err(t, "Unknown escape sequence");
 		return false;
 	}
 
@@ -537,9 +541,9 @@ b32 scan_escape(Tokenizer *t, Rune quote) {
 		u32 d = cast(u32)digit_value(t->curr_rune);
 		if (d >= base) {
 			if (t->curr_rune < 0)
-				tokenizer_error(t, "Escape sequence was not terminated");
+				tokenizer_err(t, "Escape sequence was not terminated");
 			else
-				tokenizer_error(t, "Illegal character %d in escape sequence", t->curr_rune);
+				tokenizer_err(t, "Illegal character %d in escape sequence", t->curr_rune);
 			return false;
 		}
 
@@ -646,7 +650,7 @@ Token tokenizer_get_token(Tokenizer *t) {
 			for (;;) {
 				Rune r = t->curr_rune;
 				if (r == '\n' || r < 0) {
-					tokenizer_error(t, "String literal not terminated");
+					tokenizer_err(t, "String literal not terminated");
 					break;
 				}
 				advance_to_next_rune(t);
@@ -665,7 +669,7 @@ Token tokenizer_get_token(Tokenizer *t) {
 				Rune r = t->curr_rune;
 				if (r == '\n' || r < 0) {
 					if (valid)
-						tokenizer_error(t, "Rune literal not terminated");
+						tokenizer_err(t, "Rune literal not terminated");
 					break;
 				}
 				advance_to_next_rune(t);
@@ -679,7 +683,7 @@ Token tokenizer_get_token(Tokenizer *t) {
 			}
 
 			if (valid && len != 1)
-				tokenizer_error(t, "Illegal rune literal");
+				tokenizer_err(t, "Illegal rune literal");
 		} break;
 
 		case '.':
@@ -722,10 +726,8 @@ Token tokenizer_get_token(Tokenizer *t) {
 		case '&':
 			token.kind = Token_And;
 			if (t->curr_rune == '~') {
-				advance_to_next_rune(t);
 				token.kind = token_type_variant2(t, Token_AndNot, Token_AndNotEq);
 			} else {
-				advance_to_next_rune(t);
 				token.kind = token_type_variant3(t, Token_And, Token_AndEq, '&', Token_CmpAnd);
 				if (t->curr_rune == '=') {
 					token.kind = Token_CmpAndEq;
@@ -735,8 +737,6 @@ Token tokenizer_get_token(Tokenizer *t) {
 			break;
 
 		case '|':
-			token.kind = Token_Or;
-			advance_to_next_rune(t);
 			token.kind = token_type_variant3(t, Token_Or, Token_OrEq, '|', Token_CmpOr);
 			if (t->curr_rune == '=')  {
 				token.kind = Token_CmpOrEq;
@@ -746,7 +746,7 @@ Token tokenizer_get_token(Tokenizer *t) {
 
 		default:
 			if (curr_rune != GB_RUNE_BOM)
-				tokenizer_error(t, "Illegal character: %c (%d) ", cast(char)curr_rune, curr_rune);
+				tokenizer_err(t, "Illegal character: %c (%d) ", cast(char)curr_rune, curr_rune);
 			token.kind = Token_Invalid;
 			break;
 		}

+ 30 - 99
todo.md

@@ -1,100 +1,31 @@
-# Odin Language Features
-
-* variables
-* constants (compile-time)
-* procedures
-	- overloading
-	- polymorphic (poly prockets)
-	- multiple return values
-		- Optional forced checking
-	- inline and outline actually meant it!
-	- local scoped procedures
-		* Maybe closures & lambdas?
-	- named parameters
-	- optional parameters
-* struct
-* enum
-* raw union
-* tagged union or variants or both?
-* pointers
-* pointer arithmetic
-* defer statement
-* death to headers
-	- no pre-declaration
-* maybe both inline assembly and intrinsics
-* `using`
-* metaprogramming
-	- Compile execution
-	- Introspection
-	- Any type
-		* type_of?
-
-
-## Basic Types
-bool - true|false
-	 - register size or variable size?
-
-u8   - Unsigned integer
-u16
-u32
-u64
-uint - Register size unsigned integer
-uintptr - integer big enough to store a pointer
-
-i8  - Signed integer
-i16
-i32
-i64
-int - Register size signed integer
-intptr - integer big enough to store a pointer
-
-
-f32 - Floating Point 32 bit
-f64 - Floating Point 64 bit
-
-byte - alias for u8
-rune - alias for i32
-
-string   - Immutable: once created, it is impossible to change the contents of a string
-arrays   -    ArrayType = [count]ElementType
-                  count = Expression
-            ElementType = Type
-	Allow for dynamic arrays? Allow use slices?
-pointers - PointerType = *BaseType
-              BaseType = Type
-
-struct
-enum
-raw_union
-tagged_union
-procedure
-
-
-
-
-
-
-## Basic program
-
-import "io"
-
-type Vec2: struct {
-	x, y: f32;
-}
-
-test_proc :: (x, y: f32) -> f32 {
-	result := x * y;
-	result += 2;
-	result /= x;
-	return result;
-}
-
-main :: () {
-	x : i32 = 123;
-	y := 1337;  // Type inference (will be `int`)
-	z :: x + y; // Defined and made constant
-
-	io.print("Hellope, World! z = {}", z);
-}
-
+# Todo
+
+## Tokenizer
+* Unicode character category check - Letters, Digits
+* Extra operators
+	- << and <<=
+	- >> and >>=
+
+## Parser
+* Extra checking here rather than in the checker
+* Mulitple files
+
+## Checker
+* Cyclic Type Checking
+	- type A: struct { b: B; }; type B: struct { a: A; };
+	- ^ Should be illegal as it's a cyclic definition
+* Big numbers library
+	- integer
+	- rational
+	- real
+* Multiple files
+
+## Codegen
+* Begin!!!
+* Emit LLVM-IR using custom library
+* Debug info
+
+## Command Line Tool
+* Begin!!!
+* Choose/determine architecture
 

Some files were not shown because too many files changed in this diff