aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <ginger.bill.22@gmail.com>2016-07-21 00:26:14 +0100
committergingerBill <ginger.bill.22@gmail.com>2016-07-21 00:26:14 +0100
commitcbd82e3c02cbeff8fe3ba5198d6ca730f8c1eace (patch)
tree00728d59925609e8fd081f5276e8b26117ec00e3 /src
parentaa6a2caecb759522914ba82cc506e60270ad1ab0 (diff)
Support import files as modules (i.e. import only once)
Diffstat (limited to 'src')
-rw-r--r--src/checker/checker.cpp334
-rw-r--r--src/checker/entity.cpp4
-rw-r--r--src/checker/expression.cpp712
-rw-r--r--src/checker/statements.cpp115
-rw-r--r--src/checker/type.cpp4
-rw-r--r--src/exact_value.cpp (renamed from src/checker/value.cpp)206
-rw-r--r--src/gb/gb.h7
-rw-r--r--src/generator.cpp82
-rw-r--r--src/main.cpp24
-rw-r--r--src/parser.cpp1181
-rw-r--r--src/test.odin26
-rw-r--r--src/tokenizer.cpp44
12 files changed, 1397 insertions, 1342 deletions
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<ExpressionInfo> untyped; // Key: AstNode * | Expression -> ExpressionInfo
Map<DeclarationInfo *> entities; // Key: Entity *
+ AstFile * curr_ast_file;
BaseTypeSizes sizes;
- Scope * file_scope;
+ Scope * global_scope;
gbArray(ProcedureInfo) procedures; // NOTE(bill): Procedures to check
gbArena arena;
@@ -168,21 +175,20 @@ struct Checker {
gbArray(Type *) procedure_stack;
b32 in_defer; // TODO(bill): Actually handle correctly
-#define MAX_CHECKER_ERROR_COUNT 10
isize error_prev_line;
isize error_prev_column;
isize error_count;
};
-gb_global Scope *global_scope = NULL;
+gb_global Scope *universal_scope = NULL;
Scope *make_scope(Scope *parent, gbAllocator allocator) {
Scope *s = gb_alloc_item(allocator, Scope);
s->parent = parent;
map_init(&s->elements, gb_heap_allocator());
- if (parent != NULL && parent != global_scope) {
+ if (parent != NULL && parent != universal_scope) {
DLIST_APPEND(parent->first_child, parent->last_child, s);
}
return s;
@@ -258,12 +264,12 @@ void add_global_entity(Entity *entity) {
if (gb_memchr(name.text, ' ', name.len)) {
return; // NOTE(bill): `untyped thing`
}
- if (scope_insert_entity(global_scope, entity)) {
+ if (scope_insert_entity(universal_scope, entity)) {
GB_PANIC("Compiler error: double declaration");
}
}
-void add_global_constant(gbAllocator a, String name, Type *type, Value value) {
+void add_global_constant(gbAllocator a, String name, Type *type, ExactValue value) {
Token token = {Token_Identifier};
token.string = name;
Entity *entity = alloc_entity(a, Entity_Constant, NULL, token, type);
@@ -271,10 +277,10 @@ void add_global_constant(gbAllocator a, String name, Type *type, Value value) {
add_global_entity(entity);
}
-void init_global_scope(void) {
+void init_universal_scope(void) {
// NOTE(bill): No need to free these
gbAllocator a = gb_heap_allocator();
- global_scope = make_scope(NULL, a);
+ universal_scope = make_scope(NULL, a);
// Types
for (isize i = 0; i < gb_count_of(basic_types); i++) {
@@ -289,9 +295,9 @@ void init_global_scope(void) {
}
// Constants
- add_global_constant(a, make_string("true"), &basic_types[Basic_UntypedBool], make_value_bool(true));
- add_global_constant(a, make_string("false"), &basic_types[Basic_UntypedBool], make_value_bool(false));
- add_global_constant(a, make_string("null"), &basic_types[Basic_UntypedPointer], make_value_pointer(NULL));
+ add_global_constant(a, make_string("true"), &basic_types[Basic_UntypedBool], make_exact_value_bool(true));
+ add_global_constant(a, make_string("false"), &basic_types[Basic_UntypedBool], make_exact_value_bool(false));
+ add_global_constant(a, make_string("null"), &basic_types[Basic_UntypedPointer], make_exact_value_pointer(NULL));
// Builtin Procedures
for (isize i = 0; i < gb_count_of(builtin_procedures); i++) {
@@ -329,12 +335,17 @@ void init_checker(Checker *c, Parser *parser) {
// NOTE(bill): Is this big enough or too small?
isize item_size = gb_max(gb_max(gb_size_of(Entity), gb_size_of(Type)), gb_size_of(Scope));
- isize arena_size = 2 * item_size * gb_array_count(c->parser->tokens);
+ isize total_token_count = 0;
+ for (isize i = 0; i < gb_array_count(c->parser->files); i++) {
+ AstFile *f = &c->parser->files[i];
+ total_token_count += gb_array_count(f->tokens);
+ }
+ isize arena_size = 2 * item_size * total_token_count;
gb_arena_init_from_allocator(&c->arena, a, arena_size);
c->allocator = gb_arena_allocator(&c->arena);
- c->file_scope = make_scope(global_scope, c->allocator);
- c->curr_scope = c->file_scope;
+ c->global_scope = make_scope(universal_scope, c->allocator);
+ c->curr_scope = c->global_scope;
}
void destroy_checker(Checker *c) {
@@ -344,7 +355,7 @@ void destroy_checker(Checker *c) {
map_destroy(&c->scopes);
map_destroy(&c->untyped);
map_destroy(&c->entities);
- destroy_scope(c->file_scope);
+ destroy_scope(c->global_scope);
gb_array_free(c->procedure_stack);
gb_array_free(c->procedures);
@@ -353,8 +364,8 @@ void destroy_checker(Checker *c) {
-#define print_checker_error(p, token, fmt, ...) print_checker_error_(p, __FUNCTION__, token, fmt, ##__VA_ARGS__)
-void print_checker_error_(Checker *c, char *function, Token token, char *fmt, ...) {
+#define checker_err(p, token, fmt, ...) checker_err_(p, __FUNCTION__, token, fmt, ##__VA_ARGS__)
+void checker_err_(Checker *c, char *function, Token token, char *fmt, ...) {
// NOTE(bill): Duplicate error, skip it
@@ -368,20 +379,20 @@ void print_checker_error_(Checker *c, char *function, Token token, char *fmt, ..
va_list va;
va_start(va, fmt);
- gb_printf_err("%s(%td:%td) %s\n",
- c->parser->tokenizer.fullpath, token.line, token.column,
+ gb_printf_err("%.*s(%td:%td) %s\n",
+ LIT(c->curr_ast_file->tokenizer.fullpath), token.line, token.column,
gb_bprintf_va(fmt, va));
va_end(va);
}
c->error_count++;
// NOTE(bill): If there are too many errors, just quit
- if (c->error_count > MAX_CHECKER_ERROR_COUNT) {
- gb_exit(1);
- return;
- }
}
+TypeAndValue *type_and_value_of_expression(Checker *c, AstNode *expression) {
+ TypeAndValue *found = map_get(&c->types, hash_pointer(expression));
+ return found;
+}
Entity *entity_of_identifier(Checker *c, AstNode *identifier) {
@@ -397,7 +408,7 @@ Entity *entity_of_identifier(Checker *c, AstNode *identifier) {
}
Type *type_of_expression(Checker *c, AstNode *expression) {
- TypeAndValue *found = map_get(&c->types, hash_pointer(expression));
+ TypeAndValue *found = type_and_value_of_expression(c, expression);
if (found)
return found->type;
if (expression->kind == AstNode_Identifier) {
@@ -410,19 +421,19 @@ Type *type_of_expression(Checker *c, AstNode *expression) {
}
-void add_untyped(Checker *c, AstNode *expression, b32 lhs, AddressingMode mode, Type *basic_type, Value value) {
+void add_untyped(Checker *c, AstNode *expression, b32 lhs, AddressingMode mode, Type *basic_type, ExactValue value) {
map_set(&c->untyped, hash_pointer(expression), make_expression_info(lhs, mode, basic_type, value));
}
-void add_type_and_value(Checker *c, AstNode *expression, AddressingMode mode, Type *type, Value value) {
+void add_type_and_value(Checker *c, AstNode *expression, AddressingMode mode, Type *type, ExactValue value) {
GB_ASSERT(expression != NULL);
GB_ASSERT(type != NULL);
if (mode == Addressing_Invalid)
return;
if (mode == Addressing_Constant) {
- GB_ASSERT(value.kind != Value_Invalid);
+ GB_ASSERT(value.kind != ExactValue_Invalid);
GB_ASSERT(type == &basic_types[Basic_Invalid] || is_type_constant_type(type));
}
@@ -443,7 +454,7 @@ void add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
if (!are_strings_equal(entity->token.string, make_string("_"))) {
Entity *insert_entity = scope_insert_entity(scope, entity);
if (insert_entity) {
- print_checker_error(c, entity->token, "Redeclared entity in this scope: %.*s", LIT(entity->token.string));
+ checker_err(c, entity->token, "Redeclared entity in this scope: %.*s", LIT(entity->token.string));
return;
}
}
@@ -463,14 +474,15 @@ void add_file_entity(Checker *c, AstNode *identifier, Entity *e, DeclarationInfo
GB_ASSERT(are_strings_equal(identifier->identifier.token.string, e->token.string));
- add_entity(c, c->file_scope, identifier, e);
+ add_entity(c, c->global_scope, identifier, e);
map_set(&c->entities, hash_pointer(e), d);
e->order = gb_array_count(c->entities.entries);
}
-void check_procedure_later(Checker *c, Token token, DeclarationInfo *decl, Type *type, AstNode *body) {
+void check_procedure_later(Checker *c, AstFile *file, Token token, DeclarationInfo *decl, Type *type, AstNode *body) {
ProcedureInfo info = {};
+ info.file = file;
info.token = token;
info.decl = decl;
info.type = type;
@@ -506,6 +518,12 @@ void pop_procedure(Checker *c) {
}
+void add_curr_ast_file(Checker *c, AstFile *file) {
+ c->error_prev_line = 0;
+ c->error_prev_column = 0;
+ c->curr_ast_file = file;
+}
+
@@ -523,162 +541,115 @@ GB_COMPARE_PROC(entity_order_cmp) {
return p->order < q->order ? -1 : p->order > q->order;
}
-void check_file(Checker *c, AstNode *file_node) {
-
-// Collect Entities
- for (AstNode *decl = file_node; decl != NULL; decl = decl->next) {
- if (!is_ast_node_declaration(decl))
- continue;
-
- switch (decl->kind) {
- case AstNode_BadDeclaration:
- break;
-
- case AstNode_VariableDeclaration: {
- auto *vd = &decl->variable_declaration;
-
- switch (vd->kind) {
- case Declaration_Immutable: {
- for (AstNode *name = vd->name_list, *value = vd->value_list;
- name != NULL && value != NULL;
- name = name->next, value = value->next) {
- GB_ASSERT(name->kind == AstNode_Identifier);
- Value v = {Value_Invalid};
- Entity *e = make_entity_constant(c->allocator, c->curr_scope, name->identifier.token, NULL, v);
- DeclarationInfo *di = make_declaration_info(c->allocator, c->file_scope);
- di->type_expr = vd->type_expression;
- di->init_expr = value;
- add_file_entity(c, name, e, di);
- }
-
- isize lhs_count = vd->name_list_count;
- isize rhs_count = vd->value_list_count;
-
- if (rhs_count == 0 && vd->type_expression == NULL) {
- print_checker_error(c, ast_node_token(decl), "Missing type or initial expression");
- } else if (lhs_count < rhs_count) {
- print_checker_error(c, ast_node_token(decl), "Extra initial expression");
- }
- } break;
-
- case Declaration_Mutable: {
- isize entity_count = vd->name_list_count;
- isize entity_index = 0;
- Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
- DeclarationInfo *di = NULL;
- if (vd->value_list_count == 1) {
- di = make_declaration_info(gb_heap_allocator(), c->file_scope);
- di->entities = entities;
- di->entity_count = entity_count;
- di->type_expr = vd->type_expression;
- di->init_expr = vd->value_list;
- }
-
- AstNode *value = vd->value_list;
- for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
- Entity *e = make_entity_variable(c->allocator, c->file_scope, name->identifier.token, NULL);
- entities[entity_index++] = e;
-
- DeclarationInfo *d = di;
- if (d == NULL) {
- AstNode *init_expr = value;
- d = make_declaration_info(gb_heap_allocator(), c->file_scope);
- d->type_expr = vd->type_expression;
- d->init_expr = init_expr;
+void check_parsed_files(Checker *c) {
+ // Collect Entities
+ for (isize i = 0; i < gb_array_count(c->parser->files); i++) {
+ AstFile *f = &c->parser->files[i];
+ add_curr_ast_file(c, f);
+ for (AstNode *decl = f->declarations; decl != NULL; decl = decl->next) {
+ if (!is_ast_node_declaration(decl))
+ continue;
+
+ switch (decl->kind) {
+ case AstNode_BadDeclaration:
+ break;
+
+ case AstNode_VariableDeclaration: {
+ auto *vd = &decl->variable_declaration;
+
+ switch (vd->kind) {
+ case Declaration_Immutable: {
+ for (AstNode *name = vd->name_list, *value = vd->value_list;
+ name != NULL && value != NULL;
+ name = name->next, value = value->next) {
+ GB_ASSERT(name->kind == AstNode_Identifier);
+ ExactValue v = {ExactValue_Invalid};
+ Entity *e = make_entity_constant(c->allocator, c->curr_scope, name->identifier.token, NULL, v);
+ DeclarationInfo *di = make_declaration_info(c->allocator, c->global_scope);
+ di->type_expr = vd->type_expression;
+ di->init_expr = value;
+ add_file_entity(c, name, e, di);
}
- add_file_entity(c, name, e, d);
+ isize lhs_count = vd->name_list_count;
+ isize rhs_count = vd->value_list_count;
- if (value != NULL)
- value = value->next;
- }
+ if (rhs_count == 0 && vd->type_expression == NULL) {
+ checker_err(c, ast_node_token(decl), "Missing type or initial expression");
+ } else if (lhs_count < rhs_count) {
+ checker_err(c, ast_node_token(decl), "Extra initial expression");
+ }
+ } break;
+
+ case Declaration_Mutable: {
+ isize entity_count = vd->name_list_count;
+ isize entity_index = 0;
+ Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
+ DeclarationInfo *di = NULL;
+ if (vd->value_list_count == 1) {
+ di = make_declaration_info(gb_heap_allocator(), c->global_scope);
+ di->entities = entities;
+ di->entity_count = entity_count;
+ di->type_expr = vd->type_expression;
+ di->init_expr = vd->value_list;
+ }
-#if 0
- for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
- Entity *entity = NULL;
- Token token = name->identifier.token;
- if (name->kind == AstNode_Identifier) {
- String str = token.string;
- Entity *found = NULL;
- // NOTE(bill): Ignore assignments to `_`
- b32 can_be_ignored = are_strings_equal(str, make_string("_"));
- if (!can_be_ignored) {
- found = current_scope_lookup_entity(c->file_scope, str);
- }
- if (found == NULL) {
- entity = make_entity_variable(c->allocator, c->file_scope, token, NULL);
- if (!can_be_ignored) {
- new_entities[new_entity_count++] = entity;
- }
- add_entity_definition(c, name, entity);
- } else {
- entity = found;
+ AstNode *value = vd->value_list;
+ for (AstNode *name = vd->name_list; name != NULL; name = name->next) {
+ Entity *e = make_entity_variable(c->allocator, c->global_scope, name->identifier.token, NULL);
+ entities[entity_index++] = e;
+
+ DeclarationInfo *d = di;
+ if (d == NULL) {
+ AstNode *init_expr = value;
+ d = make_declaration_info(gb_heap_allocator(), c->global_scope);
+ d->type_expr = vd->type_expression;
+ d->init_expr = init_expr;
}
- } else {
- print_checker_error(c, token, "A variable declaration must be an identifier");
- }
- if (entity == NULL)
- entity = make_entity_dummy_variable(c, token);
- entities[entity_index++] = entity;
- }
- Type *init_type = NULL;
- if (vd->type_expression) {
- init_type = check_type(c, vd->type_expression, NULL);
- if (init_type == NULL)
- init_type = &basic_types[Basic_Invalid];
- }
+ add_file_entity(c, name, e, d);
- for (isize i = 0; i < entity_count; i++) {
- Entity *e = entities[i];
- GB_ASSERT(e != NULL);
- if (e->variable.visited) {
- e->type = &basic_types[Basic_Invalid];
- continue;
+ if (value != NULL)
+ value = value->next;
}
- e->variable.visited = true;
-
- if (e->type == NULL)
- e->type = init_type;
+ } break;
}
- check_init_variables(c, entities, entity_count, vd->value_list, vd->value_list_count, make_string("variable declaration"));
-#endif
} break;
- }
+ case AstNode_TypeDeclaration: {
+ AstNode *identifier = decl->type_declaration.name;
+ Entity *e = make_entity_type_name(c->allocator, c->global_scope, identifier->identifier.token, NULL);
+ DeclarationInfo *d = make_declaration_info(c->allocator, e->parent);
+ d->type_expr = decl->type_declaration.type_expression;
+ add_file_entity(c, identifier, e, d);
+ } break;
- } break;
-
- case AstNode_TypeDeclaration: {
- AstNode *identifier = decl->type_declaration.name;
- Entity *e = make_entity_type_name(c->allocator, c->file_scope, identifier->identifier.token, NULL);
- DeclarationInfo *d = make_declaration_info(c->allocator, e->parent);
- d->type_expr = decl->type_declaration.type_expression;
- add_file_entity(c, identifier, e, d);
- } break;
+ case AstNode_ProcedureDeclaration: {
+ AstNode *identifier = decl->procedure_declaration.name;
+ Token token = identifier->identifier.token;
+ Entity *e = make_entity_procedure(c->allocator, c->global_scope, token, NULL);
+ add_entity(c, c->global_scope, identifier, e);
+ DeclarationInfo *d = make_declaration_info(c->allocator, e->parent);
+ d->proc_decl = decl;
+ map_set(&c->entities, hash_pointer(e), d);
+ e->order = gb_array_count(c->entities.entries);
- case AstNode_ProcedureDeclaration: {
- AstNode *identifier = decl->procedure_declaration.name;
- Token token = identifier->identifier.token;
- Entity *e = make_entity_procedure(c->allocator, c->file_scope, token, NULL);
- add_entity(c, c->file_scope, identifier, e);
- DeclarationInfo *d = make_declaration_info(c->allocator, e->parent);
- d->proc_decl = decl;
- map_set(&c->entities, hash_pointer(e), d);
- e->order = gb_array_count(c->entities.entries);
+ } break;
- } break;
+ case AstNode_ImportDeclaration:
+ // NOTE(bill): ignore
+ break;
- default:
- print_checker_error(c, ast_node_token(decl), "Only declarations are allowed at file scope");
- break;
+ default:
+ checker_err(c, ast_node_token(decl), "Only declarations are allowed at file scope");
+ break;
+ }
}
}
-// Order entities
- {
+ { // Order entities
gbArray(Entity *) entities;
isize count = gb_array_count(c->entities.entries);
gb_array_init_reserve(entities, gb_heap_allocator(), count);
@@ -698,10 +669,27 @@ void check_file(Checker *c, AstNode *file_node) {
}
+ // Check procedure bodies
for (isize i = 0; i < gb_array_count(c->procedures); i++) {
ProcedureInfo *pi = &c->procedures[i];
+ add_curr_ast_file(c, pi->file);
check_procedure_body(c, pi->token, pi->decl, pi->type, pi->body);
}
+
+
+ { // Add untyped expression values
+ isize count = gb_array_count(c->untyped.entries);
+ for (isize i = 0; i < count; i++) {
+ auto *entry = c->untyped.entries + i;
+ u64 key = entry->key;
+ AstNode *expr = cast(AstNode *)cast(uintptr)key;
+ ExpressionInfo *info = &entry->value;
+ if (is_type_typed(info->type)) {
+ GB_PANIC("%s (type %s) is typed!", expression_to_string(expr), info->type);
+ }
+ add_type_and_value(c, expr, info->mode, info->type, info->value);
+ }
+ }
}
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));
+
+ 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:
- 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:
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
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)<<precision);
- return make_value_integer(i);
+ return make_exact_value_integer(i);
} break;
case Token_Not: {
switch (v.kind) {
- case Value_Invalid: return v;
- case Value_Bool:
- return make_value_bool(!v.value_bool);
+ case ExactValue_Invalid: return v;
+ case ExactValue_Bool:
+ return make_exact_value_bool(!v.value_bool);
}
} break;
}
@@ -181,23 +181,23 @@ Value unary_operator_value(Token op, Value v, i32 precision) {
failure:
GB_PANIC("Invalid unary operation, %s", token_kind_to_string(op.kind));
- Value error_value = {};
+ ExactValue error_value = {};
return error_value;
}
// NOTE(bill): Make sure things are evaluated in correct order
-i32 value_order(Value v) {
+i32 exact_value_order(ExactValue v) {
switch (v.kind) {
- case Value_Invalid:
+ case ExactValue_Invalid:
return 0;
- case Value_Bool:
- case Value_String:
+ case ExactValue_Bool:
+ case ExactValue_String:
return 1;
- case Value_Integer:
+ case ExactValue_Integer:
return 2;
- case Value_Float:
+ case ExactValue_Float:
return 3;
- case Value_Pointer:
+ case ExactValue_Pointer:
return 4;
default:
@@ -206,58 +206,58 @@ i32 value_order(Value v) {
}
}
-void match_values(Value *x, Value *y) {
- if (value_order(*y) < value_order(*x)) {
- match_values(y, x);
+void match_exact_values(ExactValue *x, ExactValue *y) {
+ if (exact_value_order(*y) < exact_value_order(*x)) {
+ match_exact_values(y, x);
return;
}
switch (x->kind) {
- case Value_Invalid:
+ case ExactValue_Invalid:
*y = *x;
return;
- case Value_Bool:
- case Value_String:
+ case ExactValue_Bool:
+ case ExactValue_String:
return;
- case Value_Integer:
+ case ExactValue_Integer:
switch (y->kind) {
- case Value_Integer:
+ case ExactValue_Integer:
return;
- case Value_Float:
+ case ExactValue_Float:
// TODO(bill): Is this good enough?
- *x = make_value_float(cast(f64)x->value_integer);
+ *x = make_exact_value_float(cast(f64)x->value_integer);
return;
}
break;
- case Value_Float:
- if (y->kind == Value_Float)
+ case ExactValue_Float:
+ if (y->kind == ExactValue_Float)
return;
break;
}
- GB_PANIC("How'd you get here? Invalid Value.kind");
+ GB_PANIC("How'd you get here? Invalid ExactValueKind");
}
// TODO(bill): Allow for pointer arithmetic? Or are pointer slices good enough?
-Value binary_operator_value(Token op, Value x, Value y) {
- match_values(&x, &y);
+ExactValue exact_binary_operator_value(Token op, ExactValue x, ExactValue y) {
+ match_exact_values(&x, &y);
switch (x.kind) {
- case Value_Invalid:
+ case ExactValue_Invalid:
return x;
- case Value_Bool:
+ case ExactValue_Bool:
switch (op.kind) {
- case Token_CmpAnd: return make_value_bool(x.value_bool && y.value_bool);
- case Token_CmpOr: return make_value_bool(x.value_bool || y.value_bool);
+ case Token_CmpAnd: return make_exact_value_bool(x.value_bool && y.value_bool);
+ case Token_CmpOr: return make_exact_value_bool(x.value_bool || y.value_bool);
default: goto error;
}
break;
- case Value_Integer: {
+ case ExactValue_Integer: {
i64 a = x.value_integer;
i64 b = y.value_integer;
i64 c = 0;
@@ -265,7 +265,7 @@ Value binary_operator_value(Token op, Value x, Value y) {
case Token_Add: c = a + b; break;
case Token_Sub: c = a - b; break;
case Token_Mul: c = a * b; break;
- case Token_Quo: return make_value_float(fmod(cast(f64)a, cast(f64)b));
+ case Token_Quo: return make_exact_value_float(fmod(cast(f64)a, cast(f64)b));
case Token_QuoEq: c = a / b; break; // NOTE(bill): Integer division
case Token_Mod: c = a % b; break;
case Token_And: c = a & b; break;
@@ -274,53 +274,53 @@ Value binary_operator_value(Token op, Value x, Value y) {
case Token_AndNot: c = a&(~b); break;
default: goto error;
}
- return make_value_integer(c);
+ return make_exact_value_integer(c);
} break;
- case Value_Float: {
+ case ExactValue_Float: {
f64 a = x.value_float;
f64 b = y.value_float;
switch (op.kind) {
- case Token_Add: return make_value_float(a + b);
- case Token_Sub: return make_value_float(a - b);
- case Token_Mul: return make_value_float(a * b);
- case Token_Quo: return make_value_float(a / b);
+ case Token_Add: return make_exact_value_float(a + b);
+ case Token_Sub: return make_exact_value_float(a - b);
+ case Token_Mul: return make_exact_value_float(a * b);
+ case Token_Quo: return make_exact_value_float(a / b);
default: goto error;
}
} break;
}
error:
- Value error_value = {};
- GB_PANIC("Invalid binary operation: %s", token_kind_to_string(op.kind));
+ ExactValue error_value = {};
+ // gb_printf_err("Invalid binary operation: %s\n", token_kind_to_string(op.kind));
return error_value;
}
-gb_inline Value value_add(Value x, Value y) { Token op = {Token_Add}; return binary_operator_value(op, x, y); }
-gb_inline Value value_sub(Value x, Value y) { Token op = {Token_Sub}; return binary_operator_value(op, x, y); }
-gb_inline Value value_mul(Value x, Value y) { Token op = {Token_Mul}; return binary_operator_value(op, x, y); }
-gb_inline Value value_quo(Value x, Value y) { Token op = {Token_Quo}; return binary_operator_value(op, x, y); }
+gb_inline ExactValue exact_value_add(ExactValue x, ExactValue y) { Token op = {Token_Add}; return exact_binary_operator_value(op, x, y); }
+gb_inline ExactValue exact_value_sub(ExactValue x, ExactValue y) { Token op = {Token_Sub}; return exact_binary_operator_value(op, x, y); }
+gb_inline ExactValue exact_value_mul(ExactValue x, ExactValue y) { Token op = {Token_Mul}; return exact_binary_operator_value(op, x, y); }
+gb_inline ExactValue exact_value_quo(ExactValue x, ExactValue y) { Token op = {Token_Quo}; return exact_binary_operator_value(op, x, y); }
i32 cmp_f64(f64 a, f64 b) {
return (a > b) - (a < b);
}
-b32 compare_values(Token op, Value x, Value y) {
- match_values(&x, &y);
+b32 compare_exact_values(Token op, ExactValue x, ExactValue y) {
+ match_exact_values(&x, &y);
switch (x.kind) {
- case Value_Invalid:
+ case ExactValue_Invalid:
return false;
- case Value_Bool:
+ case ExactValue_Bool:
switch (op.kind) {
case Token_CmpEq: return x.value_bool == y.value_bool;
case Token_NotEq: return x.value_bool != y.value_bool;
}
break;
- case Value_Integer: {
+ case ExactValue_Integer: {
i64 a = x.value_integer;
i64 b = y.value_integer;
switch (op.kind) {
@@ -333,7 +333,7 @@ b32 compare_values(Token op, Value x, Value y) {
}
} break;
- case Value_Float: {
+ case ExactValue_Float: {
f64 a = x.value_float;
f64 b = y.value_float;
switch (op.kind) {
@@ -346,7 +346,7 @@ b32 compare_values(Token op, Value x, Value y) {
}
} break;
- case Value_String: {
+ case ExactValue_String: {
String a = x.value_string;
String b = y.value_string;
isize len = gb_min(a.len, b.len);
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 <llvm-c/Core.h>
-#include <llvm-c/BitWriter.h>
-
-struct Generator {
- Checker *checker;
- String output_path;
-
-#define MAX_GENERATOR_ERROR_COUNT 10
- isize error_prev_line;
- isize error_prev_column;
- isize error_count;
-};
-
-#define print_generator_error(p, token, fmt, ...) print_generator_error_(p, __FUNCTION__, token, fmt, ##__VA_ARGS__)
-void print_generator_error_(Generator *g, char *function, Token token, char *fmt, ...) {
-
- // NOTE(bill): Duplicate error, skip it
- if (g->error_prev_line != token.line || g->error_prev_column != token.column) {
- va_list va;
-
- g->error_prev_line = token.line;
- g->error_prev_column = token.column;
-
- #if 0
- gb_printf_err("%s()\n", function);
- #endif
- va_start(va, fmt);
- gb_printf_err("%s(%td:%td) %s\n",
- g->checker->parser->tokenizer.fullpath, token.line, token.column,
- gb_bprintf_va(fmt, va));
- va_end(va);
-
- }
- g->error_count++;
-}
-
-
-b32 init_generator(Generator *g, Checker *checker) {
- if (checker->error_count > 0)
- return false;
- gb_zero_item(g);
- g->checker = checker;
-
- char *fullpath = checker->parser->tokenizer.fullpath;
- char const *ext = gb_path_extension(fullpath);
- isize len = ext-fullpath;
- u8 *text = gb_alloc_array(gb_heap_allocator(), u8, len);
- gb_memcopy(text, fullpath, len);
- g->output_path = make_string(text, len);
-
- return true;
-}
-
-void destroy_generator(Generator *g) {
- if (g->error_count > 0) {
-
- }
-
- if (g->output_path.text)
- gb_free(gb_heap_allocator(), g->output_path.text);
-}
-
-
-void emit_var_decl(Generator *g, String name, Type *type) {
- // gb_printf("%.*s: %s;\n", LIT(name), type_to_string(type));
-}
-
-
-void generate_code(Generator *g, AstNode *file_node) {
- // if (file_node->kind == AstNode_VariableDeclaration) {
- // auto *vd = &file_node->variable_declaration;
- // if (vd->kind == Declaration_Mutable) {
- // for (AstNode *name_item = vd->name_list; name_item != NULL; name_item = name_item->next) {
- // String name = name_item->identifier.token.string;
- // Entity *entity = entity_of_identifier(g->checker, name_item);
- // Type *type = entity->type;
- // emit_var_decl(g, name, type);
- // }
- // }
- // }
-
-}
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, &params, &param_count, &results, &result_count);
+ Token proc_token = parse_procedure_signature(f, scope, &params, &param_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, &param_list, &param_count, &result_list, &result_count);
+ parse_procedure_signature(f, scope, &param_list, &param_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;
}