mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-22 13:44:59 -07:00
when statement; Better entity collection system (for both local and global); Better parsing for record declarations
This commit is contained in:
+9
-20
@@ -1,29 +1,18 @@
|
||||
// #import "fmt.odin"
|
||||
#import "fmt.odin"
|
||||
#import "utf8.odin"
|
||||
|
||||
when ODIN_OS == "window" {
|
||||
when ODIN_OS != "window" {
|
||||
} else {
|
||||
MAX :: 64
|
||||
}
|
||||
#import "fmt.odin"
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
|
||||
main :: proc() {
|
||||
when true {
|
||||
OffsetType :: type int
|
||||
}
|
||||
|
||||
// MAX :: 64
|
||||
buf: [MAX]rune
|
||||
backing: [MAX]byte
|
||||
offset: OffsetType
|
||||
offset: int
|
||||
|
||||
when MAX > 0 {
|
||||
msg := "Hello"
|
||||
}
|
||||
|
||||
MAX :: 64
|
||||
|
||||
msg := "Hello"
|
||||
count := utf8.rune_count(msg)
|
||||
assert(count <= MAX)
|
||||
runes := buf[:count]
|
||||
@@ -33,14 +22,14 @@ main :: proc() {
|
||||
s := msg[offset:]
|
||||
r, len := utf8.decode_rune(s)
|
||||
runes[count-i-1] = r
|
||||
offset += len as OffsetType
|
||||
offset += len
|
||||
}
|
||||
|
||||
offset = 0
|
||||
for i := 0; i < count; i++ {
|
||||
data, len := utf8.encode_rune(runes[i])
|
||||
copy(backing[offset:], data[:len])
|
||||
offset += len as OffsetType
|
||||
offset += len
|
||||
}
|
||||
|
||||
reverse := backing[:offset] as string
|
||||
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
#foreign_system_library "opengl32"
|
||||
when ODIN_OS == "windows" {
|
||||
#foreign_system_library "opengl32"
|
||||
}
|
||||
#import "win32.odin"
|
||||
#load "opengl_constants.odin"
|
||||
|
||||
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
#import "win32.odin"
|
||||
when ODIN_OS == "windows" {
|
||||
#import "win32.odin"
|
||||
}
|
||||
#import "fmt.odin"
|
||||
|
||||
File_Time :: type u64
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
#foreign_system_library "user32"
|
||||
#foreign_system_library "gdi32"
|
||||
|
||||
_:= compile_assert(ODIN_OS == "windows")
|
||||
when ODIN_OS == "windows" {
|
||||
#foreign_system_library "user32"
|
||||
#foreign_system_library "gdi32"
|
||||
}
|
||||
|
||||
HANDLE :: type rawptr
|
||||
HWND :: type HANDLE
|
||||
|
||||
+23
-16
@@ -917,10 +917,12 @@ Type *const curr_procedure(Checker *c) {
|
||||
}
|
||||
|
||||
void add_curr_ast_file(Checker *c, AstFile *file) {
|
||||
TokenPos zero_pos = {0};
|
||||
global_error_collector.prev = zero_pos;
|
||||
c->curr_ast_file = file;
|
||||
c->context.decl = file->decl_info;
|
||||
if (file != NULL) {
|
||||
TokenPos zero_pos = {0};
|
||||
global_error_collector.prev = zero_pos;
|
||||
c->curr_ast_file = file;
|
||||
c->context.decl = file->decl_info;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -966,9 +968,6 @@ MapEntity generate_minimum_dependency_map(CheckerInfo *info, Entity *start) {
|
||||
return map;
|
||||
}
|
||||
|
||||
void check_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray nodes, MapScope *file_scopes);
|
||||
|
||||
|
||||
|
||||
#include "expr.c"
|
||||
#include "decl.c"
|
||||
@@ -1072,6 +1071,7 @@ 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};
|
||||
@@ -1088,11 +1088,11 @@ void check_global_when_stmt(Checker *c, Scope *parent_scope, AstNodeWhenStmt *ws
|
||||
if (operand.value.kind == ExactValue_Bool &&
|
||||
operand.value.value_bool == true) {
|
||||
ast_node(body, BlockStmt, ws->body);
|
||||
check_collect_entities(c, parent_scope, body->stmts, file_scopes);
|
||||
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_collect_entities(c, parent_scope, ws->else_stmt->BlockStmt.stmts, file_scopes);
|
||||
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);
|
||||
@@ -1104,7 +1104,7 @@ void check_global_when_stmt(Checker *c, Scope *parent_scope, AstNodeWhenStmt *ws
|
||||
}
|
||||
}
|
||||
}
|
||||
void check_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray nodes, MapScope *file_scopes) {
|
||||
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];
|
||||
if (!is_ast_node_decl(decl) && !is_ast_node_when_stmt(decl)) {
|
||||
@@ -1242,9 +1242,8 @@ void check_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray nodes,
|
||||
try_add_foreign_library_path(c, file_str);
|
||||
case_end;
|
||||
case_ast_node(ws, WhenStmt, decl);
|
||||
check_global_when_stmt(c, parent_scope, ws, file_scopes);
|
||||
// Will be handled later
|
||||
case_end;
|
||||
|
||||
case_ast_node(cd, ConstDecl, decl);
|
||||
for_array(i, cd->values) {
|
||||
AstNode *name = cd->names.e[i];
|
||||
@@ -1267,7 +1266,6 @@ void check_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray nodes,
|
||||
error(ast_node_token(decl), "Extra initial expression");
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(vd, VarDecl, decl);
|
||||
if (!parent_scope->is_file) {
|
||||
// NOTE(bill): Within a procedure, variables must be in order
|
||||
@@ -1308,7 +1306,6 @@ void check_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray nodes,
|
||||
add_entity_and_decl_info(c, name, e, d);
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(td, TypeDecl, decl);
|
||||
ast_node(n, Ident, td->name);
|
||||
Entity *e = make_entity_type_name(c->allocator, parent_scope, *n, NULL);
|
||||
@@ -1317,7 +1314,6 @@ void check_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray nodes,
|
||||
d->type_expr = td->type;
|
||||
add_entity_and_decl_info(c, td->name, e, d);
|
||||
case_end;
|
||||
|
||||
case_ast_node(pd, ProcDecl, decl);
|
||||
ast_node(n, Ident, pd->name);
|
||||
Token token = *n;
|
||||
@@ -1335,6 +1331,17 @@ void check_collect_entities(Checker *c, Scope *parent_scope, AstNodeArray nodes,
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1371,7 +1378,7 @@ void check_parsed_files(Checker *c) {
|
||||
for_array(i, c->parser->files) {
|
||||
AstFile *f = &c->parser->files.e[i];
|
||||
add_curr_ast_file(c, f);
|
||||
check_collect_entities(c, f->scope, f->decls, &file_scopes);
|
||||
check_global_collect_entities(c, f->scope, f->decls, &file_scopes);
|
||||
}
|
||||
|
||||
check_global_entities_by_kind(c, Entity_TypeName);
|
||||
|
||||
+205
-89
@@ -20,6 +20,206 @@ gb_inline Type *check_type(Checker *c, AstNode *expression) {
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct DelayedEntity {
|
||||
Entity *entity;
|
||||
DeclInfo *decl;
|
||||
} DelayedEntity;
|
||||
|
||||
typedef struct DelayedOtherFields {
|
||||
Entity **other_fields;
|
||||
isize other_field_count;
|
||||
isize other_field_index;
|
||||
|
||||
MapEntity *entity_map;
|
||||
} DelayedOtherFields;
|
||||
|
||||
typedef Array(DelayedEntity) DelayedEntities;
|
||||
|
||||
void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntities *delayed_entities, DelayedOtherFields *dof);
|
||||
|
||||
void check_local_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws, DelayedEntities *delayed_entities, DelayedOtherFields *dof) {
|
||||
Operand operand = {Addressing_Invalid};
|
||||
check_expr(c, &operand, ws->cond);
|
||||
if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
|
||||
error(ast_node_token(ws->cond), "Non-boolean condition in `when` statement");
|
||||
}
|
||||
if (operand.mode != Addressing_Constant) {
|
||||
error(ast_node_token(ws->cond), "Non-constant condition in `when` statement");
|
||||
}
|
||||
if (ws->body == NULL || ws->body->kind != AstNode_BlockStmt) {
|
||||
error(ast_node_token(ws->cond), "Invalid body for `when` statement");
|
||||
} else {
|
||||
if (operand.value.kind == ExactValue_Bool &&
|
||||
operand.value.value_bool) {
|
||||
check_local_collect_entities(c, ws->body->BlockStmt.stmts, delayed_entities, dof);
|
||||
} else if (ws->else_stmt) {
|
||||
switch (ws->else_stmt->kind) {
|
||||
case AstNode_BlockStmt:
|
||||
check_local_collect_entities(c, ws->else_stmt->BlockStmt.stmts, delayed_entities, dof);
|
||||
break;
|
||||
case AstNode_WhenStmt:
|
||||
check_local_collect_entities_from_when_stmt(c, &ws->else_stmt->WhenStmt, delayed_entities, dof);
|
||||
break;
|
||||
default:
|
||||
error(ast_node_token(ws->else_stmt), "Invalid `else` statement in `when` statement");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(bill): The `dof` is for use within records
|
||||
void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntities *delayed_entities, DelayedOtherFields *dof) {
|
||||
for_array(i, nodes) {
|
||||
AstNode *node = nodes.e[i];
|
||||
switch (node->kind) {
|
||||
case_ast_node(ws, WhenStmt, node);
|
||||
// Will be handled later
|
||||
case_end;
|
||||
case_ast_node(cd, ConstDecl, node);
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
|
||||
isize entity_count = cd->names.count;
|
||||
isize entity_index = 0;
|
||||
Entity **entities = gb_alloc_array(c->tmp_allocator, Entity *, entity_count);
|
||||
|
||||
for_array(i, cd->values) {
|
||||
AstNode *name = cd->names.e[i];
|
||||
AstNode *value = cd->values.e[i];
|
||||
ExactValue v = {ExactValue_Invalid};
|
||||
|
||||
Entity *e = make_entity_constant(c->allocator, c->context.scope, name->Ident, NULL, v);
|
||||
e->identifier = name;
|
||||
entities[entity_index++] = e;
|
||||
|
||||
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
||||
d->type_expr = cd->type;
|
||||
d->init_expr = value;
|
||||
|
||||
add_entity_and_decl_info(c, name, e, d);
|
||||
|
||||
DelayedEntity delay = {e, d};
|
||||
array_add(delayed_entities, delay);
|
||||
}
|
||||
|
||||
isize lhs_count = cd->names.count;
|
||||
isize rhs_count = cd->values.count;
|
||||
|
||||
// TODO(bill): Better error messages or is this good enough?
|
||||
if (rhs_count == 0 && cd->type == NULL) {
|
||||
error(ast_node_token(node), "Missing type or initial expression");
|
||||
} else if (lhs_count < rhs_count) {
|
||||
error(ast_node_token(node), "Extra initial expression");
|
||||
}
|
||||
|
||||
if (dof != NULL) {
|
||||
// NOTE(bill): Within a record
|
||||
for_array(i, cd->names) {
|
||||
AstNode *name = cd->names.e[i];
|
||||
Entity *e = entities[i];
|
||||
Token name_token = name->Ident;
|
||||
if (str_eq(name_token.string, str_lit("_"))) {
|
||||
dof->other_fields[dof->other_field_index++] = e;
|
||||
} else {
|
||||
HashKey key = hash_string(name_token.string);
|
||||
if (map_entity_get(dof->entity_map, key) != NULL) {
|
||||
// TODO(bill): Scope checking already checks the declaration
|
||||
error(name_token, "`%.*s` is already declared in this record", LIT(name_token.string));
|
||||
} else {
|
||||
map_entity_set(dof->entity_map, key, e);
|
||||
dof->other_fields[dof->other_field_index++] = e;
|
||||
}
|
||||
add_entity(c, c->context.scope, name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
case_end;
|
||||
|
||||
case_ast_node(pd, ProcDecl, node);
|
||||
// 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);
|
||||
e->identifier = pd->name;
|
||||
|
||||
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
||||
d->proc_decl = node;
|
||||
|
||||
add_entity_and_decl_info(c, pd->name, e, d);
|
||||
check_entity_decl(c, e, d, NULL, NULL);
|
||||
case_end;
|
||||
|
||||
case_ast_node(td, TypeDecl, node);
|
||||
Token name_token = td->name->Ident;
|
||||
|
||||
Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, NULL);
|
||||
e->identifier = td->name;
|
||||
|
||||
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
||||
d->type_expr = td->type;
|
||||
|
||||
add_entity_and_decl_info(c, td->name, e, d);
|
||||
|
||||
DelayedEntity delay = {e, d};
|
||||
array_add(delayed_entities, delay);
|
||||
|
||||
|
||||
if (dof != NULL) {
|
||||
if (str_eq(name_token.string, str_lit("_"))) {
|
||||
dof->other_fields[dof->other_field_index++] = e;
|
||||
} else {
|
||||
HashKey key = hash_string(name_token.string);
|
||||
if (map_entity_get(dof->entity_map, key) != NULL) {
|
||||
// TODO(bill): Scope checking already checks the declaration
|
||||
error(name_token, "`%.*s` is already declared in this record", LIT(name_token.string));
|
||||
} else {
|
||||
map_entity_set(dof->entity_map, key, e);
|
||||
dof->other_fields[dof->other_field_index++] = e;
|
||||
}
|
||||
add_entity(c, c->context.scope, td->name, e);
|
||||
add_entity_use(c, td->name, e);
|
||||
}
|
||||
}
|
||||
case_end;
|
||||
}
|
||||
}
|
||||
|
||||
// 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(i, nodes) {
|
||||
AstNode *node = nodes.e[i];
|
||||
switch (node->kind) {
|
||||
case_ast_node(ws, WhenStmt, node);
|
||||
check_local_collect_entities_from_when_stmt(c, ws, delayed_entities, dof);
|
||||
case_end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void check_scope_decls(Checker *c, AstNodeArray nodes, isize reserve_size, DelayedOtherFields *dof) {
|
||||
DelayedEntities delayed_entities;
|
||||
array_init_reserve(&delayed_entities, heap_allocator(), reserve_size);
|
||||
check_local_collect_entities(c, nodes, &delayed_entities, dof);
|
||||
|
||||
for_array(i, delayed_entities) {
|
||||
DelayedEntity delayed = delayed_entities.e[i];
|
||||
if (delayed.entity->kind == Entity_TypeName) {
|
||||
check_entity_decl(c, delayed.entity, delayed.decl, NULL, NULL);
|
||||
}
|
||||
}
|
||||
for_array(i, delayed_entities) {
|
||||
DelayedEntity delayed = delayed_entities.e[i];
|
||||
if (delayed.entity->kind == Entity_Constant) {
|
||||
check_entity_decl(c, delayed.entity, delayed.decl, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
array_free(&delayed_entities);
|
||||
}
|
||||
|
||||
|
||||
bool check_is_assignable_to_using_subtype(Type *dst, Type *src) {
|
||||
Type *prev_src = src;
|
||||
// Type *prev_dst = dst;
|
||||
@@ -247,96 +447,12 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
|
||||
isize other_field_index = 0;
|
||||
Entity *using_index_expr = NULL;
|
||||
|
||||
DelayedOtherFields dof = {0};
|
||||
dof.other_fields = other_fields;
|
||||
dof.other_field_count = other_field_count;
|
||||
dof.entity_map = &entity_map;
|
||||
|
||||
typedef struct {
|
||||
Entity *e;
|
||||
AstNode *t;
|
||||
} Delay;
|
||||
Array(Delay) delayed_const; array_init_reserve(&delayed_const, c->tmp_allocator, other_field_count);
|
||||
Array(Delay) delayed_type; array_init_reserve(&delayed_type, c->tmp_allocator, other_field_count);
|
||||
|
||||
for_array(decl_index, decls) {
|
||||
AstNode *decl = decls.e[decl_index];
|
||||
if (decl->kind == AstNode_ConstDecl) {
|
||||
ast_node(cd, ConstDecl, decl);
|
||||
|
||||
isize entity_count = cd->names.count;
|
||||
isize entity_index = 0;
|
||||
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
|
||||
|
||||
for_array(i, cd->values) {
|
||||
AstNode *name = cd->names.e[i];
|
||||
AstNode *value = cd->values.e[i];
|
||||
|
||||
GB_ASSERT(name->kind == AstNode_Ident);
|
||||
ExactValue v = {ExactValue_Invalid};
|
||||
Token name_token = name->Ident;
|
||||
Entity *e = make_entity_constant(c->allocator, c->context.scope, name_token, NULL, v);
|
||||
entities[entity_index++] = e;
|
||||
|
||||
Delay delay = {e, cd->type};
|
||||
array_add(&delayed_const, delay);
|
||||
}
|
||||
|
||||
isize lhs_count = cd->names.count;
|
||||
isize rhs_count = cd->values.count;
|
||||
|
||||
// TODO(bill): Better error messages or is this good enough?
|
||||
if (rhs_count == 0 && cd->type == NULL) {
|
||||
error(ast_node_token(node), "Missing type or initial expression");
|
||||
} else if (lhs_count < rhs_count) {
|
||||
error(ast_node_token(node), "Extra initial expression");
|
||||
}
|
||||
|
||||
for_array(i, cd->names) {
|
||||
AstNode *name = cd->names.e[i];
|
||||
Entity *e = entities[i];
|
||||
Token name_token = name->Ident;
|
||||
if (str_eq(name_token.string, str_lit("_"))) {
|
||||
other_fields[other_field_index++] = e;
|
||||
} else {
|
||||
HashKey key = hash_string(name_token.string);
|
||||
if (map_entity_get(&entity_map, key) != NULL) {
|
||||
// TODO(bill): Scope checking already checks the declaration
|
||||
error(name_token, "`%.*s` is already declared in this structure", LIT(name_token.string));
|
||||
} else {
|
||||
map_entity_set(&entity_map, key, e);
|
||||
other_fields[other_field_index++] = e;
|
||||
}
|
||||
add_entity(c, c->context.scope, name, e);
|
||||
}
|
||||
}
|
||||
} else if (decl->kind == AstNode_TypeDecl) {
|
||||
ast_node(td, TypeDecl, decl);
|
||||
Token name_token = td->name->Ident;
|
||||
|
||||
Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, NULL);
|
||||
Delay delay = {e, td->type};
|
||||
array_add(&delayed_type, delay);
|
||||
|
||||
if (str_eq(name_token.string, str_lit("_"))) {
|
||||
other_fields[other_field_index++] = e;
|
||||
} else {
|
||||
HashKey key = hash_string(name_token.string);
|
||||
if (map_entity_get(&entity_map, key) != NULL) {
|
||||
// TODO(bill): Scope checking already checks the declaration
|
||||
error(name_token, "`%.*s` is already declared in this structure", LIT(name_token.string));
|
||||
} else {
|
||||
map_entity_set(&entity_map, key, e);
|
||||
other_fields[other_field_index++] = e;
|
||||
}
|
||||
add_entity(c, c->context.scope, td->name, e);
|
||||
add_entity_use(c, td->name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for_array(i, delayed_type) {
|
||||
check_const_decl(c, delayed_type.e[i].e, delayed_type.e[i].t, NULL);
|
||||
}
|
||||
for_array(i, delayed_const) {
|
||||
check_type_decl(c, delayed_const.e[i].e, delayed_const.e[i].t, NULL, NULL);
|
||||
}
|
||||
check_scope_decls(c, decls, 1.2*other_field_count, &dof);
|
||||
|
||||
if (node->kind == AstNode_UnionType) {
|
||||
isize field_index = 0;
|
||||
|
||||
+4
-64
@@ -11,74 +11,12 @@ typedef enum StmtFlag {
|
||||
} StmtFlag;
|
||||
|
||||
|
||||
|
||||
void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
|
||||
if (stmts.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
|
||||
typedef struct {
|
||||
Entity *e;
|
||||
DeclInfo *d;
|
||||
} Delay;
|
||||
Array(Delay) delayed_const; array_init_reserve(&delayed_const, c->tmp_allocator, stmts.count);
|
||||
Array(Delay) delayed_type; array_init_reserve(&delayed_type, c->tmp_allocator, stmts.count);
|
||||
|
||||
for_array(i, stmts) {
|
||||
AstNode *node = stmts.e[i];
|
||||
switch (node->kind) {
|
||||
case_ast_node(cd, ConstDecl, node);
|
||||
for_array(i, cd->values) {
|
||||
AstNode *name = cd->names.e[i];
|
||||
AstNode *value = cd->values.e[i];
|
||||
ExactValue v = {ExactValue_Invalid};
|
||||
|
||||
Entity *e = make_entity_constant(c->allocator, c->context.scope, name->Ident, NULL, v);
|
||||
e->identifier = name;
|
||||
|
||||
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
||||
d->type_expr = cd->type;
|
||||
d->init_expr = value;
|
||||
|
||||
add_entity_and_decl_info(c, name, e, d);
|
||||
|
||||
Delay delay = {e, d};
|
||||
array_add(&delayed_const, delay);
|
||||
}
|
||||
|
||||
isize lhs_count = cd->names.count;
|
||||
isize rhs_count = cd->values.count;
|
||||
|
||||
if (rhs_count == 0 && cd->type == NULL) {
|
||||
error(ast_node_token(node), "Missing type or initial expression");
|
||||
} else if (lhs_count < rhs_count) {
|
||||
error(ast_node_token(node), "Extra initial expression");
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(td, TypeDecl, node);
|
||||
Entity *e = make_entity_type_name(c->allocator, c->context.scope, td->name->Ident, NULL);
|
||||
e->identifier = td->name;
|
||||
|
||||
DeclInfo *d = make_declaration_info(c->allocator, e->scope);
|
||||
d->type_expr = td->type;
|
||||
|
||||
add_entity_and_decl_info(c, td->name, e, d);
|
||||
|
||||
Delay delay = {e, d};
|
||||
array_add(&delayed_type, delay);
|
||||
case_end;
|
||||
}
|
||||
}
|
||||
|
||||
for_array(i, delayed_type) {
|
||||
check_entity_decl(c, delayed_type.e[i].e, delayed_type.e[i].d, NULL, NULL);
|
||||
}
|
||||
for_array(i, delayed_const) {
|
||||
check_entity_decl(c, delayed_const.e[i].e, delayed_const.e[i].d, NULL, NULL);
|
||||
}
|
||||
check_scope_decls(c, stmts, 1.2*stmts.count, NULL);
|
||||
|
||||
bool ft_ok = (flags & Stmt_FallthroughAllowed) != 0;
|
||||
u32 f = flags & (~Stmt_FallthroughAllowed);
|
||||
@@ -95,7 +33,6 @@ void check_stmt_list(Checker *c, AstNodeArray stmts, u32 flags) {
|
||||
check_stmt(c, n, new_flags);
|
||||
}
|
||||
|
||||
gb_temp_arena_memory_end(tmp);
|
||||
}
|
||||
|
||||
bool check_is_terminating_list(AstNodeArray stmts) {
|
||||
@@ -1147,6 +1084,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
case_end;
|
||||
|
||||
case_ast_node(pd, ProcDecl, node);
|
||||
// NOTE(bill): Handled elsewhere
|
||||
#if 0
|
||||
// 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);
|
||||
@@ -1157,6 +1096,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
|
||||
add_entity_and_decl_info(c, pd->name, e, d);
|
||||
check_entity_decl(c, e, d, NULL, NULL);
|
||||
#endif
|
||||
case_end;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-16
@@ -667,24 +667,9 @@ bool is_type_comparable(Type *t) {
|
||||
t = base_type(get_enum_base_type(t));
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
return t->kind != Basic_UntypedNil;
|
||||
return t->kind != Basic_UntypedNil && t->kind != Basic_any;
|
||||
case Type_Pointer:
|
||||
return true;
|
||||
case Type_Record: {
|
||||
if (false && is_type_struct(t)) {
|
||||
// TODO(bill): Should I even allow this?
|
||||
for (isize i = 0; i < t->Record.field_count; i++) {
|
||||
if (!is_type_comparable(t->Record.fields[i]->type))
|
||||
return false;
|
||||
}
|
||||
} else if (is_type_enum(t)) {
|
||||
return is_type_comparable(t->Record.enum_base);
|
||||
}
|
||||
return false;
|
||||
} break;
|
||||
case Type_Array:
|
||||
return false;
|
||||
// return is_type_comparable(t->Array.elem);
|
||||
case Type_Vector:
|
||||
return is_type_comparable(t->Vector.elem);
|
||||
case Type_Proc:
|
||||
|
||||
+57
-54
@@ -1086,6 +1086,7 @@ void fix_advance_to_next_stmt(AstFile *f) {
|
||||
return;
|
||||
|
||||
case Token_if:
|
||||
case Token_when:
|
||||
case Token_return:
|
||||
case Token_for:
|
||||
case Token_match:
|
||||
@@ -1966,55 +1967,61 @@ AstNodeArray parse_parameter_list(AstFile *f) {
|
||||
}
|
||||
|
||||
|
||||
AstNodeArray parse_struct_params(AstFile *f, isize *decl_count_, bool using_allowed) {
|
||||
AstNodeArray parse_record_params(AstFile *f, isize *decl_count_, bool using_allowed, String context) {
|
||||
AstNodeArray decls = make_ast_node_array(f);
|
||||
isize decl_count = 0;
|
||||
|
||||
while (f->curr_token.kind == Token_Identifier ||
|
||||
f->curr_token.kind == Token_using) {
|
||||
bool is_using = false;
|
||||
if (allow_token(f, Token_using)) {
|
||||
is_using = true;
|
||||
}
|
||||
AstNodeArray names = parse_lhs_expr_list(f);
|
||||
if (names.count == 0) {
|
||||
syntax_error(f->curr_token, "Empty field declaration");
|
||||
}
|
||||
while (f->curr_token.kind != Token_CloseBrace &&
|
||||
f->curr_token.kind != Token_EOF) {
|
||||
AstNode *decl = parse_stmt(f);
|
||||
if (is_ast_node_decl(decl) ||
|
||||
decl->kind == AstNode_UsingStmt ||
|
||||
decl->kind == AstNode_EmptyStmt) {
|
||||
switch (decl->kind) {
|
||||
case AstNode_EmptyStmt:
|
||||
break;
|
||||
|
||||
if (!using_allowed && is_using) {
|
||||
syntax_error(f->curr_token, "Cannot apply `using` to members of a union");
|
||||
is_using = false;
|
||||
}
|
||||
if (names.count > 1 && is_using) {
|
||||
syntax_error(f->curr_token, "Cannot apply `using` to more than one of the same type");
|
||||
}
|
||||
case AstNode_ProcDecl:
|
||||
syntax_error(f->curr_token, "Procedure declarations are not allowed within a %.*s", LIT(context));
|
||||
break;
|
||||
|
||||
AstNode *decl = NULL;
|
||||
case AstNode_UsingStmt: {
|
||||
bool is_using = true;
|
||||
if (!using_allowed) {
|
||||
syntax_error(f->curr_token, "Cannot apply `using` to members of a %.*s", LIT(context));
|
||||
is_using = false;
|
||||
}
|
||||
if (decl->UsingStmt.node->kind == AstNode_VarDecl) {
|
||||
AstNode *vd = decl->UsingStmt.node;
|
||||
vd->VarDecl.is_using = is_using && using_allowed;
|
||||
if (vd->VarDecl.values.count > 0) {
|
||||
syntax_error(f->curr_token, "Default variable assignments within a %.*s will be ignored", LIT(context));
|
||||
}
|
||||
array_add(&decls, vd);
|
||||
} else {
|
||||
syntax_error(ast_node_token(decl), "Illegal %.*s field", LIT(context));
|
||||
}
|
||||
} break;
|
||||
|
||||
if (f->curr_token.kind == Token_Colon) {
|
||||
decl = parse_decl(f, names);
|
||||
case AstNode_VarDecl: {
|
||||
if (decl->VarDecl.values.count > 0) {
|
||||
syntax_error(f->curr_token, "Default variable assignments within a %.*s will be ignored", LIT(context));
|
||||
}
|
||||
array_add(&decls, decl);
|
||||
}
|
||||
|
||||
if (decl->kind == AstNode_ProcDecl) {
|
||||
syntax_error(f->curr_token, "Procedure declarations are not allowed within a structure");
|
||||
decl = make_bad_decl(f, ast_node_token(names.e[0]), f->curr_token);
|
||||
case AstNode_BadDecl:
|
||||
break;
|
||||
|
||||
case AstNode_ConstDecl:
|
||||
case AstNode_TypeDecl:
|
||||
default:
|
||||
decl_count += 1;
|
||||
array_add(&decls, decl);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
syntax_error(f->curr_token, "Illegal structure field");
|
||||
decl = make_bad_decl(f, ast_node_token(names.e[0]), f->curr_token);
|
||||
}
|
||||
|
||||
expect_semicolon_after_stmt(f, decl);
|
||||
|
||||
if (is_ast_node_decl(decl)) {
|
||||
array_add(&decls, decl);
|
||||
if (decl->kind == AstNode_VarDecl) {
|
||||
decl->VarDecl.is_using = is_using && using_allowed;
|
||||
if (decl->VarDecl.values.count > 0) {
|
||||
syntax_error(f->curr_token, "Default variable assignments within a structure will be ignored (at the moment)");
|
||||
}
|
||||
} else {
|
||||
decl_count += 1;
|
||||
}
|
||||
syntax_error(ast_node_token(decl), "Illegal record field: %.*s", LIT(ast_node_strings[decl->kind]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2063,7 +2070,11 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) {
|
||||
next_token(f);
|
||||
} else if (f->curr_token.kind == Token_vector) {
|
||||
next_token(f);
|
||||
count_expr = parse_expr(f, false);
|
||||
if (f->curr_token.kind != Token_CloseBracket) {
|
||||
count_expr = parse_expr(f, false);
|
||||
} else {
|
||||
syntax_error(f->curr_token, "Vector type missing count");
|
||||
}
|
||||
is_vector = true;
|
||||
} else if (f->curr_token.kind != Token_CloseBracket) {
|
||||
count_expr = parse_expr(f, false);
|
||||
@@ -2076,15 +2087,6 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) {
|
||||
return make_array_type(f, token, count_expr, parse_type(f));
|
||||
}
|
||||
|
||||
// case Token_OpenBrace: {
|
||||
// f->expr_level++;
|
||||
// Token token = expect_token(f, Token_OpenBrace);
|
||||
// AstNode *count_expr = parse_expr(f, false);
|
||||
// expect_token(f, Token_CloseBrace);
|
||||
// f->expr_level--;
|
||||
// return make_vector_type(f, token, count_expr, parse_type(f));
|
||||
// }
|
||||
|
||||
case Token_struct: {
|
||||
Token token = expect_token(f, Token_struct);
|
||||
bool is_packed = false;
|
||||
@@ -2112,7 +2114,7 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) {
|
||||
|
||||
Token open = expect_token_after(f, Token_OpenBrace, "`struct`");
|
||||
isize decl_count = 0;
|
||||
AstNodeArray decls = parse_struct_params(f, &decl_count, true);
|
||||
AstNodeArray decls = parse_record_params(f, &decl_count, true, str_lit("struct"));
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
|
||||
return make_struct_type(f, token, decls, decl_count, is_packed, is_ordered);
|
||||
@@ -2122,7 +2124,7 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) {
|
||||
Token token = expect_token(f, Token_union);
|
||||
Token open = expect_token_after(f, Token_OpenBrace, "`union`");
|
||||
isize decl_count = 0;
|
||||
AstNodeArray decls = parse_struct_params(f, &decl_count, false);
|
||||
AstNodeArray decls = parse_record_params(f, &decl_count, false, str_lit("union"));
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
|
||||
return make_union_type(f, token, decls, decl_count);
|
||||
@@ -2132,7 +2134,7 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) {
|
||||
Token token = expect_token(f, Token_raw_union);
|
||||
Token open = expect_token_after(f, Token_OpenBrace, "`raw_union`");
|
||||
isize decl_count = 0;
|
||||
AstNodeArray decls = parse_struct_params(f, &decl_count, true);
|
||||
AstNodeArray decls = parse_record_params(f, &decl_count, true, str_lit("raw_union"));
|
||||
Token close = expect_token(f, Token_CloseBrace);
|
||||
|
||||
return make_raw_union_type(f, token, decls, decl_count);
|
||||
@@ -2192,8 +2194,9 @@ AstNode *parse_identifier_or_type(AstFile *f, u32 flags) {
|
||||
break;
|
||||
|
||||
case Token_Eq:
|
||||
if (f->prev_token.kind == Token_Colon)
|
||||
if (f->prev_token.kind == Token_Colon) {
|
||||
break;
|
||||
}
|
||||
// fallthrough
|
||||
default:
|
||||
syntax_error(f->curr_token,
|
||||
|
||||
Reference in New Issue
Block a user