Semicolons are required; when condition for certain file scope declarations; #import syntax change

This commit is contained in:
Ginger Bill
2016-12-01 22:44:00 +00:00
parent be8b9bda2f
commit 4bb45700a5
29 changed files with 3400 additions and 3244 deletions
+52 -73
View File
@@ -223,10 +223,10 @@ typedef struct CheckerContext {
#define MAP_NAME MapExprInfo
#include "../map.c"
typedef struct DelayedImport {
Scope * parent;
AstNodeImportDecl *decl;
} DelayedImport;
typedef struct DelayedDecl {
Scope * parent;
AstNode *decl;
} DelayedDecl;
// NOTE(bill): Symbol tables
@@ -253,7 +253,8 @@ typedef struct Checker {
BaseTypeSizes sizes;
Scope * global_scope;
Array(ProcedureInfo) procs; // NOTE(bill): Procedures to check
Array(DelayedImport) delayed_imports;
Array(DelayedDecl) delayed_imports;
Array(DelayedDecl) delayed_foreign_libraries;
gbArena arena;
@@ -427,7 +428,7 @@ void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entit
}
if (e->scope != shared) {
// Do not return imported entities even #load ones
// Do not return imported entities even #include ones
continue;
}
@@ -616,6 +617,7 @@ void init_checker(Checker *c, Parser *parser, BaseTypeSizes sizes) {
array_init(&c->proc_stack, a);
array_init(&c->procs, a);
array_init(&c->delayed_imports, a);
array_init(&c->delayed_foreign_libraries, a);
// NOTE(bill): Is this big enough or too small?
isize item_size = gb_max3(gb_size_of(Entity), gb_size_of(Type), gb_size_of(Scope));
@@ -642,6 +644,7 @@ void destroy_checker(Checker *c) {
array_free(&c->proc_stack);
array_free(&c->procs);
array_free(&c->delayed_imports);
array_free(&c->delayed_foreign_libraries);
gb_arena_free(&c->arena);
}
@@ -1083,39 +1086,6 @@ void check_global_entities_by_kind(Checker *c, EntityKind kind) {
}
}
void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray nodes, MapScope *file_scopes);
void check_global_when_stmt(Checker *c, Scope *parent_scope, AstNodeWhenStmt *ws, MapScope *file_scopes) {
Operand operand = {Addressing_Invalid};
check_expr(c, &operand, ws->cond);
if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
error_node(ws->cond, "Non-boolean condition in `when` statement");
}
if (operand.mode != Addressing_Constant) {
error_node(ws->cond, "Non-constant condition in `when` statement");
}
if (ws->body == NULL || ws->body->kind != AstNode_BlockStmt) {
error_node(ws->cond, "Invalid body for `when` statement");
} else {
if (operand.value.kind == ExactValue_Bool &&
operand.value.value_bool == true) {
ast_node(body, BlockStmt, ws->body);
check_global_collect_entities(c, parent_scope, body->stmts, file_scopes);
} else if (ws->else_stmt) {
switch (ws->else_stmt->kind) {
case AstNode_BlockStmt:
check_global_collect_entities(c, parent_scope, ws->else_stmt->BlockStmt.stmts, file_scopes);
break;
case AstNode_WhenStmt:
check_global_when_stmt(c, parent_scope, &ws->else_stmt->WhenStmt, file_scopes);
break;
default:
error_node(ws->else_stmt, "Invalid `else` statement in `when` statement");
break;
}
}
}
}
void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray nodes, MapScope *file_scopes) {
for_array(decl_index, nodes) {
AstNode *decl = nodes.e[decl_index];
@@ -1126,16 +1096,13 @@ void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray
switch (decl->kind) {
case_ast_node(bd, BadDecl, decl);
case_end;
case_ast_node(ws, WhenStmt, decl);
// Will be handled later
case_end;
case_ast_node(id, ImportDecl, decl);
if (!parent_scope->is_file) {
// NOTE(bill): _Should_ be caught by the parser
// TODO(bill): Better error handling if it isn't
continue;
}
DelayedImport di = {parent_scope, id};
DelayedDecl di = {parent_scope, decl};
array_add(&c->delayed_imports, di);
case_end;
case_ast_node(fl, ForeignLibrary, decl);
@@ -1145,24 +1112,8 @@ void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray
continue;
}
String file_str = fl->filepath.string;
String base_dir = fl->base_dir;
if (!fl->is_system) {
gbAllocator a = heap_allocator(); // TODO(bill): Change this allocator
String rel_path = get_fullpath_relative(a, base_dir, file_str);
String import_file = rel_path;
if (!gb_file_exists(cast(char *)rel_path.text)) { // NOTE(bill): This should be null terminated
String abs_path = get_fullpath_core(a, file_str);
if (gb_file_exists(cast(char *)abs_path.text)) {
import_file = abs_path;
}
}
file_str = import_file;
}
try_add_foreign_library_path(c, file_str);
DelayedDecl di = {parent_scope, decl};
array_add(&c->delayed_foreign_libraries, di);
case_end;
case_ast_node(cd, ConstDecl, decl);
for_array(i, cd->values) {
@@ -1251,23 +1202,13 @@ void check_global_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray
break;
}
}
// NOTE(bill): `when` stmts need to be handled after the other as the condition may refer to something
// declared after this stmt in source
for_array(decl_index, nodes) {
AstNode *decl = nodes.e[decl_index];
switch (decl->kind) {
case_ast_node(ws, WhenStmt, decl);
check_global_when_stmt(c, parent_scope, ws, file_scopes);
case_end;
}
}
}
void check_import_entities(Checker *c, MapScope *file_scopes) {
for_array(i, c->delayed_imports) {
AstNodeImportDecl *id = c->delayed_imports.e[i].decl;
Scope *parent_scope = c->delayed_imports.e[i].parent;
AstNode *decl = c->delayed_imports.e[i].decl;
ast_node(id, ImportDecl, decl);
HashKey key = hash_string(id->fullpath);
Scope **found = map_scope_get(file_scopes, key);
@@ -1286,6 +1227,19 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
continue;
}
if (id->cond != NULL) {
Operand operand = {Addressing_Invalid};
check_expr(c, &operand, id->cond);
if (operand.mode != Addressing_Constant || !is_type_boolean(operand.type)) {
error_node(id->cond, "Non-constant boolean `when` condition");
continue;
}
if (operand.value.kind == ExactValue_Bool &&
!operand.value.value_bool) {
continue;
}
}
bool previously_added = false;
for_array(import_index, parent_scope->imported) {
Scope *prev = parent_scope->imported.e[import_index];
@@ -1366,6 +1320,31 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
}
}
}
for_array(i, c->delayed_foreign_libraries) {
Scope *parent_scope = c->delayed_foreign_libraries.e[i].parent;
AstNode *decl = c->delayed_foreign_libraries.e[i].decl;
ast_node(fl, ForeignLibrary, decl);
String file_str = fl->filepath.string;
String base_dir = fl->base_dir;
if (!fl->is_system) {
gbAllocator a = heap_allocator(); // TODO(bill): Change this allocator
String rel_path = get_fullpath_relative(a, base_dir, file_str);
String import_file = rel_path;
if (!gb_file_exists(cast(char *)rel_path.text)) { // NOTE(bill): This should be null terminated
String abs_path = get_fullpath_core(a, file_str);
if (gb_file_exists(cast(char *)abs_path.text)) {
import_file = abs_path;
}
}
file_str = import_file;
}
try_add_foreign_library_path(c, file_str);
}
}
+23 -26
View File
@@ -1,10 +1,10 @@
bool check_is_terminating(AstNode *node);
void check_stmt (Checker *c, AstNode *node, u32 flags);
void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags);
void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker);
void check_const_decl (Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr);
void check_proc_decl (Checker *c, Entity *e, DeclInfo *d);
void check_var_decl (Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr);
void check_stmt (Checker *c, AstNode *node, u32 flags);
void check_stmt_list (Checker *c, AstNodeArray stmts, u32 flags);
void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker);
void check_const_decl (Checker *c, Entity *e, AstNode *type_expr, AstNode *init_expr);
void check_proc_decl (Checker *c, Entity *e, DeclInfo *d);
void check_var_decl (Checker *c, Entity *e, Entity **entities, isize entity_count, AstNode *type_expr, AstNode *init_expr);
// NOTE(bill): `content_name` is for debugging and error messages
Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String context_name) {
@@ -227,23 +227,21 @@ void check_init_constant(Checker *c, Entity *e, Operand *operand) {
if (operand->mode != Addressing_Constant) {
// TODO(bill): better error
error_node(operand->expr,
"`%.*s` is not a constant", LIT(ast_node_token(operand->expr).string));
error_node(operand->expr, "`%.*s` is not a constant", LIT(ast_node_token(operand->expr).string));
if (e->type == NULL) {
e->type = t_invalid;
}
return;
}
if (!is_type_constant_type(operand->type)) {
gbString type_str = type_to_string(operand->type);
error_node(operand->expr, "Invalid constant type: `%s`", type_str);
gb_string_free(type_str);
if (e->type == NULL) {
e->type = t_invalid;
}
return;
}
// if (!is_type_constant_type(operand->type)) {
// gbString type_str = type_to_string(operand->type);
// defer (gb_string_free(type_str));
// error_node(operand->expr,
// "Invalid constant type: `%s`", type_str);
// if (e->type == NULL) {
// e->type = t_invalid;
// }
// return;
// }
if (e->type == NULL) { // NOTE(bill): type inference
e->type = operand->type;
@@ -269,14 +267,13 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init_e
if (type_expr) {
Type *t = check_type(c, type_expr);
// if (!is_type_constant_type(t)) {
// gbString str = type_to_string(t);
// defer (gb_string_free(str));
// error_node(type_expr),
// "Invalid constant type `%s`", str);
// e->type = t_invalid;
// return;
// }
if (!is_type_constant_type(t)) {
gbString str = type_to_string(t);
error_node(type_expr, "Invalid constant type `%s`", str);
gb_string_free(str);
e->type = t_invalid;
return;
}
e->type = t;
}
+2
View File
@@ -149,6 +149,7 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie
gb_temp_arena_memory_end(tmp);
case_end;
#if 0
case_ast_node(pd, ProcDecl, node);
if (!ast_node_expect(pd->name, AstNode_Ident)) {
break;
@@ -163,6 +164,7 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie
add_entity_and_decl_info(c, pd->name, e, d);
check_entity_decl(c, e, d, NULL, NULL);
case_end;
#endif
case_ast_node(td, TypeDecl, node);
if (!ast_node_expect(td->name, AstNode_Ident)) {
+29 -22
View File
@@ -111,6 +111,15 @@ bool check_is_terminating(AstNode *node) {
}
case_end;
case_ast_node(ws, WhenStmt, node);
if (ws->else_stmt != NULL) {
if (check_is_terminating(ws->body) &&
check_is_terminating(ws->else_stmt)) {
return true;
}
}
case_end;
case_ast_node(fs, ForStmt, node);
if (fs->cond == NULL && !check_has_break(fs->body, true)) {
return true;
@@ -283,30 +292,28 @@ typedef struct TypeAndToken {
void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) {
Operand operand = {Addressing_Invalid};
check_expr(c, &operand, ws->cond);
if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
error_node(ws->cond, "Non-boolean condition in `when` statement");
}
if (operand.mode != Addressing_Constant) {
error_node(ws->cond, "Non-constant condition in `when` statement");
if (operand.mode != Addressing_Constant || !is_type_boolean(operand.type)) {
error_node(ws->cond, "Non-constant boolean `when` condition");
return;
}
if (ws->body == NULL || ws->body->kind != AstNode_BlockStmt) {
error_node(ws->cond, "Invalid body for `when` statement");
} else {
if (operand.value.kind == ExactValue_Bool &&
operand.value.value_bool) {
check_stmt_list(c, ws->body->BlockStmt.stmts, flags);
} else if (ws->else_stmt) {
switch (ws->else_stmt->kind) {
case AstNode_BlockStmt:
check_stmt_list(c, ws->else_stmt->BlockStmt.stmts, flags);
break;
case AstNode_WhenStmt:
check_when_stmt(c, &ws->else_stmt->WhenStmt, flags);
break;
default:
error_node(ws->else_stmt, "Invalid `else` statement in `when` statement");
break;
}
return;
}
if (operand.value.kind == ExactValue_Bool &&
operand.value.value_bool) {
check_stmt_list(c, ws->body->BlockStmt.stmts, flags);
} else if (ws->else_stmt) {
switch (ws->else_stmt->kind) {
case AstNode_BlockStmt:
check_stmt_list(c, ws->else_stmt->BlockStmt.stmts, flags);
break;
case AstNode_WhenStmt:
check_when_stmt(c, &ws->else_stmt->WhenStmt, flags);
break;
default:
error_node(ws->else_stmt, "Invalid `else` statement in `when` statement");
break;
}
}
}
@@ -1085,7 +1092,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case_ast_node(pd, ProcDecl, node);
// NOTE(bill): Handled elsewhere
#if 0
#if 1
// NOTE(bill): This must be handled here so it has access to the parent scope stuff
// e.g. using
Entity *e = make_entity_procedure(c->allocator, c->context.scope, pd->name->Ident, NULL);