diff --git a/build.bat b/build.bat index c5e38d20c..8feef3028 100644 --- a/build.bat +++ b/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 diff --git a/examples/other.odin b/examples/other.odin new file mode 100644 index 000000000..cdea3c675 --- /dev/null +++ b/examples/other.odin @@ -0,0 +1,3 @@ +add :: proc(a, b: int) -> int { + return a + b; +} diff --git a/examples/test.odin b/examples/test.odin new file mode 100644 index 000000000..c4c966d69 --- /dev/null +++ b/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); +} diff --git a/run.bat b/run.bat new file mode 100644 index 000000000..7868aeaa4 --- /dev/null +++ b/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 + diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 44ec1d6a5..b97764584 100644 --- a/src/checker/checker.cpp +++ b/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 untyped; // Key: AstNode * | Expression -> ExpressionInfo Map 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) { +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; -// 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; - switch (decl->kind) { - case AstNode_BadDeclaration: - break; + case AstNode_VariableDeclaration: { + auto *vd = &decl->variable_declaration; - 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); + } - 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) { + 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; + } + + 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; + } + + add_file_entity(c, name, e, d); + + if (value != NULL) + value = value->next; + } + } break; } - 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; - } - - add_file_entity(c, name, e, d); - - if (value != NULL) - value = value->next; - } - -#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; - } - } 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]; - } - - 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; - } - e->variable.visited = true; - - if (e->type == NULL) - e->type = init_type; - } - - - check_init_variables(c, entities, entity_count, vd->value_list, vd->value_list_count, make_string("variable declaration")); -#endif + 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; + + 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); + + } break; + + case AstNode_ImportDeclaration: + // NOTE(bill): ignore + break; + + default: + checker_err(c, ast_node_token(decl), "Only declarations are allowed at file scope"); + 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->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; - - default: - print_checker_error(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); + } + } } diff --git a/src/checker/entity.cpp b/src/checker/entity.cpp index d90d08cfd..aed4751ef 100644 --- a/src/checker/entity.cpp +++ b/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; diff --git a/src/checker/expression.cpp b/src/checker/expression.cpp index a96ae74d6..dbcfe3d10 100644 --- a/src/checker/expression.cpp +++ b/src/checker/expression.cpp @@ -17,7 +17,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) { GB_ASSERT(struct_type->kind == Type_Structure); auto *st = &node->struct_type; if (st->field_count == 0) { - print_checker_error(c, ast_node_token(node), "Empty struct{} definition"); + checker_err(c, ast_node_token(node), "Empty struct{} definition"); return; } @@ -45,7 +45,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) { u64 key = hash_string(name_token.string); if (map_get(&entity_map, key)) { // TODO(bill): Scope checking already checks the declaration - print_checker_error(c, name_token, "`%.*s` is already declared in this structure", LIT(name_token.string)); + checker_err(c, name_token, "`%.*s` is already declared in this structure", LIT(name_token.string)); } else { map_set(&entity_map, key, e); fields[field_index++] = e; @@ -76,7 +76,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *field_list, isize fiel add_entity(c, scope, name, param); variables[variable_index++] = param; } else { - print_checker_error(c, ast_node_token(name), + checker_err(c, ast_node_token(name), "Invalid parameter (invalid AST)"); } } @@ -106,7 +106,7 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *list, isize list_coun if (get_base_type(type)->kind == Type_Array) { // TODO(bill): Should I allow array's to returned? - print_checker_error(c, token, "You cannot return an array from a procedure"); + checker_err(c, token, "You cannot return an array from a procedure"); } } tuple->tuple.variables = variables; @@ -133,15 +133,15 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { } -void check_identifier(Checker *c, Operand *operand, AstNode *n, Type *named_type) { +void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) { GB_ASSERT(n->kind == AstNode_Identifier); - operand->mode = Addressing_Invalid; - operand->expression = n; + o->mode = Addressing_Invalid; + o->expression = n; Entity *e = NULL; scope_lookup_parent_entity(c->curr_scope, n->identifier.token.string, NULL, &e); if (e == NULL) { - print_checker_error(c, n->identifier.token, - "Undeclared type or identifier `%.*s`", LIT(n->identifier.token.string)); + checker_err(c, n->identifier.token, + "Undeclared type or identifier `%.*s`", LIT(n->identifier.token.string)); return; } add_entity_use(c, n, e); @@ -158,9 +158,9 @@ void check_identifier(Checker *c, Operand *operand, AstNode *n, Type *named_type add_declaration_dependency(c, e); if (e->type == &basic_types[Basic_Invalid]) return; - operand->value = e->constant.value; - GB_ASSERT(operand->value.kind != Value_Invalid); - operand->mode = Addressing_Constant; + o->value = e->constant.value; + GB_ASSERT(o->value.kind != ExactValue_Invalid); + o->mode = Addressing_Constant; break; case Entity_Variable: @@ -168,21 +168,21 @@ void check_identifier(Checker *c, Operand *operand, AstNode *n, Type *named_type e->variable.used = true; if (e->type == &basic_types[Basic_Invalid]) return; - operand->mode = Addressing_Variable; + o->mode = Addressing_Variable; break; case Entity_TypeName: - operand->mode = Addressing_Type; + o->mode = Addressing_Type; break; case Entity_Procedure: add_declaration_dependency(c, e); - operand->mode = Addressing_Value; + o->mode = Addressing_Value; break; case Entity_Builtin: - operand->builtin_id = e->builtin.id; - operand->mode = Addressing_Builtin; + o->builtin_id = e->builtin.id; + o->mode = Addressing_Builtin; break; default: @@ -190,45 +190,45 @@ void check_identifier(Checker *c, Operand *operand, AstNode *n, Type *named_type break; } - operand->type = e->type; + o->type = e->type; } -i64 check_array_count(Checker *c, AstNode *expression) { - if (expression) { - Operand operand = {}; - check_expression(c, &operand, expression); - if (operand.mode != Addressing_Constant) { - if (operand.mode != Addressing_Invalid) { - print_checker_error(c, ast_node_token(expression), "Array count must be a constant"); +i64 check_array_count(Checker *c, AstNode *e) { + if (e) { + Operand o = {}; + check_expression(c, &o, e); + if (o.mode != Addressing_Constant) { + if (o.mode != Addressing_Invalid) { + checker_err(c, ast_node_token(e), "Array count must be a constant"); } return 0; } - if (is_type_untyped(operand.type) || is_type_integer(operand.type)) { - if (operand.value.kind == Value_Integer) { - i64 count = operand.value.value_integer; + if (is_type_untyped(o.type) || is_type_integer(o.type)) { + if (o.value.kind == ExactValue_Integer) { + i64 count = o.value.value_integer; if (count >= 0) return count; - print_checker_error(c, ast_node_token(expression), "Invalid array count"); + checker_err(c, ast_node_token(e), "Invalid array count"); return 0; } } - print_checker_error(c, ast_node_token(expression), "Array count must be an integer"); + checker_err(c, ast_node_token(e), "Array count must be an integer"); } return 0; } -Type *check_type_expression_extra(Checker *c, AstNode *expression, Type *named_type) { +Type *check_type_expression_extra(Checker *c, AstNode *e, Type *named_type) { gbString err_str = NULL; defer (gb_string_free(err_str)); - switch (expression->kind) { + switch (e->kind) { case AstNode_Identifier: { - Operand operand = {}; - check_identifier(c, &operand, expression, named_type); - switch (operand.mode) { + Operand o = {}; + check_identifier(c, &o, e, named_type); + switch (o.mode) { case Addressing_Type: { - Type *t = operand.type; + Type *t = o.type; set_base_type(named_type, t); return t; } break; @@ -237,28 +237,28 @@ Type *check_type_expression_extra(Checker *c, AstNode *expression, Type *named_t break; case Addressing_NoValue: - err_str = expression_to_string(expression); - print_checker_error(c, ast_node_token(expression), "`%s` used as a type", err_str); + err_str = expression_to_string(e); + checker_err(c, ast_node_token(e), "`%s` used as a type", err_str); break; default: - err_str = expression_to_string(expression); - print_checker_error(c, ast_node_token(expression), "`%s` used as a type when not a type", err_str); + err_str = expression_to_string(e); + checker_err(c, ast_node_token(e), "`%s` used as a type when not a type", err_str); break; } } break; case AstNode_ParenExpression: - return check_type(c, expression->paren_expression.expression, named_type); + return check_type(c, e->paren_expression.expression, named_type); case AstNode_ArrayType: - if (expression->array_type.count != NULL) { + if (e->array_type.count != NULL) { Type *t = make_type_array(c->allocator, - check_type(c, expression->array_type.element), - check_array_count(c, expression->array_type.count)); + check_type(c, e->array_type.element), + check_array_count(c, e->array_type.count)); set_base_type(named_type, t); return t; } else { - Type *t = make_type_slice(c->allocator, check_type(c, expression->array_type.element)); + Type *t = make_type_slice(c->allocator, check_type(c, e->array_type.element)); set_base_type(named_type, t); return t; } @@ -267,12 +267,12 @@ Type *check_type_expression_extra(Checker *c, AstNode *expression, Type *named_t case AstNode_StructType: { Type *t = make_type_structure(c->allocator); set_base_type(named_type, t); - check_struct_type(c, t, expression); + check_struct_type(c, t, e); return t; } break; case AstNode_PointerType: { - Type *t = make_type_pointer(c->allocator, check_type(c, expression->pointer_type.type_expression)); + Type *t = make_type_pointer(c->allocator, check_type(c, e->pointer_type.type_expression)); set_base_type(named_type, t); return t; } break; @@ -280,15 +280,15 @@ Type *check_type_expression_extra(Checker *c, AstNode *expression, Type *named_t case AstNode_ProcedureType: { Type *t = alloc_type(c->allocator, Type_Procedure); set_base_type(named_type, t); - check_open_scope(c, expression); - check_procedure_type(c, t, expression); + check_open_scope(c, e); + check_procedure_type(c, t, e); check_close_scope(c); return t; } break; default: - err_str = expression_to_string(expression); - print_checker_error(c, ast_node_token(expression), "`%s` is not a type", err_str); + err_str = expression_to_string(e); + checker_err(c, ast_node_token(e), "`%s` is not a type", err_str); break; } @@ -298,16 +298,16 @@ Type *check_type_expression_extra(Checker *c, AstNode *expression, Type *named_t } -Type *check_type(Checker *c, AstNode *expression, Type *named_type) { - Value null_value = {Value_Invalid}; +Type *check_type(Checker *c, AstNode *e, Type *named_type) { + ExactValue null_value = {ExactValue_Invalid}; Type *type = NULL; gbString err_str = NULL; defer (gb_string_free(err_str)); - switch (expression->kind) { + switch (e->kind) { case AstNode_Identifier: { Operand operand = {}; - check_identifier(c, &operand, expression, named_type); + check_identifier(c, &operand, e, named_type); switch (operand.mode) { case Addressing_Type: { type = operand.type; @@ -319,37 +319,37 @@ Type *check_type(Checker *c, AstNode *expression, Type *named_type) { break; case Addressing_NoValue: - err_str = expression_to_string(expression); - print_checker_error(c, ast_node_token(expression), "`%s` used as a type", err_str); + err_str = expression_to_string(e); + checker_err(c, ast_node_token(e), "`%s` used as a type", err_str); break; default: - err_str = expression_to_string(expression); - print_checker_error(c, ast_node_token(expression), "`%s` used as a type when not a type", err_str); + err_str = expression_to_string(e); + checker_err(c, ast_node_token(e), "`%s` used as a type when not a type", err_str); break; } } break; case AstNode_SelectorExpression: { - Operand operand = {}; - check_selector(c, &operand, expression); + Operand o = {}; + check_selector(c, &o, e); - if (operand.mode == Addressing_Type) { - set_base_type(type, operand.type); - return operand.type; + if (o.mode == Addressing_Type) { + set_base_type(type, o.type); + return o.type; } } break; case AstNode_ParenExpression: - return check_type(c, expression->paren_expression.expression, named_type); + return check_type(c, e->paren_expression.expression, named_type); case AstNode_ArrayType: { - if (expression->array_type.count != NULL) { + if (e->array_type.count != NULL) { type = make_type_array(c->allocator, - check_type(c, expression->array_type.element), - check_array_count(c, expression->array_type.count)); + check_type(c, e->array_type.element), + check_array_count(c, e->array_type.count)); set_base_type(named_type, type); } else { - type = make_type_slice(c->allocator, check_type(c, expression->array_type.element)); + type = make_type_slice(c->allocator, check_type(c, e->array_type.element)); set_base_type(named_type, type); } goto end; @@ -358,12 +358,12 @@ Type *check_type(Checker *c, AstNode *expression, Type *named_type) { case AstNode_StructType: { type = make_type_structure(c->allocator); set_base_type(named_type, type); - check_struct_type(c, type, expression); + check_struct_type(c, type, e); goto end; } break; case AstNode_PointerType: { - type = make_type_pointer(c->allocator, check_type(c, expression->pointer_type.type_expression)); + type = make_type_pointer(c->allocator, check_type(c, e->pointer_type.type_expression)); set_base_type(named_type, type); goto end; } break; @@ -371,13 +371,13 @@ Type *check_type(Checker *c, AstNode *expression, Type *named_type) { case AstNode_ProcedureType: { type = alloc_type(c->allocator, Type_Procedure); set_base_type(named_type, type); - check_procedure_type(c, type, expression); + check_procedure_type(c, type, e); goto end; } break; default: - err_str = expression_to_string(expression); - print_checker_error(c, ast_node_token(expression), "`%s` is not a type", err_str); + err_str = expression_to_string(e); + checker_err(c, ast_node_token(e), "`%s` is not a type", err_str); break; } @@ -386,113 +386,117 @@ Type *check_type(Checker *c, AstNode *expression, Type *named_type) { end: GB_ASSERT(is_type_typed(type)); - add_type_and_value(c, expression, Addressing_Type, type, null_value); + add_type_and_value(c, e, Addressing_Type, type, null_value); return type; } -b32 check_unary_op(Checker *c, Operand *operand, Token op) { +b32 check_unary_op(Checker *c, Operand *o, Token op) { // TODO(bill): Handle errors correctly gbString str = NULL; defer (gb_string_free(str)); switch (op.kind) { case Token_Add: case Token_Sub: - if (!is_type_numeric(operand->type)) { - str = expression_to_string(operand->expression); - print_checker_error(c, op, "Operator `%.*s` is not allowed with `%s`", LIT(op.string), str); + if (!is_type_numeric(o->type)) { + str = expression_to_string(o->expression); + checker_err(c, op, "Operator `%.*s` is not allowed with `%s`", LIT(op.string), str); } break; case Token_Xor: - if (!is_type_integer(operand->type)) { - print_checker_error(c, op, "Operator `%.*s` is only allowed with integers", LIT(op.string)); + if (!is_type_integer(o->type)) { + checker_err(c, op, "Operator `%.*s` is only allowed with integers", LIT(op.string)); } break; case Token_Not: - if (!is_type_boolean(operand->type)) { - str = expression_to_string(operand->expression); - print_checker_error(c, op, "Operator `%.*s` is only allowed on boolean expression", LIT(op.string)); + if (!is_type_boolean(o->type)) { + str = expression_to_string(o->expression); + checker_err(c, op, "Operator `%.*s` is only allowed on boolean expression", LIT(op.string)); } break; default: - print_checker_error(c, op, "Unknown operator `%.*s`", LIT(op.string)); + checker_err(c, op, "Unknown operator `%.*s`", LIT(op.string)); return false; } return true; } -b32 check_binary_op(Checker *c, Operand *operand, Token op) { +b32 check_binary_op(Checker *c, Operand *o, Token op) { // TODO(bill): Handle errors correctly switch (op.kind) { case Token_Add: case Token_Sub: case Token_Mul: case Token_Quo: - if (!is_type_numeric(operand->type)) { - print_checker_error(c, op, "Operator `%.*s` is only allowed with numeric expressions", LIT(op.string)); - } - break; - - case Token_Mod: - case Token_Or: - case Token_Xor: - case Token_AndNot: - if (!is_type_integer(operand->type)) { - print_checker_error(c, op, "Operand `%.*s` is only allowed with integers", LIT(op.string)); - } - break; - - case Token_CmpAnd: - case Token_CmpOr: - if (!is_type_boolean(operand->type)) { - print_checker_error(c, op, "Operator `%.*s` is only allowed with boolean expressions", LIT(op.string)); - } - break; case Token_AddEq: case Token_SubEq: case Token_MulEq: case Token_QuoEq: + if (!is_type_numeric(o->type)) { + checker_err(c, op, "Operator `%.*s` is only allowed with numeric expressions", LIT(op.string)); + return false; + } + break; + + case Token_Mod: + case Token_And: + case Token_Or: + case Token_Xor: + case Token_AndNot: + case Token_ModEq: case Token_AndEq: case Token_OrEq: case Token_XorEq: case Token_AndNotEq: + if (!is_type_integer(o->type)) { + checker_err(c, op, "Operator `%.*s` is only allowed with integers", LIT(op.string)); + return false; + } + break; + + case Token_CmpAnd: + case Token_CmpOr: + case Token_CmpAndEq: case Token_CmpOrEq: - // TODO(bill): is this okay? - return true; - + if (!is_type_boolean(o->type)) { + checker_err(c, op, "Operator `%.*s` is only allowed with boolean expressions", LIT(op.string)); + return false; + } + break; default: - print_checker_error(c, op, "Unknown operator `%.*s`", LIT(op.string)); + checker_err(c, op, "Unknown operator `%.*s`", LIT(op.string)); return false; } return true; } -b32 check_value_is_expressible(Checker *c, Value in_value, Type *type, Value *out_value) { - if (in_value.kind == Value_Invalid) +b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value) { + if (in_value.kind == ExactValue_Invalid) return true; if (is_type_boolean(type)) { - return in_value.kind == Value_Bool; + return in_value.kind == ExactValue_Bool; } else if (is_type_string(type)) { - return in_value.kind == Value_String; + return in_value.kind == ExactValue_String; } else if (is_type_integer(type)) { - if (in_value.kind != Value_Integer) + if (in_value.kind != ExactValue_Integer) return false; if (out_value) *out_value = in_value; i64 i = in_value.value_integer; i64 s = 8*type_size_of(c->sizes, c->allocator, type); u64 umax = ~0ull; - if (s < 64) + if (s < 64) { umax = (1ull << s) - 1ull; + } i64 imax = (1ll << (s-1ll)); @@ -517,8 +521,8 @@ b32 check_value_is_expressible(Checker *c, Value in_value, Type *type, Value *ou default: GB_PANIC("Compiler error: Unknown integer type!"); break; } } else if (is_type_float(type)) { - Value v = value_to_float(in_value); - if (v.kind != Value_Float) + ExactValue v = exact_value_to_float(in_value); + if (v.kind != ExactValue_Float) return false; switch (type->basic.kind) { @@ -534,9 +538,9 @@ b32 check_value_is_expressible(Checker *c, Value in_value, Type *type, Value *ou return true; } } else if (is_type_pointer(type)) { - if (in_value.kind == Value_Pointer) + if (in_value.kind == ExactValue_Pointer) return true; - if (in_value.kind == Value_Integer) + if (in_value.kind == ExactValue_Integer) return true; if (out_value) *out_value = in_value; } @@ -544,65 +548,65 @@ b32 check_value_is_expressible(Checker *c, Value in_value, Type *type, Value *ou return false; } -void check_is_expressible(Checker *c, Operand *operand, Type *type) { +void check_is_expressible(Checker *c, Operand *o, Type *type) { GB_ASSERT(type->kind == Type_Basic); - GB_ASSERT(operand->mode == Addressing_Constant); - if (!check_value_is_expressible(c, operand->value, type, &operand->value)) { - gbString a = type_to_string(operand->type); + GB_ASSERT(o->mode == Addressing_Constant); + if (!check_value_is_expressible(c, o->value, type, &o->value)) { + gbString a = type_to_string(o->type); gbString b = type_to_string(type); defer (gb_string_free(a)); defer (gb_string_free(b)); - if (is_type_numeric(operand->type) && is_type_numeric(type)) { - if (!is_type_integer(operand->type) && is_type_integer(type)) { - print_checker_error(c, ast_node_token(operand->expression), "`%s` truncated to `%s`", a, b); + if (is_type_numeric(o->type) && is_type_numeric(type)) { + if (!is_type_integer(o->type) && is_type_integer(type)) { + checker_err(c, ast_node_token(o->expression), "`%s` truncated to `%s`", a, b); } else { - print_checker_error(c, ast_node_token(operand->expression), "`%s` overflows to `%s`", a, b); + checker_err(c, ast_node_token(o->expression), "`%s` overflows to `%s`", a, b); } } else { - print_checker_error(c, ast_node_token(operand->expression), "Cannot convert `%s` to `%s`", a, b); + checker_err(c, ast_node_token(o->expression), "Cannot convert `%s` to `%s`", a, b); } - operand->mode = Addressing_Invalid; + o->mode = Addressing_Invalid; } } -void check_unary_expression(Checker *c, Operand *operand, Token op, AstNode *node) { +void check_unary_expression(Checker *c, Operand *o, Token op, AstNode *node) { if (op.kind == Token_Pointer) { // Pointer address - if (operand->mode != Addressing_Variable) { + if (o->mode != Addressing_Variable) { gbString str = expression_to_string(node->unary_expression.operand); defer (gb_string_free(str)); - print_checker_error(c, op, "Cannot take the pointer address of `%s`", str); - operand->mode = Addressing_Invalid; + checker_err(c, op, "Cannot take the pointer address of `%s`", str); + o->mode = Addressing_Invalid; return; } - operand->mode = Addressing_Value; - operand->type = make_type_pointer(c->allocator, operand->type); + o->mode = Addressing_Value; + o->type = make_type_pointer(c->allocator, o->type); return; } - if (!check_unary_op(c, operand, op)) { - operand->mode = Addressing_Invalid; + if (!check_unary_op(c, o, op)) { + o->mode = Addressing_Invalid; return; } - if (operand->mode == Addressing_Constant) { - Type *type = get_base_type(operand->type); + if (o->mode == Addressing_Constant) { + Type *type = get_base_type(o->type); GB_ASSERT(type->kind == Type_Basic); i32 precision = 0; if (is_type_unsigned(type)) precision = cast(i32)(8 * type_size_of(c->sizes, c->allocator, type)); - operand->value = unary_operator_value(op, operand->value, precision); + o->value = exact_unary_operator_value(op, o->value, precision); if (is_type_typed(type)) { if (node != NULL) - operand->expression = node; - check_is_expressible(c, operand, type); + o->expression = node; + check_is_expressible(c, o, type); } return; } - operand->mode = Addressing_Value; + o->mode = Addressing_Value; } void check_comparison(Checker *c, Operand *x, Operand *y, Token op) { @@ -641,13 +645,13 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) { } if (err_str) { - print_checker_error(c, op, "Cannot compare expression, %s", err_str); + checker_err(c, op, "Cannot compare expression, %s", err_str); return; } if (x->mode == Addressing_Constant && y->mode == Addressing_Constant) { - x->value = make_value_bool(compare_values(op, x->value, y->value)); + x->value = make_exact_value_bool(compare_exact_values(op, x->value, y->value)); } else { // TODO(bill): What should I do? } @@ -657,42 +661,42 @@ void check_comparison(Checker *c, Operand *x, Operand *y, Token op) { void check_binary_expression(Checker *c, Operand *x, AstNode *node) { GB_ASSERT(node->kind == AstNode_BinaryExpression); - Operand y = {}; + Operand y_ = {}, *y = &y_; gbString err_str = NULL; defer (gb_string_free(err_str)); check_expression(c, x, node->binary_expression.left); - check_expression(c, &y, node->binary_expression.right); + check_expression(c, y, node->binary_expression.right); if (x->mode == Addressing_Invalid) return; - if (y.mode == Addressing_Invalid) { + if (y->mode == Addressing_Invalid) { x->mode = Addressing_Invalid; - x->expression = y.expression; + x->expression = y->expression; return; } - convert_to_typed(c, x, y.type); + convert_to_typed(c, x, y->type); if (x->mode == Addressing_Invalid) return; - convert_to_typed(c, &y, x->type); - if (y.mode == Addressing_Invalid) { + convert_to_typed(c, y, x->type); + if (y->mode == Addressing_Invalid) { x->mode = Addressing_Invalid; return; } Token op = node->binary_expression.op; if (token_is_comparison(op)) { - check_comparison(c, x, &y, op); + check_comparison(c, x, y, op); return; } - if (!are_types_identical(x->type, y.type)) { + if (!are_types_identical(x->type, y->type)) { if (x->type != &basic_types[Basic_Invalid] && - y.type != &basic_types[Basic_Invalid]) { + y->type != &basic_types[Basic_Invalid]) { gbString xt = type_to_string(x->type); - gbString yt = type_to_string(y.type); + gbString yt = type_to_string(y->type); defer (gb_string_free(xt)); defer (gb_string_free(yt)); err_str = expression_to_string(x->expression); - print_checker_error(c, op, "Mismatched types in binary expression `%s` : `%s` vs `%s`", err_str, xt, yt); + checker_err(c, op, "Mismatched types in binary expression `%s` : `%s` vs `%s`", err_str, xt, yt); } x->mode = Addressing_Invalid; return; @@ -703,40 +707,44 @@ void check_binary_expression(Checker *c, Operand *x, AstNode *node) { return; } - if ((op.kind == Token_Quo || op.kind == Token_Mod) && - (x->mode == Addressing_Constant || is_type_integer(x->type)) && - y.mode == Addressing_Constant) { - b32 fail = false; - switch (y.value.kind) { - case Value_Integer: - if (y.value.value_integer == 0) - fail = true; - break; - case Value_Float: - if (y.value.value_float == 0.0) - fail = true; - break; - } + switch (op.kind) { + case Token_Quo: + case Token_Mod: + case Token_QuoEq: + case Token_ModEq: + if ((x->mode == Addressing_Constant || is_type_integer(x->type)) && + y->mode == Addressing_Constant) { + b32 fail = false; + switch (y->value.kind) { + case ExactValue_Integer: + if (y->value.value_integer == 0) + fail = true; + break; + case ExactValue_Float: + if (y->value.value_float == 0.0) + fail = true; + break; + } - if (fail) { - print_checker_error(c, ast_node_token(y.expression), - "Division by zero not allowed"); - x->mode = Addressing_Invalid; - return; + if (fail) { + checker_err(c, ast_node_token(y->expression), "Division by zero not allowed"); + x->mode = Addressing_Invalid; + return; + } } } if (x->mode == Addressing_Constant && - y.mode == Addressing_Constant) { - Value a = x->value; - Value b = y.value; + y->mode == Addressing_Constant) { + ExactValue a = x->value; + ExactValue b = y->value; Type *type = get_base_type(x->type); GB_ASSERT(type->kind == Type_Basic); if (op.kind == Token_Quo && is_type_integer(type)) { op.kind = Token_QuoEq; // NOTE(bill): Hack to get division of integers } - x->value = binary_operator_value(op, a, b); + x->value = exact_binary_operator_value(op, a, b); if (is_type_typed(type)) { if (node != NULL) x->expression = node; @@ -749,36 +757,36 @@ void check_binary_expression(Checker *c, Operand *x, AstNode *node) { } -void update_expression_type(Checker *c, AstNode *expression, Type *type, b32 final) { - ExpressionInfo *found = map_get(&c->untyped, hash_pointer(expression)); +void update_expression_type(Checker *c, AstNode *e, Type *type) { + ExpressionInfo *found = map_get(&c->untyped, hash_pointer(e)); if (!found) return; - switch (expression->kind) { + switch (e->kind) { case AstNode_UnaryExpression: - if (found->value.kind != Value_Invalid) + if (found->value.kind != ExactValue_Invalid) break; - update_expression_type(c, expression->unary_expression.operand, type, final); + update_expression_type(c, e->unary_expression.operand, type); break; case AstNode_BinaryExpression: - if (found->value.kind != Value_Invalid) + if (found->value.kind != ExactValue_Invalid) break; - if (!token_is_comparison(expression->binary_expression.op)) { - update_expression_type(c, expression->binary_expression.left, type, final); - update_expression_type(c, expression->binary_expression.right, type, final); + if (!token_is_comparison(e->binary_expression.op)) { + update_expression_type(c, e->binary_expression.left, type); + update_expression_type(c, e->binary_expression.right, type); } } - if (!final && is_type_untyped(type)) { + if (is_type_untyped(type)) { found->type = get_base_type(type); } else { found->type = type; } } -void update_expression_value(Checker *c, AstNode *expression, Value value) { - ExpressionInfo *found = map_get(&c->untyped, hash_pointer(expression)); +void update_expression_value(Checker *c, AstNode *e, ExactValue value) { + ExpressionInfo *found = map_get(&c->untyped, hash_pointer(e)); if (found) found->value = value; } @@ -796,7 +804,7 @@ void convert_untyped_error(Checker *c, Operand *operand, Type *target_type) { extra_text = " - Did you want `null`?"; } } - print_checker_error(c, ast_node_token(operand->expression), "Cannot convert `%s` to `%s`%s", expr_str, type_str, extra_text); + checker_err(c, ast_node_token(operand->expression), "Cannot convert `%s` to `%s`%s", expr_str, type_str, extra_text); operand->mode = Addressing_Invalid; } @@ -815,7 +823,7 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type) { if (is_type_numeric(x) && is_type_numeric(y)) { if (x < y) { operand->type = target_type; - update_expression_type(c, operand->expression, target_type, false); + update_expression_type(c, operand->expression, target_type); } } else if (x != y) { convert_untyped_error(c, operand, target_type); @@ -887,8 +895,8 @@ b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *valu if (!is_type_integer(operand.type)) { gbString expr_str = expression_to_string(operand.expression); - print_checker_error(c, ast_node_token(operand.expression), - "Index `%s` must be an integer", expr_str); + checker_err(c, ast_node_token(operand.expression), + "Index `%s` must be an integer", expr_str); gb_string_free(expr_str); if (value) *value = 0; return false; @@ -896,11 +904,11 @@ b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *valu if (operand.mode == Addressing_Constant) { if (max_count >= 0) { // NOTE(bill): Do array bound checking - i64 i = value_to_integer(operand.value).value_integer; + i64 i = exact_value_to_integer(operand.value).value_integer; if (i < 0) { gbString expr_str = expression_to_string(operand.expression); - print_checker_error(c, ast_node_token(operand.expression), - "Index `%s` cannot be a negative value", expr_str); + checker_err(c, ast_node_token(operand.expression), + "Index `%s` cannot be a negative value", expr_str); gb_string_free(expr_str); if (value) *value = 0; return false; @@ -910,8 +918,8 @@ b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *valu if (i >= max_count) { gbString expr_str = expression_to_string(operand.expression); - print_checker_error(c, ast_node_token(operand.expression), - "Index `%s` is out of bounds range [0, %lld)", expr_str, max_count); + checker_err(c, ast_node_token(operand.expression), + "Index `%s` is out of bounds range [0, %lld)", expr_str, max_count); gb_string_free(expr_str); return false; } @@ -964,8 +972,7 @@ void check_selector(Checker *c, Operand *operand, AstNode *node) { gbString sel_str = expression_to_string(selector); defer (gb_string_free(op_str)); defer (gb_string_free(sel_str)); - print_checker_error(c, ast_node_token(op_expr), "`%s` has no field `%s`", - op_str, sel_str); + checker_err(c, ast_node_token(op_expr), "`%s` has no field `%s`", op_str, sel_str); operand->mode = Addressing_Invalid; operand->expression = node; return; @@ -994,9 +1001,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (ce->arg_list_count > bp->arg_count && !bp->variadic) err = "Too many"; if (err) { - print_checker_error(c, ce->close, "`%s` arguments for `%.*s`, expected %td, got %td", - err, LIT(call->call_expression.proc->identifier.token.string), - bp->arg_count, ce->arg_list_count); + checker_err(c, ce->close, "`%s` arguments for `%.*s`, expected %td, got %td", + err, LIT(call->call_expression.proc->identifier.token.string), + bp->arg_count, ce->arg_list_count); return false; } } @@ -1016,12 +1023,12 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) // size_of :: proc(Type) Type *type = check_type(c, ce->arg_list); if (!type) { - print_checker_error(c, ast_node_token(ce->arg_list), "Expected a type for `size_of`"); + checker_err(c, ast_node_token(ce->arg_list), "Expected a type for `size_of`"); return false; } operand->mode = Addressing_Constant; - operand->value = make_value_integer(type_size_of(c->sizes, c->allocator, type)); + operand->value = make_exact_value_integer(type_size_of(c->sizes, c->allocator, type)); operand->type = &basic_types[Basic_int]; } break; @@ -1033,7 +1040,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) return false; operand->mode = Addressing_Constant; - operand->value = make_value_integer(type_size_of(c->sizes, c->allocator, operand->type)); + operand->value = make_exact_value_integer(type_size_of(c->sizes, c->allocator, operand->type)); operand->type = &basic_types[Basic_int]; break; @@ -1041,11 +1048,11 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) // align_of :: proc(Type) Type *type = check_type(c, ce->arg_list); if (!type) { - print_checker_error(c, ast_node_token(ce->arg_list), "Expected a type for `align_of`"); + checker_err(c, ast_node_token(ce->arg_list), "Expected a type for `align_of`"); return false; } operand->mode = Addressing_Constant; - operand->value = make_value_integer(type_align_of(c->sizes, c->allocator, type)); + operand->value = make_exact_value_integer(type_align_of(c->sizes, c->allocator, type)); operand->type = &basic_types[Basic_int]; } break; @@ -1056,7 +1063,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) return false; operand->mode = Addressing_Constant; - operand->value = make_value_integer(type_align_of(c->sizes, c->allocator, operand->type)); + operand->value = make_exact_value_integer(type_align_of(c->sizes, c->allocator, operand->type)); operand->type = &basic_types[Basic_int]; break; @@ -1066,12 +1073,12 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) AstNode *field_arg = unparen_expression(ce->arg_list->next); if (type) { if (type->kind != Type_Structure) { - print_checker_error(c, ast_node_token(ce->arg_list), "Expected a structure type for `offset_of`"); + checker_err(c, ast_node_token(ce->arg_list), "Expected a structure type for `offset_of`"); return false; } if (field_arg == NULL || field_arg->kind != AstNode_Identifier) { - print_checker_error(c, ast_node_token(field_arg), "Expected an identifier for field argument"); + checker_err(c, ast_node_token(field_arg), "Expected an identifier for field argument"); return false; } } @@ -1080,13 +1087,13 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) Entity *entity = lookup_field(type, field_arg, &index); if (entity == NULL) { gbString type_str = type_to_string(type); - print_checker_error(c, ast_node_token(ce->arg_list), + checker_err(c, ast_node_token(ce->arg_list), "`%s` has no field named `%.*s`", type_str, LIT(field_arg->identifier.token.string)); return false; } operand->mode = Addressing_Constant; - operand->value = make_value_integer(type_offset_of(c->sizes, c->allocator, type, index)); + operand->value = make_exact_value_integer(type_offset_of(c->sizes, c->allocator, type, index)); operand->type = &basic_types[Basic_int]; } break; @@ -1095,7 +1102,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) AstNode *arg = unparen_expression(ce->arg_list); if (arg->kind != AstNode_SelectorExpression) { gbString str = expression_to_string(arg); - print_checker_error(c, ast_node_token(arg), "`%s` is not a selector expression", str); + checker_err(c, ast_node_token(arg), "`%s` is not a selector expression", str); return false; } auto *s = &arg->selector_expression; @@ -1115,13 +1122,13 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) Entity *entity = lookup_field(type, s->selector, &index); if (entity == NULL) { gbString type_str = type_to_string(type); - print_checker_error(c, ast_node_token(arg), - "`%s` has no field named `%.*s`", type_str, LIT(s->selector->identifier.token.string)); + checker_err(c, ast_node_token(arg), + "`%s` has no field named `%.*s`", type_str, LIT(s->selector->identifier.token.string)); return false; } operand->mode = Addressing_Constant; - operand->value = make_value_integer(type_offset_of(c->sizes, c->allocator, type, index)); + operand->value = make_exact_value_integer(type_offset_of(c->sizes, c->allocator, type, index)); operand->type = &basic_types[Basic_int]; } break; @@ -1133,15 +1140,15 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) !is_type_boolean(operand->type)) { gbString str = expression_to_string(ce->arg_list); defer (gb_string_free(str)); - print_checker_error(c, ast_node_token(call), - "`%s` is not a constant boolean", str); + checker_err(c, ast_node_token(call), + "`%s` is not a constant boolean", str); return false; } if (!operand->value.value_bool) { gbString str = expression_to_string(ce->arg_list); defer (gb_string_free(str)); - print_checker_error(c, ast_node_token(call), - "Static assertion: `%s`", str); + checker_err(c, ast_node_token(call), + "Static assertion: `%s`", str); return true; } break; @@ -1152,7 +1159,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) Type *t = get_base_type(operand->type); AddressingMode mode = Addressing_Invalid; - Value value = {}; + ExactValue value = {}; switch (t->kind) { case Type_Basic: @@ -1160,7 +1167,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (is_type_string(t)) { if (operand->mode == Addressing_Constant) { mode = Addressing_Constant; - value = make_value_integer(operand->value.value_string.len); + value = make_exact_value_integer(operand->value.value_string.len); } else { mode = Addressing_Value; } @@ -1170,7 +1177,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) case Type_Array: mode = Addressing_Constant; - value = make_value_integer(t->array.count); + value = make_exact_value_integer(t->array.count); break; case Type_Slice: @@ -1180,9 +1187,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) if (mode == Addressing_Invalid) { gbString str = expression_to_string(operand->expression); - print_checker_error(c, ast_node_token(operand->expression), - "Invalid expression `%s` for `%.*s`", - str, LIT(bp->name)); + checker_err(c, ast_node_token(operand->expression), + "Invalid expression `%s` for `%.*s`", + str, LIT(bp->name)); gb_string_free(str); return false; } @@ -1211,7 +1218,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) src_type = s->slice.element; if (dest_type == NULL || src_type == NULL) { - print_checker_error(c, ast_node_token(call), "`copy` only expects slices as arguments"); + checker_err(c, ast_node_token(call), "`copy` only expects slices as arguments"); return false; } @@ -1224,9 +1231,9 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) defer (gb_string_free(s_arg)); defer (gb_string_free(d_str)); defer (gb_string_free(s_str)); - print_checker_error(c, ast_node_token(call), - "Arguments to `copy`, %s, %s, have different element types: %s vs %s", - d_arg, s_arg, d_str, s_str); + checker_err(c, ast_node_token(call), + "Arguments to `copy`, %s, %s, have different element types: %s vs %s", + d_arg, s_arg, d_str, s_str); return false; } @@ -1251,7 +1258,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) src_type = s; if (dest_type == NULL || src_type == NULL) { - print_checker_error(c, ast_node_token(call), "`copy_bytes` only expects pointers for the destintation and source"); + checker_err(c, ast_node_token(call), "`copy_bytes` only expects pointers for the destintation and source"); return false; } @@ -1265,13 +1272,13 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) op.type->basic.kind != Basic_int) { gbString str = type_to_string(op.type); defer (gb_string_free(str)); - print_checker_error(c, ast_node_token(call), "`copy_bytes` 3rd argument must be of type `int`, a `%s` was given", str); + checker_err(c, ast_node_token(call), "`copy_bytes` 3rd argument must be of type `int`, a `%s` was given", str); return false; } if (op.mode == Addressing_Constant) { - if (value_to_integer(op.value).value_integer <= 0) { - print_checker_error(c, ast_node_token(call), "You cannot copy a zero or negative amount of bytes with `copy_bytes`"); + if (exact_value_to_integer(op.value).value_integer <= 0) { + checker_err(c, ast_node_token(call), "You cannot copy a zero or negative amount of bytes with `copy_bytes`"); return false; } } @@ -1364,7 +1371,7 @@ void check_call_arguments(Checker *c, Operand *operand, Type *proc_type, AstNode } gbString proc_str = expression_to_string(ce->proc); - print_checker_error(c, ast_node_token(call), err_fmt, proc_str, param_count); + checker_err(c, ast_node_token(call), err_fmt, proc_str, param_count); gb_string_free(proc_str); operand->mode = Addressing_Invalid; @@ -1398,8 +1405,7 @@ ExpressionKind check_call_expression(Checker *c, Operand *operand, AstNode *call AstNode *e = operand->expression; gbString str = expression_to_string(e); defer (gb_string_free(str)); - print_checker_error(c, ast_node_token(e), - "Cannot call a non-procedure: `%s`", str); + checker_err(c, ast_node_token(e), "Cannot call a non-procedure: `%s`", str); operand->mode = Addressing_Invalid; operand->expression = call; @@ -1407,6 +1413,7 @@ ExpressionKind check_call_expression(Checker *c, Operand *operand, AstNode *call return Expression_Statement; } + check_call_arguments(c, operand, proc_type, call); auto *proc = &proc_type->procedure; @@ -1486,8 +1493,7 @@ void check_cast_expression(Checker *c, Operand *operand, Type *type) { gbString type_str = type_to_string(type); defer (gb_string_free(expr_str)); defer (gb_string_free(type_str)); - print_checker_error(c, ast_node_token(operand->expression), - "Cannot cast `%s` to `%s`", expr_str, type_str); + checker_err(c, ast_node_token(operand->expression), "Cannot cast `%s` to `%s`", expr_str, type_str); operand->mode = Addressing_Invalid; return; @@ -1498,18 +1504,18 @@ void check_cast_expression(Checker *c, Operand *operand, Type *type) { -ExpressionKind check_expression_base(Checker *c, Operand *operand, AstNode *node, Type *type_hint) { +ExpressionKind check__expression_base(Checker *c, Operand *o, AstNode *node, Type *type_hint) { ExpressionKind kind = Expression_Statement; - operand->mode = Addressing_Invalid; - operand->type = &basic_types[Basic_Invalid]; + o->mode = Addressing_Invalid; + o->type = &basic_types[Basic_Invalid]; switch (node->kind) { case AstNode_BadExpression: goto error; case AstNode_Identifier: - check_identifier(c, operand, node, type_hint); + check_identifier(c, o, node, type_hint); break; case AstNode_BasicLiteral: { BasicKind basic_kind = Basic_Invalid; @@ -1521,97 +1527,95 @@ ExpressionKind check_expression_base(Checker *c, Operand *operand, AstNode *node case Token_Rune: basic_kind = Basic_UntypedRune; break; default: GB_PANIC("Unknown literal"); break; } - operand->mode = Addressing_Constant; - operand->type = &basic_types[basic_kind]; - operand->value = make_value_from_basic_literal(lit); + o->mode = Addressing_Constant; + o->type = &basic_types[basic_kind]; + o->value = make_exact_value_from_basic_literal(lit); } break; case AstNode_ParenExpression: - kind = check_expression_base(c, operand, node->paren_expression.expression, type_hint); - operand->expression = node; + kind = check_expression_base(c, o, node->paren_expression.expression, type_hint); + o->expression = node; break; case AstNode_TagExpression: // TODO(bill): Tag expressions - print_checker_error(c, ast_node_token(node), "Tag expressions are not supported yet"); - kind = check_expression_base(c, operand, node->tag_expression.expression, type_hint); - operand->expression = node; + checker_err(c, ast_node_token(node), "Tag expressions are not supported yet"); + kind = check_expression_base(c, o, node->tag_expression.expression, type_hint); + o->expression = node; break; case AstNode_UnaryExpression: - check_expression(c, operand, node->unary_expression.operand); - if (operand->mode == Addressing_Invalid) + check_expression(c, o, node->unary_expression.operand); + if (o->mode == Addressing_Invalid) goto error; - check_unary_expression(c, operand, node->unary_expression.op, node); - if (operand->mode == Addressing_Invalid) + check_unary_expression(c, o, node->unary_expression.op, node); + if (o->mode == Addressing_Invalid) goto error; break; case AstNode_BinaryExpression: - check_binary_expression(c, operand, node); - if (operand->mode == Addressing_Invalid) + check_binary_expression(c, o, node); + if (o->mode == Addressing_Invalid) goto error; break; case AstNode_SelectorExpression: - check_expression_base(c, operand, node->selector_expression.operand); - check_selector(c, operand, node); + check_expression_base(c, o, node->selector_expression.operand); + check_selector(c, o, node); break; case AstNode_IndexExpression: { - check_expression(c, operand, node->index_expression.expression); - if (operand->mode == Addressing_Invalid) + check_expression(c, o, node->index_expression.expression); + if (o->mode == Addressing_Invalid) goto error; b32 valid = false; i64 max_count = -1; - Type *t = get_base_type(operand->type); + Type *t = get_base_type(o->type); switch (t->kind) { case Type_Basic: if (is_type_string(t)) { valid = true; - if (operand->mode == Addressing_Constant) { - max_count = operand->value.value_string.len; + if (o->mode == Addressing_Constant) { + max_count = o->value.value_string.len; } - operand->mode = Addressing_Value; - operand->type = &basic_types[Basic_u8]; + o->mode = Addressing_Value; + o->type = &basic_types[Basic_u8]; } break; case Type_Array: valid = true; max_count = t->array.count; - if (operand->mode != Addressing_Variable) - operand->mode = Addressing_Value; - operand->type = t->array.element; + if (o->mode != Addressing_Variable) + o->mode = Addressing_Value; + o->type = t->array.element; break; case Type_Slice: valid = true; - operand->type = t->slice.element; - operand->mode = Addressing_Variable; + o->type = t->slice.element; + o->mode = Addressing_Variable; break; case Type_Pointer: valid = true; - operand->mode = Addressing_Variable; - operand->type = get_base_type(t->pointer.element); + o->mode = Addressing_Variable; + o->type = get_base_type(t->pointer.element); break; } if (!valid) { - gbString str = expression_to_string(operand->expression); - print_checker_error(c, ast_node_token(operand->expression), - "Cannot index `%s`", str); + gbString str = expression_to_string(o->expression); + checker_err(c, ast_node_token(o->expression), "Cannot index `%s`", str); gb_string_free(str); goto error; } if (node->index_expression.value == NULL) { - gbString str = expression_to_string(operand->expression); - print_checker_error(c, ast_node_token(operand->expression), - "Missing index for `%s`", str); + gbString str = expression_to_string(o->expression); + checker_err(c, ast_node_token(o->expression), "Missing index for `%s`", str); gb_string_free(str); goto error; } @@ -1622,53 +1626,52 @@ ExpressionKind check_expression_base(Checker *c, Operand *operand, AstNode *node case AstNode_SliceExpression: { auto *se = &node->slice_expression; - check_expression(c, operand, se->expression); - if (operand->mode == Addressing_Invalid) + check_expression(c, o, se->expression); + if (o->mode == Addressing_Invalid) goto error; b32 valid = false; i64 max_count = -1; - Type *t = get_base_type(operand->type); + Type *t = get_base_type(o->type); switch (t->kind) { case Type_Basic: if (is_type_string(t)) { valid = true; - if (operand->mode == Addressing_Constant) { - max_count = operand->value.value_string.len; + if (o->mode == Addressing_Constant) { + max_count = o->value.value_string.len; } - operand->mode = Addressing_Value; + o->mode = Addressing_Value; } break; case Type_Array: valid = true; max_count = t->array.count; - if (operand->mode != Addressing_Variable) { + if (o->mode != Addressing_Variable) { gbString str = expression_to_string(node); - print_checker_error(c, ast_node_token(node), "Cannot slice array `%s`, value is not addressable", str); + checker_err(c, ast_node_token(node), "Cannot slice array `%s`, value is not addressable", str); gb_string_free(str); goto error; } - operand->type = make_type_slice(c->allocator, t->array.element); - operand->mode = Addressing_Value; + o->type = make_type_slice(c->allocator, t->array.element); + o->mode = Addressing_Value; break; case Type_Slice: valid = true; - operand->mode = Addressing_Value; + o->mode = Addressing_Value; break; case Type_Pointer: valid = true; - operand->type = make_type_slice(c->allocator, get_base_type(t->pointer.element)); - operand->mode = Addressing_Value; + o->type = make_type_slice(c->allocator, get_base_type(t->pointer.element)); + o->mode = Addressing_Value; break; } if (!valid) { - gbString str = expression_to_string(operand->expression); - print_checker_error(c, ast_node_token(operand->expression), - "Cannot slice `%s`", str); + gbString str = expression_to_string(o->expression); + checker_err(c, ast_node_token(o->expression), "Cannot slice `%s`", str); gb_string_free(str); goto error; } @@ -1696,7 +1699,7 @@ ExpressionKind check_expression_base(Checker *c, Operand *operand, AstNode *node for (isize j = i+1; j < gb_count_of(indices); j++) { i64 b = indices[j]; if (a > b && b >= 0) { - print_checker_error(c, se->close, "Invalid slice indices: [%td > %td]", a, b); + checker_err(c, se->close, "Invalid slice indices: [%td > %td]", a, b); } } } @@ -1705,28 +1708,27 @@ ExpressionKind check_expression_base(Checker *c, Operand *operand, AstNode *node case AstNode_CastExpression: { Type *cast_type = check_type(c, node->cast_expression.type_expression); - check_expression_or_type(c, operand, node->cast_expression.operand); - if (operand->mode != Addressing_Invalid) - check_cast_expression(c, operand, cast_type); + check_expression_or_type(c, o, node->cast_expression.operand); + if (o->mode != Addressing_Invalid) + check_cast_expression(c, o, cast_type); } break; case AstNode_CallExpression: - return check_call_expression(c, operand, node); + return check_call_expression(c, o, node); case AstNode_DereferenceExpression: - check_expression_or_type(c, operand, node->dereference_expression.operand); - if (operand->mode == Addressing_Invalid) { + check_expression_or_type(c, o, node->dereference_expression.operand); + if (o->mode == Addressing_Invalid) { goto error; } else { - Type *t = get_base_type(operand->type); + Type *t = get_base_type(o->type); if (t->kind == Type_Pointer) { - operand->mode = Addressing_Variable; - operand->type = t->pointer.element; + o->mode = Addressing_Variable; + o->type = t->pointer.element; } else { - gbString str = expression_to_string(operand->expression); - print_checker_error(c, ast_node_token(operand->expression), - "Cannot dereference `%s`", str); + gbString str = expression_to_string(o->expression); + checker_err(c, ast_node_token(o->expression), "Cannot dereference `%s`", str); gb_string_free(str); goto error; } @@ -1737,24 +1739,26 @@ ExpressionKind check_expression_base(Checker *c, Operand *operand, AstNode *node case AstNode_PointerType: case AstNode_ArrayType: case AstNode_StructType: - operand->mode = Addressing_Type; - operand->type = check_type(c, node); + o->mode = Addressing_Type; + o->type = check_type(c, node); break; } kind = Expression_Expression; - operand->expression = node; - goto after_error; + o->expression = node; + return kind; error: - operand->mode = Addressing_Invalid; - operand->expression = node; - goto after_error; + o->mode = Addressing_Invalid; + o->expression = node; + return kind; +} -after_error: +ExpressionKind check_expression_base(Checker *c, Operand *o, AstNode *node, Type *type_hint) { + ExpressionKind kind = check__expression_base(c, o, node, type_hint); Type *type = NULL; - Value value = {Value_Invalid}; - switch (operand->mode) { + ExactValue value = {ExactValue_Invalid}; + switch (o->mode) { case Addressing_Invalid: type = &basic_types[Basic_Invalid]; break; @@ -1762,76 +1766,76 @@ after_error: type = NULL; break; case Addressing_Constant: - type = operand->type; - value = operand->value; + type = o->type; + value = o->value; break; default: - type = operand->type; + type = o->type; break; } - if (type) { + if (type != NULL) { if (is_type_untyped(type)) { - add_untyped(c, node, false, operand->mode, type, value); + add_untyped(c, node, false, o->mode, type, value); } else { - add_type_and_value(c, node, operand->mode, type, value); + add_type_and_value(c, node, o->mode, type, value); } } return kind; } -void check_multi_expression(Checker *c, Operand *operand, AstNode *expression) { + +void check_multi_expression(Checker *c, Operand *o, AstNode *e) { gbString err_str = NULL; defer (gb_string_free(err_str)); - check_expression_base(c, operand, expression); - switch (operand->mode) { + check_expression_base(c, o, e); + switch (o->mode) { default: return; // NOTE(bill): Valid case Addressing_NoValue: - err_str = expression_to_string(expression); - print_checker_error(c, ast_node_token(expression), "`%s` used as value", err_str); + err_str = expression_to_string(e); + checker_err(c, ast_node_token(e), "`%s` used as value", err_str); break; case Addressing_Type: - err_str = expression_to_string(expression); - print_checker_error(c, ast_node_token(expression), "`%s` is not an expression", err_str); + err_str = expression_to_string(e); + checker_err(c, ast_node_token(e), "`%s` is not an expression", err_str); break; } - operand->mode = Addressing_Invalid; + o->mode = Addressing_Invalid; } -// NOTE(bill): Just a santity checker -// TODO(bill): Remove this entirely -void check_not_tuple(Checker *c, Operand *operand) { - if (operand->mode == Addressing_Value) { +// TODO(bill): Should I remove this entirely? +void check_not_tuple(Checker *c, Operand *o) { + if (o->mode == Addressing_Value) { // NOTE(bill): Tuples are not first class thus never named - if (operand->type->kind == Type_Tuple) { - isize count = operand->type->tuple.variable_count; + if (o->type->kind == Type_Tuple) { + isize count = o->type->tuple.variable_count; GB_ASSERT(count != 1); - print_checker_error(c, ast_node_token(operand->expression), - gb_bprintf("%td-valued tuple found where single value expected", count)); - operand->mode = Addressing_Invalid; + checker_err(c, ast_node_token(o->expression), + "%td-valued tuple found where single value expected", count); + o->mode = Addressing_Invalid; } } } -void check_expression(Checker *c, Operand *operand, AstNode *expression) { - check_multi_expression(c, operand, expression); - check_not_tuple(c, operand); +void check_expression(Checker *c, Operand *o, AstNode *e) { + check_multi_expression(c, o, e); + check_not_tuple(c, o); } -void check_expression_or_type(Checker *c, Operand *operand, AstNode *expression) { - check_expression_base(c, operand, expression); - check_not_tuple(c, operand); - if (operand->mode == Addressing_NoValue) { - AstNode *e = operand->expression; +void check_expression_or_type(Checker *c, Operand *o, AstNode *e) { + check_expression_base(c, o, e); + check_not_tuple(c, o); + if (o->mode == Addressing_NoValue) { + AstNode *e = o->expression; gbString str = expression_to_string(e); defer (gb_string_free(str)); - print_checker_error(c, ast_node_token(e), - "`%s` used as value or type", str); - operand->mode = Addressing_Invalid; + checker_err(c, ast_node_token(e), + "`%s` used as value or type", str); + o->mode = Addressing_Invalid; } } diff --git a/src/checker/statements.cpp b/src/checker/statements.cpp index 435f7ef4f..5bb151252 100644 --- a/src/checker/statements.cpp +++ b/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: { diff --git a/src/checker/type.cpp b/src/checker/type.cpp index b7be9a3db..301def0ca 100644 --- a/src/checker/type.cpp +++ b/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")}}, }; diff --git a/src/checker/value.cpp b/src/exact_value.cpp similarity index 52% rename from src/checker/value.cpp rename to src/exact_value.cpp index fcfe6c336..52094cfed 100644 --- a/src/checker/value.cpp +++ b/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)<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); diff --git a/src/gb/gb.h b/src/gb/gb.h index 7fce1e6e8..4c1b8f7e9 100644 --- a/src/gb/gb.h +++ b/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; } diff --git a/src/generator.cpp b/src/generator.cpp deleted file mode 100644 index 4c4afe207..000000000 --- a/src/generator.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include - -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); - // } - // } - // } - -} diff --git a/src/main.cpp b/src/main.cpp index 68b7b7ee8..e4190714e 100644 --- a/src/main.cpp +++ b/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 } diff --git a/src/parser.cpp b/src/parser.cpp index 050a69894..223229f03 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2,6 +2,27 @@ struct AstNode; struct Type; struct AstScope; + + +struct AstFile { + gbArena arena; + Tokenizer tokenizer; + gbArray(Token) tokens; + Token * cursor; // NOTE(bill): Current token, easy to peek forward and backwards if needed + + AstNode *declarations; + isize declaration_count; + + AstScope *file_scope; + AstScope *curr_scope; + isize scope_level; + + isize error_count; + isize error_prev_line; + isize error_prev_column; +}; + + // NOTE(bill): Just used to quickly check if there is double declaration in the same scope // No type checking actually happens // TODO(bill): Should this be completely handled in the semantic checker or is it better here? @@ -17,19 +38,9 @@ struct AstScope { }; struct Parser { - gbArena arena; - Tokenizer tokenizer; - gbArray(Token) tokens; - Token * cursor; // NOTE(bill): Current token, easy to peek forward and backwards if needed - - AstScope *file_scope; - AstScope *curr_scope; - isize scope_level; - -#define MAX_PARSER_ERROR_COUNT 10 - isize error_count; - isize error_prev_line; - isize error_prev_column; + gbArray(AstFile) files; + gbArray(String) imports; + isize import_index; }; enum AstNodeKind { @@ -75,6 +86,7 @@ AstNode__DeclarationBegin, AstNode_VariableDeclaration, AstNode_ProcedureDeclaration, AstNode_TypeDeclaration, + AstNode_ImportDeclaration, AstNode__DeclarationEnd, AstNode__TypeBegin, @@ -207,6 +219,10 @@ struct AstNode { AstNode *name; // AstNode_Identifier AstNode *type_expression; } type_declaration; + struct { + Token token; + Token filepath; + } import_declaration; struct { @@ -226,9 +242,8 @@ struct AstNode { }; }; - -gb_inline AstScope *make_ast_scope(Parser *p, AstScope *parent) { - AstScope *scope = gb_alloc_item(gb_arena_allocator(&p->arena), AstScope); +gb_inline AstScope *make_ast_scope(AstFile *f, AstScope *parent) { + AstScope *scope = gb_alloc_item(gb_arena_allocator(&f->arena), AstScope); map_init(&scope->entities, gb_heap_allocator()); scope->parent = parent; return scope; @@ -310,6 +325,8 @@ Token ast_node_token(AstNode *node) { return node->procedure_declaration.name->identifier.token; case AstNode_TypeDeclaration: return node->type_declaration.token; + case AstNode_ImportDeclaration: + return node->import_declaration.token; case AstNode_Field: { if (node->field.name_list) return ast_node_token(node->field.name_list); @@ -336,28 +353,28 @@ gb_inline void destroy_ast_scope(AstScope *scope) { map_destroy(&scope->entities); } -gb_inline AstScope *open_ast_scope(Parser *p) { - AstScope *scope = make_ast_scope(p, p->curr_scope); - p->curr_scope = scope; - p->scope_level++; - return p->curr_scope; +gb_inline AstScope *open_ast_scope(AstFile *f) { + AstScope *scope = make_ast_scope(f, f->curr_scope); + f->curr_scope = scope; + f->scope_level++; + return f->curr_scope; } -gb_inline void close_ast_scope(Parser *p) { - GB_ASSERT_NOT_NULL(p->curr_scope); - GB_ASSERT(p->scope_level > 0); +gb_inline void close_ast_scope(AstFile *f) { + GB_ASSERT_NOT_NULL(f->curr_scope); + GB_ASSERT(f->scope_level > 0); { - AstScope *parent = p->curr_scope->parent; - if (p->curr_scope) { - destroy_ast_scope(p->curr_scope); + AstScope *parent = f->curr_scope->parent; + if (f->curr_scope) { + destroy_ast_scope(f->curr_scope); } - p->curr_scope = parent; - p->scope_level--; + f->curr_scope = parent; + f->scope_level--; } } -AstEntity *make_ast_entity(Parser *p, Token token, AstNode *declaration, AstScope *parent) { - AstEntity *entity = gb_alloc_item(gb_arena_allocator(&p->arena), AstEntity); +AstEntity *make_ast_entity(AstFile *f, Token token, AstNode *declaration, AstScope *parent) { + AstEntity *entity = gb_alloc_item(gb_arena_allocator(&f->arena), AstEntity); entity->token = token; entity->declaration = declaration; entity->parent = parent; @@ -381,88 +398,99 @@ AstEntity *ast_scope_insert(AstScope *scope, AstEntity entity) { } -#define print_parse_error(p, token, fmt, ...) print_parse_error_(p, __FUNCTION__, token, fmt, ##__VA_ARGS__) -void print_parse_error_(Parser *p, char *function, Token token, char *fmt, ...) { - +#define ast_file_err(f, token, fmt, ...) ast_file_err_(f, __FUNCTION__, token, fmt, ##__VA_ARGS__) +void ast_file_err_(AstFile *file, char *function, Token token, char *fmt, ...) { // NOTE(bill): Duplicate error, skip it - if (p->error_prev_line != token.line || p->error_prev_column != token.column) { + if (file->error_prev_line != token.line || file->error_prev_column != token.column) { va_list va; - p->error_prev_line = token.line; - p->error_prev_column = token.column; + file->error_prev_line = token.line; + file->error_prev_column = token.column; - #if 1 + #if 0 gb_printf_err("%s()\n", function); #endif va_start(va, fmt); - gb_printf_err("%s(%td:%td) Syntax error: %s\n", - p->tokenizer.fullpath, token.line, token.column, + gb_printf_err("%.*s(%td:%td) Syntax error: %s\n", + LIT(file->tokenizer.fullpath), token.line, token.column, gb_bprintf_va(fmt, va)); va_end(va); } - p->error_count++; + file->error_count++; } // NOTE(bill): And this below is why is I/we need a new language! Discriminated unions are a pain in C/C++ -gb_inline AstNode *make_node(Parser *p, AstNodeKind kind) { - if (gb_arena_size_remaining(&p->arena, GB_DEFAULT_MEMORY_ALIGNMENT) < gb_size_of(AstNode)) { +gb_inline AstNode *make_node(AstFile *f, AstNodeKind kind) { + gbArena *arena = &f->arena; + if (gb_arena_size_remaining(arena, GB_DEFAULT_MEMORY_ALIGNMENT) < gb_size_of(AstNode)) { // NOTE(bill): If a syntax error is so bad, just quit! gb_exit(1); } - AstNode *node = gb_alloc_item(gb_arena_allocator(&p->arena), AstNode); + AstNode *node = gb_alloc_item(gb_arena_allocator(arena), AstNode); node->kind = kind; return node; } -gb_inline AstNode *make_bad_expression(Parser *p, Token begin, Token end) { - AstNode *result = make_node(p, AstNode_BadExpression); +gb_inline AstNode *make_bad_expression(AstFile *f, Token begin, Token end) { + AstNode *result = make_node(f, AstNode_BadExpression); result->bad_expression.begin = begin; result->bad_expression.end = end; return result; } -gb_inline AstNode *make_tag_expression(Parser *p, Token token, Token name, AstNode *expression) { - AstNode *result = make_node(p, AstNode_TagExpression); +gb_inline AstNode *make_tag_expression(AstFile *f, Token token, Token name, AstNode *expression) { + AstNode *result = make_node(f, AstNode_TagExpression); result->tag_expression.token = token; result->tag_expression.name = name; result->tag_expression.expression = expression; return result; } -gb_inline AstNode *make_tag_statement(Parser *p, Token token, Token name, AstNode *statement) { - AstNode *result = make_node(p, AstNode_TagStatement); +gb_inline AstNode *make_tag_statement(AstFile *f, Token token, Token name, AstNode *statement) { + AstNode *result = make_node(f, AstNode_TagStatement); result->tag_statement.token = token; result->tag_statement.name = name; result->tag_statement.statement = statement; return result; } -gb_inline AstNode *make_unary_expression(Parser *p, Token op, AstNode *operand) { - AstNode *result = make_node(p, AstNode_UnaryExpression); +gb_inline AstNode *make_unary_expression(AstFile *f, Token op, AstNode *operand) { + AstNode *result = make_node(f, AstNode_UnaryExpression); result->unary_expression.op = op; result->unary_expression.operand = operand; return result; } -gb_inline AstNode *make_binary_expression(Parser *p, Token op, AstNode *left, AstNode *right) { - AstNode *result = make_node(p, AstNode_BinaryExpression); +gb_inline AstNode *make_binary_expression(AstFile *f, Token op, AstNode *left, AstNode *right) { + AstNode *result = make_node(f, AstNode_BinaryExpression); + + if (left == NULL) { + ast_file_err(f, op, "No lhs expression for binary expression `%.*s`", LIT(op.string)); + left = make_bad_expression(f, op, op); + } + if (right == NULL) { + ast_file_err(f, op, "No rhs expression for binary expression `%.*s`", LIT(op.string)); + right = make_bad_expression(f, op, op); + } + result->binary_expression.op = op; result->binary_expression.left = left; result->binary_expression.right = right; + return result; } -gb_inline AstNode *make_paren_expression(Parser *p, AstNode *expression, Token open, Token close) { - AstNode *result = make_node(p, AstNode_ParenExpression); +gb_inline AstNode *make_paren_expression(AstFile *f, AstNode *expression, Token open, Token close) { + AstNode *result = make_node(f, AstNode_ParenExpression); result->paren_expression.expression = expression; result->paren_expression.open = open; result->paren_expression.close = close; return result; } -gb_inline AstNode *make_call_expression(Parser *p, AstNode *proc, AstNode *arg_list, isize arg_list_count, Token open, Token close) { - AstNode *result = make_node(p, AstNode_CallExpression); +gb_inline AstNode *make_call_expression(AstFile *f, AstNode *proc, AstNode *arg_list, isize arg_list_count, Token open, Token close) { + AstNode *result = make_node(f, AstNode_CallExpression); result->call_expression.proc = proc; result->call_expression.arg_list = arg_list; result->call_expression.arg_list_count = arg_list_count; @@ -471,15 +499,15 @@ gb_inline AstNode *make_call_expression(Parser *p, AstNode *proc, AstNode *arg_l return result; } -gb_inline AstNode *make_selector_expression(Parser *p, Token token, AstNode *operand, AstNode *selector) { - AstNode *result = make_node(p, AstNode_SelectorExpression); +gb_inline AstNode *make_selector_expression(AstFile *f, Token token, AstNode *operand, AstNode *selector) { + AstNode *result = make_node(f, AstNode_SelectorExpression); result->selector_expression.operand = operand; result->selector_expression.selector = selector; return result; } -gb_inline AstNode *make_index_expression(Parser *p, AstNode *expression, AstNode *value, Token open, Token close) { - AstNode *result = make_node(p, AstNode_IndexExpression); +gb_inline AstNode *make_index_expression(AstFile *f, AstNode *expression, AstNode *value, Token open, Token close) { + AstNode *result = make_node(f, AstNode_IndexExpression); result->index_expression.expression = expression; result->index_expression.value = value; result->index_expression.open = open; @@ -488,8 +516,8 @@ gb_inline AstNode *make_index_expression(Parser *p, AstNode *expression, AstNode } -gb_inline AstNode *make_slice_expression(Parser *p, AstNode *expression, Token open, Token close, AstNode *low, AstNode *high, AstNode *max, b32 triple_indexed) { - AstNode *result = make_node(p, AstNode_SliceExpression); +gb_inline AstNode *make_slice_expression(AstFile *f, AstNode *expression, Token open, Token close, AstNode *low, AstNode *high, AstNode *max, b32 triple_indexed) { + AstNode *result = make_node(f, AstNode_SliceExpression); result->slice_expression.expression = expression; result->slice_expression.open = open; result->slice_expression.close = close; @@ -500,8 +528,8 @@ gb_inline AstNode *make_slice_expression(Parser *p, AstNode *expression, Token o return result; } -gb_inline AstNode *make_cast_expression(Parser *p, Token token, AstNode *type_expression, AstNode *operand) { - AstNode *result = make_node(p, AstNode_CastExpression); +gb_inline AstNode *make_cast_expression(AstFile *f, Token token, AstNode *type_expression, AstNode *operand) { + AstNode *result = make_node(f, AstNode_CastExpression); result->cast_expression.token = token; result->cast_expression.type_expression = type_expression; result->cast_expression.operand = operand; @@ -509,55 +537,55 @@ gb_inline AstNode *make_cast_expression(Parser *p, Token token, AstNode *type_ex } -gb_inline AstNode *make_dereference_expression(Parser *p, AstNode *operand, Token op) { - AstNode *result = make_node(p, AstNode_DereferenceExpression); +gb_inline AstNode *make_dereference_expression(AstFile *f, AstNode *operand, Token op) { + AstNode *result = make_node(f, AstNode_DereferenceExpression); result->dereference_expression.operand = operand; result->dereference_expression.op = op; return result; } -gb_inline AstNode *make_basic_literal(Parser *p, Token basic_literal) { - AstNode *result = make_node(p, AstNode_BasicLiteral); +gb_inline AstNode *make_basic_literal(AstFile *f, Token basic_literal) { + AstNode *result = make_node(f, AstNode_BasicLiteral); result->basic_literal = basic_literal; return result; } -gb_inline AstNode *make_identifier(Parser *p, Token token, AstEntity *entity = NULL) { - AstNode *result = make_node(p, AstNode_Identifier); +gb_inline AstNode *make_identifier(AstFile *f, Token token, AstEntity *entity = NULL) { + AstNode *result = make_node(f, AstNode_Identifier); result->identifier.token = token; result->identifier.entity = entity; return result; } -gb_inline AstNode *make_bad_statement(Parser *p, Token begin, Token end) { - AstNode *result = make_node(p, AstNode_BadStatement); +gb_inline AstNode *make_bad_statement(AstFile *f, Token begin, Token end) { + AstNode *result = make_node(f, AstNode_BadStatement); result->bad_statement.begin = begin; result->bad_statement.end = end; return result; } -gb_inline AstNode *make_empty_statement(Parser *p, Token token) { - AstNode *result = make_node(p, AstNode_EmptyStatement); +gb_inline AstNode *make_empty_statement(AstFile *f, Token token) { + AstNode *result = make_node(f, AstNode_EmptyStatement); result->empty_statement.token = token; return result; } -gb_inline AstNode *make_expression_statement(Parser *p, AstNode *expression) { - AstNode *result = make_node(p, AstNode_ExpressionStatement); +gb_inline AstNode *make_expression_statement(AstFile *f, AstNode *expression) { + AstNode *result = make_node(f, AstNode_ExpressionStatement); result->expression_statement.expression = expression; return result; } -gb_inline AstNode *make_inc_dec_statement(Parser *p, Token op, AstNode *expression) { - AstNode *result = make_node(p, AstNode_IncDecStatement); +gb_inline AstNode *make_inc_dec_statement(AstFile *f, Token op, AstNode *expression) { + AstNode *result = make_node(f, AstNode_IncDecStatement); result->inc_dec_statement.op = op; result->inc_dec_statement.expression = expression; return result; } -gb_inline AstNode *make_assign_statement(Parser *p, Token op, AstNode *lhs_list, isize lhs_count, AstNode *rhs_list, isize rhs_count) { - AstNode *result = make_node(p, AstNode_AssignStatement); +gb_inline AstNode *make_assign_statement(AstFile *f, Token op, AstNode *lhs_list, isize lhs_count, AstNode *rhs_list, isize rhs_count) { + AstNode *result = make_node(f, AstNode_AssignStatement); result->assign_statement.op = op; result->assign_statement.lhs_list = lhs_list; result->assign_statement.lhs_count = lhs_count; @@ -566,8 +594,8 @@ gb_inline AstNode *make_assign_statement(Parser *p, Token op, AstNode *lhs_list, return result; } -gb_inline AstNode *make_block_statement(Parser *p, AstNode *list, isize list_count, Token open, Token close) { - AstNode *result = make_node(p, AstNode_BlockStatement); +gb_inline AstNode *make_block_statement(AstFile *f, AstNode *list, isize list_count, Token open, Token close) { + AstNode *result = make_node(f, AstNode_BlockStatement); result->block_statement.list = list; result->block_statement.list_count = list_count; result->block_statement.open = open; @@ -575,8 +603,8 @@ gb_inline AstNode *make_block_statement(Parser *p, AstNode *list, isize list_cou return result; } -gb_inline AstNode *make_if_statement(Parser *p, Token token, AstNode *cond, AstNode *body, AstNode *else_statement) { - AstNode *result = make_node(p, AstNode_IfStatement); +gb_inline AstNode *make_if_statement(AstFile *f, Token token, AstNode *cond, AstNode *body, AstNode *else_statement) { + AstNode *result = make_node(f, AstNode_IfStatement); result->if_statement.token = token; result->if_statement.cond = cond; result->if_statement.body = body; @@ -584,16 +612,16 @@ gb_inline AstNode *make_if_statement(Parser *p, Token token, AstNode *cond, AstN return result; } -gb_inline AstNode *make_return_statement(Parser *p, Token token, AstNode *results, isize result_count) { - AstNode *result = make_node(p, AstNode_ReturnStatement); +gb_inline AstNode *make_return_statement(AstFile *f, Token token, AstNode *results, isize result_count) { + AstNode *result = make_node(f, AstNode_ReturnStatement); result->return_statement.token = token; result->return_statement.results = results; result->return_statement.result_count = result_count; return result; } -gb_inline AstNode *make_for_statement(Parser *p, Token token, AstNode *init, AstNode *cond, AstNode *end, AstNode *body) { - AstNode *result = make_node(p, AstNode_ForStatement); +gb_inline AstNode *make_for_statement(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *end, AstNode *body) { + AstNode *result = make_node(f, AstNode_ForStatement); result->for_statement.token = token; result->for_statement.init = init; result->for_statement.cond = cond; @@ -601,22 +629,22 @@ gb_inline AstNode *make_for_statement(Parser *p, Token token, AstNode *init, Ast result->for_statement.body = body; return result; } -gb_inline AstNode *make_defer_statement(Parser *p, Token token, AstNode *statement) { - AstNode *result = make_node(p, AstNode_DeferStatement); +gb_inline AstNode *make_defer_statement(AstFile *f, Token token, AstNode *statement) { + AstNode *result = make_node(f, AstNode_DeferStatement); result->defer_statement.token = token; result->defer_statement.statement = statement; return result; } -gb_inline AstNode *make_bad_declaration(Parser *p, Token begin, Token end) { - AstNode *result = make_node(p, AstNode_BadDeclaration); +gb_inline AstNode *make_bad_declaration(AstFile *f, Token begin, Token end) { + AstNode *result = make_node(f, AstNode_BadDeclaration); result->bad_declaration.begin = begin; result->bad_declaration.end = end; return result; } -gb_inline AstNode *make_variable_declaration(Parser *p, DeclarationKind kind, AstNode *name_list, isize name_list_count, AstNode *type_expression, AstNode *value_list, isize value_list_count) { - AstNode *result = make_node(p, AstNode_VariableDeclaration); +gb_inline AstNode *make_variable_declaration(AstFile *f, DeclarationKind kind, AstNode *name_list, isize name_list_count, AstNode *type_expression, AstNode *value_list, isize value_list_count) { + AstNode *result = make_node(f, AstNode_VariableDeclaration); result->variable_declaration.kind = kind; result->variable_declaration.name_list = name_list; result->variable_declaration.name_list_count = name_list_count; @@ -626,16 +654,16 @@ gb_inline AstNode *make_variable_declaration(Parser *p, DeclarationKind kind, As return result; } -gb_inline AstNode *make_field(Parser *p, AstNode *name_list, isize name_list_count, AstNode *type_expression) { - AstNode *result = make_node(p, AstNode_Field); +gb_inline AstNode *make_field(AstFile *f, AstNode *name_list, isize name_list_count, AstNode *type_expression) { + AstNode *result = make_node(f, AstNode_Field); result->field.name_list = name_list; result->field.name_list_count = name_list_count; result->field.type_expression = type_expression; return result; } -gb_inline AstNode *make_procedure_type(Parser *p, Token token, AstNode *param_list, isize param_count, AstNode *results_list, isize result_count) { - AstNode *result = make_node(p, AstNode_ProcedureType); +gb_inline AstNode *make_procedure_type(AstFile *f, Token token, AstNode *param_list, isize param_count, AstNode *results_list, isize result_count) { + AstNode *result = make_node(f, AstNode_ProcedureType); result->procedure_type.token = token; result->procedure_type.param_list = param_list; result->procedure_type.param_count = param_count; @@ -644,8 +672,8 @@ gb_inline AstNode *make_procedure_type(Parser *p, Token token, AstNode *param_li return result; } -gb_inline AstNode *make_procedure_declaration(Parser *p, DeclarationKind kind, AstNode *name, AstNode *procedure_type, AstNode *body, AstNode *tag_list, isize tag_count) { - AstNode *result = make_node(p, AstNode_ProcedureDeclaration); +gb_inline AstNode *make_procedure_declaration(AstFile *f, DeclarationKind kind, AstNode *name, AstNode *procedure_type, AstNode *body, AstNode *tag_list, isize tag_count) { + AstNode *result = make_node(f, AstNode_ProcedureDeclaration); result->procedure_declaration.kind = kind; result->procedure_declaration.name = name; result->procedure_declaration.procedure_type = procedure_type; @@ -655,81 +683,90 @@ gb_inline AstNode *make_procedure_declaration(Parser *p, DeclarationKind kind, A return result; } -gb_inline AstNode *make_pointer_type(Parser *p, Token token, AstNode *type_expression) { - AstNode *result = make_node(p, AstNode_PointerType); +gb_inline AstNode *make_pointer_type(AstFile *f, Token token, AstNode *type_expression) { + AstNode *result = make_node(f, AstNode_PointerType); result->pointer_type.token = token; result->pointer_type.type_expression = type_expression; return result; } -gb_inline AstNode *make_array_type(Parser *p, Token token, AstNode *count, AstNode *element) { - AstNode *result = make_node(p, AstNode_ArrayType); +gb_inline AstNode *make_array_type(AstFile *f, Token token, AstNode *count, AstNode *element) { + AstNode *result = make_node(f, AstNode_ArrayType); result->array_type.token = token; result->array_type.count = count; result->array_type.element = element; return result; } -gb_inline AstNode *make_struct_type(Parser *p, Token token, AstNode *field_list, isize field_count) { - AstNode *result = make_node(p, AstNode_StructType); +gb_inline AstNode *make_struct_type(AstFile *f, Token token, AstNode *field_list, isize field_count) { + AstNode *result = make_node(f, AstNode_StructType); result->struct_type.token = token; result->struct_type.field_list = field_list; result->struct_type.field_count = field_count; return result; } -gb_inline AstNode *make_type_declaration(Parser *p, Token token, AstNode *name, AstNode *type_expression) { - AstNode *result = make_node(p, AstNode_TypeDeclaration); +gb_inline AstNode *make_type_declaration(AstFile *f, Token token, AstNode *name, AstNode *type_expression) { + AstNode *result = make_node(f, AstNode_TypeDeclaration); result->type_declaration.token = token; result->type_declaration.name = name; result->type_declaration.type_expression = type_expression; return result; } +gb_inline AstNode *make_import_declaration(AstFile *f, Token token, Token filepath) { + AstNode *result = make_node(f, AstNode_ImportDeclaration); + result->import_declaration.token = token; + result->import_declaration.filepath = filepath; + return result; +} -gb_inline b32 next_token(Parser *p) { - if (p->cursor+1 < p->tokens + gb_array_count(p->tokens)) { - p->cursor++; +gb_inline b32 next_token(AstFile *f) { + if (f->cursor+1 < f->tokens + gb_array_count(f->tokens)) { + f->cursor++; return true; } else { - print_parse_error(p, p->cursor[0], "Token is EOF"); + ast_file_err(f, f->cursor[0], "Token is EOF"); return false; } } -gb_inline Token expect_token(Parser *p, TokenKind kind) { - Token prev = p->cursor[0]; - if (prev.kind != kind) - print_parse_error(p, p->cursor[0], "Expected `%s`, got `%s`", - token_kind_to_string(kind), - token_kind_to_string(prev.kind)); - next_token(p); +gb_inline Token expect_token(AstFile *f, TokenKind kind) { + Token prev = f->cursor[0]; + if (prev.kind != kind) { + ast_file_err(f, f->cursor[0], "Expected `%s`, got `%s`", + token_kind_to_string(kind), + token_kind_to_string(prev.kind)); + } + next_token(f); return prev; } -gb_inline Token expect_operator(Parser *p) { - Token prev = p->cursor[0]; - if (!gb_is_between(prev.kind, Token__OperatorBegin+1, Token__OperatorEnd-1)) - print_parse_error(p, p->cursor[0], "Expected an operator, got `%s`", - token_kind_to_string(prev.kind)); - next_token(p); +gb_inline Token expect_operator(AstFile *f) { + Token prev = f->cursor[0]; + if (!gb_is_between(prev.kind, Token__OperatorBegin+1, Token__OperatorEnd-1)) { + ast_file_err(f, f->cursor[0], "Expected an operator, got `%s`", + token_kind_to_string(prev.kind)); + } + next_token(f); return prev; } -gb_inline Token expect_keyword(Parser *p) { - Token prev = p->cursor[0]; - if (!gb_is_between(prev.kind, Token__KeywordBegin+1, Token__KeywordEnd-1)) - print_parse_error(p, p->cursor[0], "Expected a keyword, got `%s`", - token_kind_to_string(prev.kind)); - next_token(p); +gb_inline Token expect_keyword(AstFile *f) { + Token prev = f->cursor[0]; + if (!gb_is_between(prev.kind, Token__KeywordBegin+1, Token__KeywordEnd-1)) { + ast_file_err(f, f->cursor[0], "Expected a keyword, got `%s`", + token_kind_to_string(prev.kind)); + } + next_token(f); return prev; } -gb_inline b32 allow_token(Parser *p, TokenKind kind) { - Token prev = p->cursor[0]; +gb_inline b32 allow_token(AstFile *f, TokenKind kind) { + Token prev = f->cursor[0]; if (prev.kind == kind) { - next_token(p); + next_token(f); return true; } return false; @@ -737,87 +774,52 @@ gb_inline b32 allow_token(Parser *p, TokenKind kind) { -b32 init_parser(Parser *p, char *filename) { - if (init_tokenizer(&p->tokenizer, filename)) { - gb_array_init(p->tokens, gb_heap_allocator()); - for (;;) { - Token token = tokenizer_get_token(&p->tokenizer); - if (token.kind == Token_Invalid) - return false; - gb_array_append(p->tokens, token); - - if (token.kind == Token_EOF) - break; - } - - p->cursor = &p->tokens[0]; - - // NOTE(bill): Is this big enough or too small? - isize arena_size = gb_max(gb_size_of(AstNode), gb_size_of(AstScope)); - arena_size *= 2*gb_array_count(p->tokens); - gb_arena_init_from_allocator(&p->arena, gb_heap_allocator(), arena_size); - - open_ast_scope(p); - p->file_scope = p->curr_scope; - - return true; - } - return false; -} - -void destroy_parser(Parser *p) { - close_ast_scope(p); - gb_arena_free(&p->arena); - gb_array_free(p->tokens); - destroy_tokenizer(&p->tokenizer); -} - -gb_internal void add_ast_entity(Parser *p, AstScope *scope, AstNode *declaration, AstNode *name_list) { +gb_internal void add_ast_entity(AstFile *f, AstScope *scope, AstNode *declaration, AstNode *name_list) { for (AstNode *n = name_list; n != NULL; n = n->next) { if (n->kind != AstNode_Identifier) { - print_parse_error(p, ast_node_token(declaration), "Identifier is already declared or resolved"); + ast_file_err(f, ast_node_token(declaration), "Identifier is already declared or resolved"); continue; } - AstEntity *entity = make_ast_entity(p, n->identifier.token, declaration, scope); + AstEntity *entity = make_ast_entity(f, n->identifier.token, declaration, scope); n->identifier.entity = entity; AstEntity *insert_entity = ast_scope_insert(scope, *entity); if (insert_entity != NULL && !are_strings_equal(insert_entity->token.string, make_string("_"))) { - print_parse_error(p, entity->token, - "There is already a previous declaration of `%.*s` in the current scope at (%td:%td)", - LIT(insert_entity->token.string), - insert_entity->token.line, insert_entity->token.column); + ast_file_err(f, entity->token, + "There is already a previous declaration of `%.*s` in the current scope at (%td:%td)", + LIT(insert_entity->token.string), + insert_entity->token.line, insert_entity->token.column); } } } -AstNode *parse_expression(Parser *p, b32 lhs); +AstNode *parse_expression(AstFile *f, b32 lhs); -AstNode *parse_identifier(Parser *p) { - Token token = p->cursor[0]; +AstNode *parse_identifier(AstFile *f) { + Token token = f->cursor[0]; if (token.kind == Token_Identifier) { - next_token(p); + next_token(f); } else { token.string = make_string("_"); - expect_token(p, Token_Identifier); + expect_token(f, Token_Identifier); } - return make_identifier(p, token); + return make_identifier(f, token); } -AstNode *parse_tag_expression(Parser *p, AstNode *expression) { - Token token = expect_token(p, Token_Hash); - Token name = expect_token(p, Token_Identifier); - return make_tag_expression(p, token, name, expression); +AstNode *parse_tag_expression(AstFile *f, AstNode *expression) { + Token token = expect_token(f, Token_Hash); + Token name = expect_token(f, Token_Identifier); + return make_tag_expression(f, token, name, expression); } -AstNode *parse_tag_statement(Parser *p, AstNode *statement) { - Token token = expect_token(p, Token_Hash); - Token name = expect_token(p, Token_Identifier); - return make_tag_statement(p, token, name, statement); +AstNode *parse_tag_statement(AstFile *f, AstNode *statement) { + Token token = expect_token(f, Token_Hash); + Token name = expect_token(f, Token_Identifier); + return make_tag_statement(f, token, name, statement); } AstNode *unparen_expression(AstNode *node) { @@ -828,11 +830,11 @@ AstNode *unparen_expression(AstNode *node) { } } -AstNode *parse_atom_expression(Parser *p, b32 lhs) { +AstNode *parse_atom_expression(AstFile *f, b32 lhs) { AstNode *operand = NULL; // Operand - switch (p->cursor[0].kind) { + switch (f->cursor[0].kind) { case Token_Identifier: - operand = parse_identifier(p); + operand = parse_identifier(f); if (!lhs) { // TODO(bill): Handle? } @@ -842,29 +844,29 @@ AstNode *parse_atom_expression(Parser *p, b32 lhs) { case Token_Float: case Token_String: case Token_Rune: - operand = make_basic_literal(p, p->cursor[0]); - next_token(p); + operand = make_basic_literal(f, f->cursor[0]); + next_token(f); break; case Token_OpenParen: { Token open, close; // NOTE(bill): Skip the Paren Expression - open = expect_token(p, Token_OpenParen); - operand = parse_expression(p, false); - close = expect_token(p, Token_CloseParen); - operand = make_paren_expression(p, operand, open, close); + open = expect_token(f, Token_OpenParen); + operand = parse_expression(f, false); + close = expect_token(f, Token_CloseParen); + operand = make_paren_expression(f, operand, open, close); } break; case Token_Hash: { - operand = parse_tag_expression(p, NULL); - operand->tag_expression.expression = parse_expression(p, false); + operand = parse_tag_expression(f, NULL); + operand->tag_expression.expression = parse_expression(f, false); } break; } b32 loop = true; while (loop) { - switch (p->cursor[0].kind) { + switch (f->cursor[0].kind) { case Token_OpenParen: { if (lhs) { // TODO(bill): Handle this shit! Is this even allowed in this language?! @@ -874,43 +876,43 @@ AstNode *parse_atom_expression(Parser *p, b32 lhs) { isize arg_list_count = 0; Token open_paren, close_paren; - open_paren = expect_token(p, Token_OpenParen); + open_paren = expect_token(f, Token_OpenParen); - while (p->cursor[0].kind != Token_CloseParen && - p->cursor[0].kind != Token_EOF) { - if (p->cursor[0].kind == Token_Comma) - print_parse_error(p, p->cursor[0], "Expected an expression not a ,"); + while (f->cursor[0].kind != Token_CloseParen && + f->cursor[0].kind != Token_EOF) { + if (f->cursor[0].kind == Token_Comma) + ast_file_err(f, f->cursor[0], "Expected an expression not a ,"); - DLIST_APPEND(arg_list, arg_list_curr, parse_expression(p, false)); + DLIST_APPEND(arg_list, arg_list_curr, parse_expression(f, false)); arg_list_count++; - if (p->cursor[0].kind != Token_Comma) { - if (p->cursor[0].kind == Token_CloseParen) + if (f->cursor[0].kind != Token_Comma) { + if (f->cursor[0].kind == Token_CloseParen) break; } - next_token(p); + next_token(f); } - close_paren = expect_token(p, Token_CloseParen); + close_paren = expect_token(f, Token_CloseParen); - operand = make_call_expression(p, operand, arg_list, arg_list_count, open_paren, close_paren); + operand = make_call_expression(f, operand, arg_list, arg_list_count, open_paren, close_paren); } break; case Token_Period: { - Token token = p->cursor[0]; - next_token(p); + Token token = f->cursor[0]; + next_token(f); if (lhs) { // TODO(bill): handle this } - switch (p->cursor[0].kind) { + switch (f->cursor[0].kind) { case Token_Identifier: - operand = make_selector_expression(p, token, operand, parse_identifier(p)); + operand = make_selector_expression(f, token, operand, parse_identifier(f)); break; default: { - print_parse_error(p, p->cursor[0], "Expected a selector"); - next_token(p); - operand = make_selector_expression(p, p->cursor[0], operand, NULL); + ast_file_err(f, f->cursor[0], "Expected a selector"); + next_token(f); + operand = make_selector_expression(f, f->cursor[0], operand, NULL); } break; } } break; @@ -922,44 +924,44 @@ AstNode *parse_atom_expression(Parser *p, b32 lhs) { Token open, close; AstNode *indices[3] = {}; - open = expect_token(p, Token_OpenBracket); - if (p->cursor[0].kind != Token_Colon) - indices[0] = parse_expression(p, false); + open = expect_token(f, Token_OpenBracket); + if (f->cursor[0].kind != Token_Colon) + indices[0] = parse_expression(f, false); isize colon_count = 0; Token colons[2] = {}; - while (p->cursor[0].kind == Token_Colon && colon_count < 2) { - colons[colon_count++] = p->cursor[0]; - next_token(p); - if (p->cursor[0].kind != Token_Colon && - p->cursor[0].kind != Token_CloseBracket && - p->cursor[0].kind != Token_EOF) { - indices[colon_count] = parse_expression(p, false); + while (f->cursor[0].kind == Token_Colon && colon_count < 2) { + colons[colon_count++] = f->cursor[0]; + next_token(f); + if (f->cursor[0].kind != Token_Colon && + f->cursor[0].kind != Token_CloseBracket && + f->cursor[0].kind != Token_EOF) { + indices[colon_count] = parse_expression(f, false); } } - close = expect_token(p, Token_CloseBracket); + close = expect_token(f, Token_CloseBracket); if (colon_count == 0) { - operand = make_index_expression(p, operand, indices[0], open, close); + operand = make_index_expression(f, operand, indices[0], open, close); } else { b32 triple_indexed = false; if (colon_count == 2) { triple_indexed = true; if (indices[1] == NULL) { - print_parse_error(p, colons[0], "Second index is required in a triple indexed slice"); - indices[1] = make_bad_expression(p, colons[0], colons[1]); + ast_file_err(f, colons[0], "Second index is required in a triple indexed slice"); + indices[1] = make_bad_expression(f, colons[0], colons[1]); } if (indices[2] == NULL) { - print_parse_error(p, colons[1], "Third index is required in a triple indexed slice"); - indices[2] = make_bad_expression(p, colons[1], close); + ast_file_err(f, colons[1], "Third index is required in a triple indexed slice"); + indices[2] = make_bad_expression(f, colons[1], close); } } - operand = make_slice_expression(p, operand, open, close, indices[0], indices[1], indices[2], triple_indexed); + operand = make_slice_expression(f, operand, open, close, indices[0], indices[1], indices[2], triple_indexed); } } break; case Token_Pointer: // Deference - operand = make_dereference_expression(p, operand, expect_token(p, Token_Pointer)); + operand = make_dereference_expression(f, operand, expect_token(f, Token_Pointer)); break; default: @@ -973,77 +975,77 @@ AstNode *parse_atom_expression(Parser *p, b32 lhs) { return operand; } -AstNode *parse_type(Parser *p); +AstNode *parse_type(AstFile *f); -AstNode *parse_unary_expression(Parser *p, b32 lhs) { - switch (p->cursor[0].kind) { +AstNode *parse_unary_expression(AstFile *f, b32 lhs) { + switch (f->cursor[0].kind) { case Token_Pointer: case Token_Add: case Token_Sub: case Token_Not: case Token_Xor: { AstNode *operand; - Token op = p->cursor[0]; - next_token(p); - operand = parse_unary_expression(p, false); - return make_unary_expression(p, op, operand); + Token op = f->cursor[0]; + next_token(f); + operand = parse_unary_expression(f, false); + return make_unary_expression(f, op, operand); } break; case Token_cast: { AstNode *type_expression, *operand; - Token token = p->cursor[0]; - next_token(p); - expect_token(p, Token_OpenParen); - type_expression = parse_type(p); - expect_token(p, Token_CloseParen); - operand = parse_unary_expression(p, false); - return make_cast_expression(p, token, type_expression, operand); + Token token = f->cursor[0]; + next_token(f); + expect_token(f, Token_OpenParen); + type_expression = parse_type(f); + expect_token(f, Token_CloseParen); + operand = parse_unary_expression(f, false); + return make_cast_expression(f, token, type_expression, operand); } break; } - return parse_atom_expression(p, lhs); + return parse_atom_expression(f, lhs); } -AstNode *parse_binary_expression(Parser *p, b32 lhs, i32 prec_in) { - AstNode *expression = parse_unary_expression(p, lhs); - for (i32 prec = token_precedence(p->cursor[0]); prec >= prec_in; prec--) { +AstNode *parse_binary_expression(AstFile *f, b32 lhs, i32 prec_in) { + AstNode *expression = parse_unary_expression(f, lhs); + for (i32 prec = token_precedence(f->cursor[0]); prec >= prec_in; prec--) { for (;;) { AstNode *right; - Token op = p->cursor[0]; + Token op = f->cursor[0]; i32 op_prec = token_precedence(op); if (op_prec != prec) break; - expect_operator(p); // NOTE(bill): error checks too + expect_operator(f); // NOTE(bill): error checks too if (lhs) { // TODO(bill): error checking lhs = false; } - right = parse_binary_expression(p, false, prec+1); + right = parse_binary_expression(f, false, prec+1); if (!right) - print_parse_error(p, op, "Expected expression on the right hand side of the binary operator"); - expression = make_binary_expression(p, op, expression, right); + ast_file_err(f, op, "Expected expression on the right hand side of the binary operator"); + expression = make_binary_expression(f, op, expression, right); } } return expression; } -AstNode *parse_expression(Parser *p, b32 lhs) { - return parse_binary_expression(p, lhs, 0+1); +AstNode *parse_expression(AstFile *f, b32 lhs) { + return parse_binary_expression(f, lhs, 0+1); } -AstNode *parse_expression_list(Parser *p, b32 lhs, isize *list_count_) { +AstNode *parse_expression_list(AstFile *f, b32 lhs, isize *list_count_) { AstNode *list_root = NULL; AstNode *list_curr = NULL; isize list_count = 0; do { - DLIST_APPEND(list_root, list_curr, parse_expression(p, lhs)); + DLIST_APPEND(list_root, list_curr, parse_expression(f, lhs)); list_count++; - if (p->cursor[0].kind != Token_Comma || - p->cursor[0].kind == Token_EOF) + if (f->cursor[0].kind != Token_Comma || + f->cursor[0].kind == Token_EOF) break; - next_token(p); + next_token(f); } while (true); if (list_count_) *list_count_ = list_count; @@ -1051,22 +1053,22 @@ AstNode *parse_expression_list(Parser *p, b32 lhs, isize *list_count_) { return list_root; } -AstNode *parse_lhs_expression_list(Parser *p, isize *list_count) { - return parse_expression_list(p, true, list_count); +AstNode *parse_lhs_expression_list(AstFile *f, isize *list_count) { + return parse_expression_list(f, true, list_count); } -AstNode *parse_rhs_expression_list(Parser *p, isize *list_count) { - return parse_expression_list(p, false, list_count); +AstNode *parse_rhs_expression_list(AstFile *f, isize *list_count) { + return parse_expression_list(f, false, list_count); } -AstNode *parse_declaration(Parser *p, AstNode *name_list, isize name_list_count); +AstNode *parse_declaration(AstFile *f, AstNode *name_list, isize name_list_count); -AstNode *parse_simple_statement(Parser *p) { +AstNode *parse_simple_statement(AstFile *f) { isize lhs_count = 0, rhs_count = 0; - AstNode *lhs_expression_list = parse_lhs_expression_list(p, &lhs_count); + AstNode *lhs_expression_list = parse_lhs_expression_list(f, &lhs_count); AstNode *statement = NULL; - Token token = p->cursor[0]; + Token token = f->cursor[0]; switch (token.kind) { case Token_Eq: case Token_AddEq: @@ -1081,86 +1083,86 @@ AstNode *parse_simple_statement(Parser *p) { case Token_CmpAndEq: case Token_CmpOrEq: { - if (p->curr_scope == p->file_scope) { - print_parse_error(p, p->cursor[0], "You cannot use a simple statement in the file scope"); - return make_bad_statement(p, p->cursor[0], p->cursor[0]); + if (f->curr_scope == f->file_scope) { + ast_file_err(f, f->cursor[0], "You cannot use a simple statement in the file scope"); + return make_bad_statement(f, f->cursor[0], f->cursor[0]); } - next_token(p); - AstNode *rhs_expression_list = parse_rhs_expression_list(p, &rhs_count); + next_token(f); + AstNode *rhs_expression_list = parse_rhs_expression_list(f, &rhs_count); if (rhs_expression_list == NULL) { - print_parse_error(p, token, "No right-hand side in assignment statement."); - return make_bad_statement(p, token, p->cursor[0]); + ast_file_err(f, token, "No right-hand side in assignment statement."); + return make_bad_statement(f, token, f->cursor[0]); } - return make_assign_statement(p, token, + return make_assign_statement(f, token, lhs_expression_list, lhs_count, rhs_expression_list, rhs_count); } break; case Token_Colon: // Declare - return parse_declaration(p, lhs_expression_list, lhs_count); + return parse_declaration(f, lhs_expression_list, lhs_count); } if (lhs_count > 1) { - print_parse_error(p, token, "Expected 1 expression"); - return make_bad_statement(p, token, p->cursor[0]); + ast_file_err(f, token, "Expected 1 expression"); + return make_bad_statement(f, token, f->cursor[0]); } - token = p->cursor[0]; + token = f->cursor[0]; switch (token.kind) { case Token_Increment: case Token_Decrement: - if (p->curr_scope == p->file_scope) { - print_parse_error(p, p->cursor[0], "You cannot use a simple statement in the file scope"); - return make_bad_statement(p, p->cursor[0], p->cursor[0]); + if (f->curr_scope == f->file_scope) { + ast_file_err(f, f->cursor[0], "You cannot use a simple statement in the file scope"); + return make_bad_statement(f, f->cursor[0], f->cursor[0]); } - statement = make_inc_dec_statement(p, token, lhs_expression_list); - next_token(p); + statement = make_inc_dec_statement(f, token, lhs_expression_list); + next_token(f); return statement; } - return make_expression_statement(p, lhs_expression_list); + return make_expression_statement(f, lhs_expression_list); } -AstNode *parse_statement_list(Parser *p, isize *list_count_); -AstNode *parse_statement(Parser *p); -AstNode *parse_body(Parser *p, AstScope *scope); +AstNode *parse_statement_list(AstFile *f, isize *list_count_); +AstNode *parse_statement(AstFile *f); +AstNode *parse_body(AstFile *f, AstScope *scope); -AstNode *parse_block_statement(Parser *p) { - if (p->curr_scope == p->file_scope) { - print_parse_error(p, p->cursor[0], "You cannot use a block statement in the file scope"); - return make_bad_statement(p, p->cursor[0], p->cursor[0]); +AstNode *parse_block_statement(AstFile *f) { + if (f->curr_scope == f->file_scope) { + ast_file_err(f, f->cursor[0], "You cannot use a block statement in the file scope"); + return make_bad_statement(f, f->cursor[0], f->cursor[0]); } AstNode *block_statement; - open_ast_scope(p); - block_statement = parse_body(p, p->curr_scope); - close_ast_scope(p); + open_ast_scope(f); + block_statement = parse_body(f, f->curr_scope); + close_ast_scope(f); return block_statement; } -AstNode *convert_statement_to_expression(Parser *p, AstNode *statement, char *kind) { +AstNode *convert_statement_to_expression(AstFile *f, AstNode *statement, char *kind) { if (statement == NULL) return NULL; if (statement->kind == AstNode_ExpressionStatement) return statement->expression_statement.expression; - print_parse_error(p, p->cursor[0], "Expected `%s`, found a simple statement.", kind); - return make_bad_expression(p, p->cursor[0], p->cursor[1]); + ast_file_err(f, f->cursor[0], "Expected `%s`, found a simple statement.", kind); + return make_bad_expression(f, f->cursor[0], f->cursor[1]); } -AstNode *parse_identfier_list(Parser *p, isize *list_count_) { +AstNode *parse_identfier_list(AstFile *f, isize *list_count_) { AstNode *list_root = NULL; AstNode *list_curr = NULL; isize list_count = 0; do { - DLIST_APPEND(list_root, list_curr, parse_identifier(p)); + DLIST_APPEND(list_root, list_curr, parse_identifier(f)); list_count++; - if (p->cursor[0].kind != Token_Comma || - p->cursor[0].kind == Token_EOF) + if (f->cursor[0].kind != Token_Comma || + f->cursor[0].kind == Token_EOF) break; - next_token(p); + next_token(f); } while (true); if (list_count_) *list_count_ = list_count; @@ -1169,116 +1171,116 @@ AstNode *parse_identfier_list(Parser *p, isize *list_count_) { } -AstNode *parse_identifier_or_type(Parser *p); +AstNode *parse_identifier_or_type(AstFile *f); -AstNode *parse_type_attempt(Parser *p) { - AstNode *type = parse_identifier_or_type(p); +AstNode *parse_type_attempt(AstFile *f) { + AstNode *type = parse_identifier_or_type(f); if (type != NULL) { // TODO(bill): Handle? } return type; } -AstNode *parse_type(Parser *p) { - AstNode *type = parse_type_attempt(p); +AstNode *parse_type(AstFile *f) { + AstNode *type = parse_type_attempt(f); if (type == NULL) { - Token token = p->cursor[0]; - print_parse_error(p, token, "Expected a type"); - next_token(p); - return make_bad_expression(p, token, p->cursor[0]); + Token token = f->cursor[0]; + ast_file_err(f, token, "Expected a type"); + next_token(f); + return make_bad_expression(f, token, f->cursor[0]); } return type; } -AstNode *parse_field_declaration(Parser *p, AstScope *scope) { +AstNode *parse_field_declaration(AstFile *f, AstScope *scope) { AstNode *name_list = NULL; isize name_list_count = 0; - name_list = parse_lhs_expression_list(p, &name_list_count); + name_list = parse_lhs_expression_list(f, &name_list_count); if (name_list_count == 0) - print_parse_error(p, p->cursor[0], "Empty field declaration"); + ast_file_err(f, f->cursor[0], "Empty field declaration"); - expect_token(p, Token_Colon); + expect_token(f, Token_Colon); - AstNode *type_expression = parse_type_attempt(p); + AstNode *type_expression = parse_type_attempt(f); if (type_expression == NULL) - print_parse_error(p, p->cursor[0], "Expected a type for this field declaration"); + ast_file_err(f, f->cursor[0], "Expected a type for this field declaration"); - AstNode *field = make_field(p, name_list, name_list_count, type_expression); - add_ast_entity(p, scope, field, name_list); + AstNode *field = make_field(f, name_list, name_list_count, type_expression); + add_ast_entity(f, scope, field, name_list); return field; } -Token parse_procedure_signature(Parser *p, AstScope *scope, +Token parse_procedure_signature(AstFile *f, AstScope *scope, AstNode **param_list, isize *param_count, AstNode **result_list, isize *result_count); -AstNode *parse_procedure_type(Parser *p, AstScope **scope_) { - AstScope *scope = make_ast_scope(p, p->file_scope); // Procedure's scope +AstNode *parse_procedure_type(AstFile *f, AstScope **scope_) { + AstScope *scope = make_ast_scope(f, f->file_scope); // Procedure's scope AstNode *params = NULL; AstNode *results = NULL; isize param_count = 0; isize result_count = 0; - Token proc_token = parse_procedure_signature(p, scope, ¶ms, ¶m_count, &results, &result_count); + Token proc_token = parse_procedure_signature(f, scope, ¶ms, ¶m_count, &results, &result_count); if (scope_) *scope_ = scope; - return make_procedure_type(p, proc_token, params, param_count, results, result_count); + return make_procedure_type(f, proc_token, params, param_count, results, result_count); } -AstNode *parse_identifier_or_type(Parser *p) { - switch (p->cursor[0].kind) { +AstNode *parse_identifier_or_type(AstFile *f) { + switch (f->cursor[0].kind) { case Token_Identifier: - return parse_identifier(p); + return parse_identifier(f); case Token_Pointer: - return make_pointer_type(p, expect_token(p, Token_Pointer), parse_type(p)); + return make_pointer_type(f, expect_token(f, Token_Pointer), parse_type(f)); case Token_OpenBracket: { - Token token = expect_token(p, Token_OpenBracket); + Token token = expect_token(f, Token_OpenBracket); AstNode *count_expression = NULL; - if (p->cursor[0].kind != Token_CloseBracket) - count_expression = parse_expression(p, false); - expect_token(p, Token_CloseBracket); - return make_array_type(p, token, count_expression, parse_type(p)); + if (f->cursor[0].kind != Token_CloseBracket) + count_expression = parse_expression(f, false); + expect_token(f, Token_CloseBracket); + return make_array_type(f, token, count_expression, parse_type(f)); } case Token_struct: { - Token token = expect_token(p, Token_struct); + Token token = expect_token(f, Token_struct); Token open, close; AstNode *field_list = NULL; AstNode *field_list_curr = NULL; isize field_list_count = 0; - open = expect_token(p, Token_OpenBrace); + open = expect_token(f, Token_OpenBrace); - AstScope *scope = make_ast_scope(p, NULL); // NOTE(bill): The struct needs its own scope with NO parent - while (p->cursor[0].kind == Token_Identifier || - p->cursor[0].kind == Token_Mul) { - DLIST_APPEND(field_list, field_list_curr, parse_field_declaration(p, scope)); - expect_token(p, Token_Semicolon); + AstScope *scope = make_ast_scope(f, NULL); // NOTE(bill): The struct needs its own scope with NO parent + while (f->cursor[0].kind == Token_Identifier || + f->cursor[0].kind == Token_Mul) { + DLIST_APPEND(field_list, field_list_curr, parse_field_declaration(f, scope)); + expect_token(f, Token_Semicolon); field_list_count++; } destroy_ast_scope(scope); - close = expect_token(p, Token_CloseBrace); + close = expect_token(f, Token_CloseBrace); - return make_struct_type(p, token, field_list, field_list_count); + return make_struct_type(f, token, field_list, field_list_count); } case Token_proc: - return parse_procedure_type(p, NULL); + return parse_procedure_type(f, NULL); case Token_OpenParen: { // NOTE(bill): Skip the paren expression AstNode *type_expression; Token open, close; - open = expect_token(p, Token_OpenParen); - type_expression = parse_type(p); - close = expect_token(p, Token_CloseParen); - return make_paren_expression(p, type_expression, open, close); + open = expect_token(f, Token_OpenParen); + type_expression = parse_type(f); + close = expect_token(f, Token_CloseParen); + return make_paren_expression(f, type_expression, open, close); } case Token_Colon: @@ -1286,55 +1288,55 @@ AstNode *parse_identifier_or_type(Parser *p) { break; default: - print_parse_error(p, p->cursor[0], - "Expected a type after `%.*s`, got `%.*s`", LIT(p->cursor[-1].string), LIT(p->cursor[0].string)); + ast_file_err(f, f->cursor[0], + "Expected a type after `%.*s`, got `%.*s`", LIT(f->cursor[-1].string), LIT(f->cursor[0].string)); break; } return NULL; } -AstNode *parse_parameters(Parser *p, AstScope *scope, isize *param_count_) { +AstNode *parse_parameters(AstFile *f, AstScope *scope, isize *param_count_) { AstNode *param_list = NULL; AstNode *param_list_curr = NULL; isize param_count = 0; - expect_token(p, Token_OpenParen); - while (p->cursor[0].kind != Token_CloseParen) { - AstNode *field = parse_field_declaration(p, scope); + expect_token(f, Token_OpenParen); + while (f->cursor[0].kind != Token_CloseParen) { + AstNode *field = parse_field_declaration(f, scope); DLIST_APPEND(param_list, param_list_curr, field); param_count += field->field.name_list_count; - if (p->cursor[0].kind != Token_Comma) + if (f->cursor[0].kind != Token_Comma) break; - next_token(p); + next_token(f); } - expect_token(p, Token_CloseParen); + expect_token(f, Token_CloseParen); if (param_count_) *param_count_ = param_count; return param_list; } -AstNode *parse_results(Parser *p, AstScope *scope, isize *result_count) { - if (allow_token(p, Token_ArrowRight)) { - if (p->cursor[0].kind == Token_OpenParen) { - expect_token(p, Token_OpenParen); +AstNode *parse_results(AstFile *f, AstScope *scope, isize *result_count) { + if (allow_token(f, Token_ArrowRight)) { + if (f->cursor[0].kind == Token_OpenParen) { + expect_token(f, Token_OpenParen); AstNode *list = NULL; AstNode *list_curr = NULL; isize count = 0; - while (p->cursor[0].kind != Token_CloseParen && - p->cursor[0].kind != Token_EOF) { - DLIST_APPEND(list, list_curr, parse_type(p)); + while (f->cursor[0].kind != Token_CloseParen && + f->cursor[0].kind != Token_EOF) { + DLIST_APPEND(list, list_curr, parse_type(f)); count++; - if (p->cursor[0].kind != Token_Comma) + if (f->cursor[0].kind != Token_Comma) break; - next_token(p); + next_token(f); } - expect_token(p, Token_CloseParen); + expect_token(f, Token_CloseParen); if (result_count) *result_count = count; return list; } - AstNode *result = parse_type(p); + AstNode *result = parse_type(f); if (result_count) *result_count = 1; return result; } @@ -1342,258 +1344,270 @@ AstNode *parse_results(Parser *p, AstScope *scope, isize *result_count) { return NULL; } -Token parse_procedure_signature(Parser *p, AstScope *scope, +Token parse_procedure_signature(AstFile *f, AstScope *scope, AstNode **param_list, isize *param_count, AstNode **result_list, isize *result_count) { - Token proc_token = expect_token(p, Token_proc); - *param_list = parse_parameters(p, scope, param_count); - *result_list = parse_results(p, scope, result_count); + Token proc_token = expect_token(f, Token_proc); + *param_list = parse_parameters(f, scope, param_count); + *result_list = parse_results(f, scope, result_count); return proc_token; } -AstNode *parse_body(Parser *p, AstScope *scope) { +AstNode *parse_body(AstFile *f, AstScope *scope) { AstNode *statement_list = NULL; isize statement_list_count = 0; Token open, close; - open = expect_token(p, Token_OpenBrace); - statement_list = parse_statement_list(p, &statement_list_count); - close = expect_token(p, Token_CloseBrace); + open = expect_token(f, Token_OpenBrace); + statement_list = parse_statement_list(f, &statement_list_count); + close = expect_token(f, Token_CloseBrace); - return make_block_statement(p, statement_list, statement_list_count, open, close); + return make_block_statement(f, statement_list, statement_list_count, open, close); } -AstNode *parse_procedure_declaration(Parser *p, Token proc_token, AstNode *name, DeclarationKind kind) { +AstNode *parse_procedure_declaration(AstFile *f, Token proc_token, AstNode *name, DeclarationKind kind) { AstNode *param_list = NULL; AstNode *result_list = NULL; isize param_count = 0; isize result_count = 0; - AstScope *scope = open_ast_scope(p); + AstScope *scope = open_ast_scope(f); - parse_procedure_signature(p, scope, ¶m_list, ¶m_count, &result_list, &result_count); + parse_procedure_signature(f, scope, ¶m_list, ¶m_count, &result_list, &result_count); AstNode *body = NULL; AstNode *tag_list = NULL; AstNode *tag_list_curr = NULL; isize tag_count = 0; - while (p->cursor[0].kind == Token_Hash) { - DLIST_APPEND(tag_list, tag_list_curr, parse_tag_expression(p, NULL)); + while (f->cursor[0].kind == Token_Hash) { + DLIST_APPEND(tag_list, tag_list_curr, parse_tag_expression(f, NULL)); tag_count++; } - if (p->cursor[0].kind == Token_OpenBrace) { - body = parse_body(p, scope); + if (f->cursor[0].kind == Token_OpenBrace) { + body = parse_body(f, scope); } - close_ast_scope(p); + close_ast_scope(f); - AstNode *proc_type = make_procedure_type(p, proc_token, param_list, param_count, result_list, result_count); - return make_procedure_declaration(p, kind, name, proc_type, body, tag_list, tag_count); + AstNode *proc_type = make_procedure_type(f, proc_token, param_list, param_count, result_list, result_count); + return make_procedure_declaration(f, kind, name, proc_type, body, tag_list, tag_count); } -AstNode *parse_declaration(Parser *p, AstNode *name_list, isize name_list_count) { +AstNode *parse_declaration(AstFile *f, AstNode *name_list, isize name_list_count) { AstNode *value_list = NULL; AstNode *type_expression = NULL; isize value_list_count = 0; - if (allow_token(p, Token_Colon)) { - type_expression = parse_identifier_or_type(p); - } else if (p->cursor[0].kind != Token_Eq && p->cursor[0].kind != Token_Semicolon) { - print_parse_error(p, p->cursor[0], "Expected type separator `:` or `=`"); + if (allow_token(f, Token_Colon)) { + type_expression = parse_identifier_or_type(f); + } else if (f->cursor[0].kind != Token_Eq && f->cursor[0].kind != Token_Semicolon) { + ast_file_err(f, f->cursor[0], "Expected type separator `:` or `=`"); } DeclarationKind declaration_kind = Declaration_Mutable; - if (p->cursor[0].kind == Token_Eq || - p->cursor[0].kind == Token_Colon) { - if (p->cursor[0].kind == Token_Colon) + if (f->cursor[0].kind == Token_Eq || + f->cursor[0].kind == Token_Colon) { + if (f->cursor[0].kind == Token_Colon) declaration_kind = Declaration_Immutable; - next_token(p); + next_token(f); - if (p->cursor[0].kind == Token_proc) { // NOTE(bill): Procedure declarations - Token proc_token = p->cursor[0]; + if (f->cursor[0].kind == Token_proc) { // NOTE(bill): Procedure declarations + Token proc_token = f->cursor[0]; AstNode *name = name_list; if (name_list_count != 1) { - print_parse_error(p, proc_token, "You can only declare one procedure at a time (at the moment)"); - return make_bad_declaration(p, name->identifier.token, proc_token); + ast_file_err(f, proc_token, "You can only declare one procedure at a time (at the moment)"); + return make_bad_declaration(f, name->identifier.token, proc_token); } // TODO(bill): Allow for mutable procedures if (declaration_kind != Declaration_Immutable) { - print_parse_error(p, proc_token, "Only immutable procedures are supported (at the moment)"); - return make_bad_declaration(p, name->identifier.token, proc_token); + ast_file_err(f, proc_token, "Only immutable procedures are supported (at the moment)"); + return make_bad_declaration(f, name->identifier.token, proc_token); } - AstNode *procedure_declaration = parse_procedure_declaration(p, proc_token, name, declaration_kind); - add_ast_entity(p, p->curr_scope, procedure_declaration, name_list); + AstNode *procedure_declaration = parse_procedure_declaration(f, proc_token, name, declaration_kind); + add_ast_entity(f, f->curr_scope, procedure_declaration, name_list); return procedure_declaration; } else { - value_list = parse_rhs_expression_list(p, &value_list_count); + value_list = parse_rhs_expression_list(f, &value_list_count); if (value_list_count > name_list_count) { - print_parse_error(p, p->cursor[0], "Too many values on the right hand side of the declaration"); + ast_file_err(f, f->cursor[0], "Too many values on the right hand side of the declaration"); } else if (value_list_count < name_list_count && declaration_kind == Declaration_Immutable) { - print_parse_error(p, p->cursor[0], "All constant declarations must be defined"); + ast_file_err(f, f->cursor[0], "All constant declarations must be defined"); } else if (value_list == NULL) { - print_parse_error(p, p->cursor[0], "Expected an expression for this declaration"); + ast_file_err(f, f->cursor[0], "Expected an expression for this declaration"); } } } if (declaration_kind == Declaration_Mutable) { if (type_expression == NULL && value_list == NULL) { - print_parse_error(p, p->cursor[0], "Missing variable type or initialization"); - return make_bad_declaration(p, p->cursor[0], p->cursor[0]); + ast_file_err(f, f->cursor[0], "Missing variable type or initialization"); + return make_bad_declaration(f, f->cursor[0], f->cursor[0]); } } else if (declaration_kind == Declaration_Immutable) { if (type_expression == NULL && value_list == NULL && name_list_count > 0) { - print_parse_error(p, p->cursor[0], "Missing constant value"); - return make_bad_declaration(p, p->cursor[0], p->cursor[0]); + ast_file_err(f, f->cursor[0], "Missing constant value"); + return make_bad_declaration(f, f->cursor[0], f->cursor[0]); } } else { - print_parse_error(p, p->cursor[0], "Unknown type of variable declaration"); - return make_bad_declaration(p, p->cursor[0], p->cursor[0]); + ast_file_err(f, f->cursor[0], "Unknown type of variable declaration"); + return make_bad_declaration(f, f->cursor[0], f->cursor[0]); } - AstNode *variable_declaration = make_variable_declaration(p, declaration_kind, name_list, name_list_count, type_expression, value_list, value_list_count); - add_ast_entity(p, p->curr_scope, variable_declaration, name_list); + AstNode *variable_declaration = make_variable_declaration(f, declaration_kind, name_list, name_list_count, type_expression, value_list, value_list_count); + add_ast_entity(f, f->curr_scope, variable_declaration, name_list); return variable_declaration; } -AstNode *parse_if_statement(Parser *p) { - if (p->curr_scope == p->file_scope) { - print_parse_error(p, p->cursor[0], "You cannot use an if statement in the file scope"); - return make_bad_statement(p, p->cursor[0], p->cursor[0]); +AstNode *parse_if_statement(AstFile *f) { + if (f->curr_scope == f->file_scope) { + ast_file_err(f, f->cursor[0], "You cannot use an if statement in the file scope"); + return make_bad_statement(f, f->cursor[0], f->cursor[0]); } - Token token = expect_token(p, Token_if); + Token token = expect_token(f, Token_if); AstNode *cond, *body, *else_statement; - open_ast_scope(p); + open_ast_scope(f); - cond = convert_statement_to_expression(p, parse_simple_statement(p), "boolean expression"); + cond = convert_statement_to_expression(f, parse_simple_statement(f), "boolean expression"); if (cond == NULL) { - print_parse_error(p, p->cursor[0], "Expected condition for if statement"); + ast_file_err(f, f->cursor[0], "Expected condition for if statement"); } - body = parse_block_statement(p); + body = parse_block_statement(f); else_statement = NULL; - if (allow_token(p, Token_else)) { - switch (p->cursor[0].kind) { + if (allow_token(f, Token_else)) { + switch (f->cursor[0].kind) { case Token_if: - else_statement = parse_if_statement(p); + else_statement = parse_if_statement(f); break; case Token_OpenBrace: - else_statement = parse_block_statement(p); + else_statement = parse_block_statement(f); break; default: - print_parse_error(p, p->cursor[0], "Expected if statement block statement"); - else_statement = make_bad_statement(p, p->cursor[0], p->cursor[1]); + ast_file_err(f, f->cursor[0], "Expected if statement block statement"); + else_statement = make_bad_statement(f, f->cursor[0], f->cursor[1]); break; } } - close_ast_scope(p); - return make_if_statement(p, token, cond, body, else_statement); + close_ast_scope(f); + return make_if_statement(f, token, cond, body, else_statement); } -AstNode *parse_return_statement(Parser *p) { - if (p->curr_scope == p->file_scope) { - print_parse_error(p, p->cursor[0], "You cannot use a return statement in the file scope"); - return make_bad_statement(p, p->cursor[0], p->cursor[0]); +AstNode *parse_return_statement(AstFile *f) { + if (f->curr_scope == f->file_scope) { + ast_file_err(f, f->cursor[0], "You cannot use a return statement in the file scope"); + return make_bad_statement(f, f->cursor[0], f->cursor[0]); } - Token token = expect_token(p, Token_return); + Token token = expect_token(f, Token_return); AstNode *result = NULL; isize result_count = 0; - if (p->cursor[0].kind != Token_Semicolon) - result = parse_rhs_expression_list(p, &result_count); - expect_token(p, Token_Semicolon); + if (f->cursor[0].kind != Token_Semicolon) + result = parse_rhs_expression_list(f, &result_count); + expect_token(f, Token_Semicolon); - return make_return_statement(p, token, result, result_count); + return make_return_statement(f, token, result, result_count); } -AstNode *parse_for_statement(Parser *p) { - if (p->curr_scope == p->file_scope) { - print_parse_error(p, p->cursor[0], "You cannot use a for statement in the file scope"); - return make_bad_statement(p, p->cursor[0], p->cursor[0]); +AstNode *parse_for_statement(AstFile *f) { + if (f->curr_scope == f->file_scope) { + ast_file_err(f, f->cursor[0], "You cannot use a for statement in the file scope"); + return make_bad_statement(f, f->cursor[0], f->cursor[0]); } - Token token = expect_token(p, Token_for); - open_ast_scope(p); + Token token = expect_token(f, Token_for); + open_ast_scope(f); AstNode *init_statement = NULL, *cond = NULL, *end_statement = NULL, *body = NULL; - if (p->cursor[0].kind != Token_OpenBrace) { - cond = parse_simple_statement(p); + if (f->cursor[0].kind != Token_OpenBrace) { + cond = parse_simple_statement(f); if (is_ast_node_complex_statement(cond)) { - print_parse_error(p, p->cursor[0], - "You are not allowed that type of statement in a for statement, it's too complex!"); + ast_file_err(f, f->cursor[0], + "You are not allowed that type of statement in a for statement, it's too complex!"); } - if (allow_token(p, Token_Semicolon)) { + if (allow_token(f, Token_Semicolon)) { init_statement = cond; cond = NULL; - if (p->cursor[0].kind != Token_Semicolon) { - cond = parse_simple_statement(p); + if (f->cursor[0].kind != Token_Semicolon) { + cond = parse_simple_statement(f); } - expect_token(p, Token_Semicolon); - if (p->cursor[0].kind != Token_OpenBrace) { - end_statement = parse_simple_statement(p); + expect_token(f, Token_Semicolon); + if (f->cursor[0].kind != Token_OpenBrace) { + end_statement = parse_simple_statement(f); } } } - body = parse_block_statement(p); + body = parse_block_statement(f); - close_ast_scope(p); + close_ast_scope(f); - return make_for_statement(p, token, init_statement, cond, end_statement, body); + return make_for_statement(f, token, init_statement, cond, end_statement, body); } -AstNode *parse_defer_statement(Parser *p) { - if (p->curr_scope == p->file_scope) { - print_parse_error(p, p->cursor[0], "You cannot use a defer statement in the file scope"); - return make_bad_statement(p, p->cursor[0], p->cursor[0]); +AstNode *parse_defer_statement(AstFile *f) { + if (f->curr_scope == f->file_scope) { + ast_file_err(f, f->cursor[0], "You cannot use a defer statement in the file scope"); + return make_bad_statement(f, f->cursor[0], f->cursor[0]); } - Token token = expect_token(p, Token_defer); - AstNode *statement = parse_statement(p); + Token token = expect_token(f, Token_defer); + AstNode *statement = parse_statement(f); switch (statement->kind) { case AstNode_EmptyStatement: - print_parse_error(p, token, "Empty statement after defer (e.g. `;`)"); + ast_file_err(f, token, "Empty statement after defer (e.g. `;`)"); break; case AstNode_DeferStatement: - print_parse_error(p, token, "You cannot defer a defer statement"); + ast_file_err(f, token, "You cannot defer a defer statement"); break; case AstNode_ReturnStatement: - print_parse_error(p, token, "You cannot a return statement"); + ast_file_err(f, token, "You cannot a return statement"); break; } - return make_defer_statement(p, token, statement); + return make_defer_statement(f, token, statement); } -AstNode *parse_type_declaration(Parser *p) { - Token token = expect_token(p, Token_type); - AstNode *name = parse_identifier(p); - expect_token(p, Token_Colon); - AstNode *type_expression = parse_type(p); +AstNode *parse_type_declaration(AstFile *f) { + Token token = expect_token(f, Token_type); + AstNode *name = parse_identifier(f); + expect_token(f, Token_Colon); + AstNode *type_expression = parse_type(f); - AstNode *type_declaration = make_type_declaration(p, token, name, type_expression); + AstNode *type_declaration = make_type_declaration(f, token, name, type_expression); if (type_expression->kind != AstNode_StructType && type_expression->kind != AstNode_ProcedureType) - expect_token(p, Token_Semicolon); + expect_token(f, Token_Semicolon); return type_declaration; } -AstNode *parse_statement(Parser *p) { +AstNode *parse_import_declaration(AstFile *f) { + Token token = expect_token(f, Token_import); + Token filepath = expect_token(f, Token_String); + if (f->curr_scope == f->file_scope) { + return make_import_declaration(f, token, filepath); + } + ast_file_err(f, token, "You cannot `import` within a procedure. This must be done at the file scope."); + return make_bad_declaration(f, token, filepath); +} + +AstNode *parse_statement(AstFile *f) { AstNode *s = NULL; - Token token = p->cursor[0]; + Token token = f->cursor[0]; switch (token.kind) { case Token_type: - return parse_type_declaration(p); + return parse_type_declaration(f); + case Token_import: + return parse_import_declaration(f); // Operands case Token_Identifier: @@ -1607,46 +1621,46 @@ AstNode *parse_statement(Parser *p) { case Token_Sub: case Token_Xor: case Token_Not: - s = parse_simple_statement(p); - if (s->kind != AstNode_ProcedureDeclaration && !allow_token(p, Token_Semicolon)) { - print_parse_error(p, p->cursor[0], "Expected `;` after statement, got `%s`", token_kind_to_string(p->cursor[0].kind)); + s = parse_simple_statement(f); + if (s->kind != AstNode_ProcedureDeclaration && !allow_token(f, Token_Semicolon)) { + ast_file_err(f, f->cursor[0], "Expected `;` after statement, got `%s`", token_kind_to_string(f->cursor[0].kind)); } return s; // TODO(bill): other keywords - case Token_if: return parse_if_statement(p); - case Token_return: return parse_return_statement(p); - case Token_for: return parse_for_statement(p); - case Token_defer: return parse_defer_statement(p); + case Token_if: return parse_if_statement(f); + case Token_return: return parse_return_statement(f); + case Token_for: return parse_for_statement(f); + case Token_defer: return parse_defer_statement(f); // case Token_match: // case Token_case: case Token_Hash: - s = parse_tag_statement(p, NULL); - s->tag_statement.statement = parse_statement(p); // TODO(bill): Find out why this doesn't work as an argument + s = parse_tag_statement(f, NULL); + s->tag_statement.statement = parse_statement(f); // TODO(bill): Find out why this doesn't work as an argument return s; - case Token_OpenBrace: return parse_block_statement(p); + case Token_OpenBrace: return parse_block_statement(f); case Token_Semicolon: - s = make_empty_statement(p, token); - next_token(p); + s = make_empty_statement(f, token); + next_token(f); return s; } - print_parse_error(p, token, "Expected a statement, got `%s`", token_kind_to_string(token.kind)); - return make_bad_statement(p, token, p->cursor[0]); + ast_file_err(f, token, "Expected a statement, got `%s`", token_kind_to_string(token.kind)); + return make_bad_statement(f, token, f->cursor[0]); } -AstNode *parse_statement_list(Parser *p, isize *list_count_) { +AstNode *parse_statement_list(AstFile *f, isize *list_count_) { AstNode *list_root = NULL; AstNode *list_curr = NULL; isize list_count = 0; - while (p->cursor[0].kind != Token_case && - p->cursor[0].kind != Token_CloseBrace && - p->cursor[0].kind != Token_EOF) { - DLIST_APPEND(list_root, list_curr, parse_statement(p)); + while (f->cursor[0].kind != Token_case && + f->cursor[0].kind != Token_CloseBrace && + f->cursor[0].kind != Token_EOF) { + DLIST_APPEND(list_root, list_curr, parse_statement(f)); list_count++; } @@ -1654,3 +1668,148 @@ AstNode *parse_statement_list(Parser *p, isize *list_count_) { return list_root; } + + +// void parse_file(AstFile *f, ) + + +b32 init_ast_file(AstFile *f, String fullpath) { + if (init_tokenizer(&f->tokenizer, fullpath)) { + gb_array_init(f->tokens, gb_heap_allocator()); + for (;;) { + Token token = tokenizer_get_token(&f->tokenizer); + if (token.kind == Token_Invalid) + return false; + gb_array_append(f->tokens, token); + + if (token.kind == Token_EOF) + break; + } + + f->cursor = &f->tokens[0]; + + // NOTE(bill): Is this big enough or too small? + isize arena_size = gb_max(gb_size_of(AstNode), gb_size_of(AstScope)); + arena_size *= 2*gb_array_count(f->tokens); + gb_arena_init_from_allocator(&f->arena, gb_heap_allocator(), arena_size); + + open_ast_scope(f); + f->file_scope = f->curr_scope; + + return true; + } + return false; +} + +void destroy_ast_file(AstFile *f) { + close_ast_scope(f); + gb_arena_free(&f->arena); + gb_array_free(f->tokens); + gb_free(gb_heap_allocator(), f->tokenizer.fullpath.text); + destroy_tokenizer(&f->tokenizer); +} + +b32 init_parser(Parser *p) { + gb_array_init(p->files, gb_heap_allocator()); + gb_array_init(p->imports, gb_heap_allocator()); + return true; +} + +void destroy_parser(Parser *p) { +#if 0 + // TODO(bill): Fix memory leak + for (isize i = 0; i < gb_array_count(p->files); i++) { + destroy_ast_file(&p->files[i]); + } + for (isize i = 0; i < gb_array_count(p->imports); i++) { + // gb_free(gb_heap_allocator(), p->imports[i].text); + } + gb_array_free(p->files); + gb_array_free(p->imports); +#endif +} + +// NOTE(bill): Returns true if it's added +b32 try_add_import_path(Parser *p, String import_file) { + for (isize i = 0; i < gb_array_count(p->imports); i++) { + String import = p->imports[i]; + if (are_strings_equal(import, import_file)) { + return false; + } + } + + gb_array_append(p->imports, import_file); + return true; +} + + +void parse_file(Parser *p, AstFile *f) { + f->declarations = parse_statement_list(f, &f->declaration_count); + + String filepath = f->tokenizer.fullpath; + String base_dir = filepath; + for (isize i = filepath.len-1; i >= 0; i--) { + if (base_dir.text[i] == GB_PATH_SEPARATOR) + break; + base_dir.len--; + } + + for (AstNode *node = f->declarations; node != NULL; node = node->next) { + if (!is_ast_node_declaration(node)) { + // NOTE(bill): Sanity check + ast_file_err(f, ast_node_token(node), "Only declarations are allowed at file scope"); + } else { + if (node->kind == AstNode_ImportDeclaration) { + auto *id = &node->import_declaration; + String file = id->filepath.string; + String file_str = {}; + if (file.text[0] == '"') + file_str = make_string(file.text+1, file.len-2); + + char ext[] = ".odin"; + isize ext_len = gb_size_of(ext)-1; + if (file_str.len > ext_len) { + if (gb_memcompare(file_str.text+file_str.len-ext_len, ext, ext_len) == 0) { + file_str.len -= ext_len; + } + } + + isize str_len = base_dir.len + file_str.len + ext_len; + u8 *str = gb_alloc_array(gb_heap_allocator(), u8, str_len+1); + defer (gb_free(gb_heap_allocator(), str)); + + gb_memcopy(str, base_dir.text, base_dir.len); + gb_memcopy(str+base_dir.len, file_str.text, file_str.len); + gb_memcopy(str+base_dir.len+file_str.len, ext, ext_len+1); + str[str_len] = '\0'; + char *path_str = gb_path_get_full_name(gb_heap_allocator(), cast(char *)str); + String import_file = make_string(path_str); + + if (!try_add_import_path(p, import_file)) { + gb_free(gb_heap_allocator(), import_file.text); + } + } + } + } +} + + +void parse_files(Parser *p, char *init_filename) { + char *fullpath_str = gb_path_get_full_name(gb_heap_allocator(), init_filename); + String init_fullpath = make_string(fullpath_str); + gb_array_append(p->imports, init_fullpath); + + for (isize i = 0; i < gb_array_count(p->imports); i++) { + String import_path = p->imports[i]; + AstFile file = {}; + b32 ok = init_ast_file(&file, import_path); + if (!ok) { + gb_printf_err("Failed to parse file: %.*s", LIT(import_path)); + return; + } + parse_file(p, &file); + gb_array_append(p->files, file); + } +} + + diff --git a/src/test.odin b/src/test.odin deleted file mode 100644 index 0ea81d86c..000000000 --- a/src/test.odin +++ /dev/null @@ -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; -} - diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index f077f687f..4edf8ab1d 100644 --- a/src/tokenizer.cpp +++ b/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; } diff --git a/todo.md b/todo.md index 5b27af36e..c7caf08cf 100644 --- a/todo.md +++ b/todo.md @@ -1,100 +1,31 @@ -# Odin Language Features +# Todo -* 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? +## Tokenizer +* Unicode character category check - Letters, Digits +* Extra operators + - << and <<= + - >> and >>= +## Parser +* Extra checking here rather than in the checker +* Mulitple files -## Basic Types -bool - true|false - - register size or variable size? +## 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 -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); -} +## Codegen +* Begin!!! +* Emit LLVM-IR using custom library +* Debug info +## Command Line Tool +* Begin!!! +* Choose/determine architecture