Begin transition to Jai-like syntax

This commit is contained in:
Ginger Bill
2017-01-01 19:08:03 +00:00
parent 3f1195cd03
commit a48e0c7179
20 changed files with 2348 additions and 2365 deletions
+95 -111
View File
@@ -1075,36 +1075,33 @@ void init_preload(Checker *c) {
c->done_preload = true;
}
bool check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init);
bool check_arity_match(Checker *c, AstNodeValueDecl *d);
#include "expr.c"
#include "decl.c"
#include "stmt.c"
bool check_arity_match(Checker *c, AstNodeValueSpec *s, AstNodeValueSpec *init) {
isize lhs = s->names.count;
isize rhs = s->values.count;
if (init != NULL) {
rhs = init->values.count;
}
bool check_arity_match(Checker *c, AstNodeValueDecl *d) {
isize lhs = d->names.count;
isize rhs = d->values.count;
if (init == NULL && rhs == 0) {
if (s->type == NULL) {
error_node(s->names.e[0], "Missing type or initial expression");
if (rhs == 0) {
if (d->type == NULL) {
error_node(d->names.e[0], "Missing type or initial expression");
return false;
}
} else if (lhs < rhs) {
if (lhs < s->values.count) {
AstNode *n = s->values.e[lhs];
if (lhs < d->values.count) {
AstNode *n = d->values.e[lhs];
gbString str = expr_to_string(n);
error_node(n, "Extra initial expression `%s`", str);
gb_string_free(str);
} else {
error_node(s->names.e[0], "Extra initial expression");
error_node(d->names.e[0], "Extra initial expression");
}
return false;
} else if (lhs > rhs && (init != NULL || rhs != 1)) {
AstNode *n = s->names.e[rhs];
} else if (lhs > rhs && rhs != 1) {
AstNode *n = d->names.e[rhs];
gbString str = expr_to_string(n);
error_node(n, "Missing expression for `%s`", str);
gb_string_free(str);
@@ -1160,15 +1157,95 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
switch (decl->kind) {
case_ast_node(bd, BadDecl, decl);
case_end;
case_ast_node(vd, ValueDecl, decl);
if (vd->is_var) {
// NOTE(bill): You need to store the entity information here unline a constant declaration
isize entity_count = vd->names.count;
isize entity_index = 0;
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
DeclInfo *di = NULL;
if (vd->values.count > 0) {
di = make_declaration_info(heap_allocator(), parent_scope);
di->entities = entities;
di->entity_count = entity_count;
di->type_expr = vd->type;
di->init_expr = vd->values.e[0];
}
for_array(i, vd->names) {
AstNode *name = vd->names.e[i];
AstNode *value = NULL;
if (i < vd->values.count) {
value = vd->values.e[i];
}
if (name->kind != AstNode_Ident) {
error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
continue;
}
Entity *e = make_entity_variable(c->allocator, parent_scope, name->Ident, NULL);
e->identifier = name;
entities[entity_index++] = e;
DeclInfo *d = di;
if (d == NULL) {
AstNode *init_expr = value;
d = make_declaration_info(heap_allocator(), e->scope);
d->type_expr = vd->type;
d->init_expr = init_expr;
d->var_decl_tags = vd->tags;
}
add_entity_and_decl_info(c, name, e, d);
}
check_arity_match(c, vd);
} else {
for_array(i, vd->names) {
AstNode *name = vd->names.e[i];
if (name->kind != AstNode_Ident) {
error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
continue;
}
AstNode *init = NULL;
if (i < vd->values.count) {
init = vd->values.e[i];
}
DeclInfo *d = make_declaration_info(c->allocator, parent_scope);
Entity *e = NULL;
AstNode *up_init = unparen_expr(init);
if (init != NULL && is_ast_node_type(up_init)) {
e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
d->type_expr = init;
d->init_expr = init;
} else if (init != NULL && up_init->kind == AstNode_ProcLit) {
e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags);
d->proc_decl = init;
} else {
e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, (ExactValue){0});
d->type_expr = vd->type;
d->init_expr = init;
}
GB_ASSERT(e != NULL);
e->identifier = name;
add_entity_and_decl_info(c, name, e, d);
}
check_arity_match(c, vd);
}
case_end;
case_ast_node(gd, GenericDecl, decl);
if (!parent_scope->is_file) {
// NOTE(bill): Within a procedure, variables must be in order
continue;
}
AstNodeValueSpec empty_spec_ = {0}, *empty_spec = &empty_spec_;
AstNodeValueSpec *prev_spec = NULL;
for_array(iota, gd->specs) {
AstNode *spec = gd->specs.e[iota];
switch (spec->kind) {
@@ -1183,99 +1260,6 @@ void check_global_collect_entities_from_file(Checker *c, Scope *parent_scope, As
DelayedDecl di = {parent_scope, spec};
array_add(&c->delayed_imports, di);
case_end;
case_ast_node(vs, ValueSpec, spec);
switch (vs->keyword) {
case Token_var: {
// NOTE(bill): You need to store the entity information here unline a constant declaration
isize entity_count = vs->names.count;
isize entity_index = 0;
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
DeclInfo *di = NULL;
if (vs->values.count > 0) {
di = make_declaration_info(heap_allocator(), parent_scope);
di->entities = entities;
di->entity_count = entity_count;
di->type_expr = vs->type;
di->init_expr = vs->values.e[0];
}
for_array(i, vs->names) {
AstNode *name = vs->names.e[i];
AstNode *value = NULL;
if (i < vs->values.count) {
value = vs->values.e[i];
}
if (name->kind != AstNode_Ident) {
error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
continue;
}
Entity *e = make_entity_variable(c->allocator, parent_scope, name->Ident, NULL);
e->identifier = name;
entities[entity_index++] = e;
DeclInfo *d = di;
if (d == NULL) {
AstNode *init_expr = value;
d = make_declaration_info(heap_allocator(), e->scope);
d->type_expr = vs->type;
d->init_expr = init_expr;
d->var_decl_tags = gd->tags;
}
add_entity_and_decl_info(c, name, e, d);
}
check_arity_match(c, vs, NULL);
} break;
case Token_const: {
if (vs->type != NULL || vs->values.count > 0) {
prev_spec = vs;
} else if (prev_spec == NULL) {
prev_spec = empty_spec;
}
for_array(i, vs->names) {
AstNode *name = vs->names.e[i];
if (name->kind != AstNode_Ident) {
error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
continue;
}
AstNode *init = NULL;
if (i < prev_spec->values.count) {
init = prev_spec->values.e[i];
}
DeclInfo *d = make_declaration_info(c->allocator, parent_scope);
Entity *e = NULL;
ExactValue v_iota = make_exact_value_integer(iota);
AstNode *up_init = unparen_expr(init);
if (init != NULL && is_ast_node_type(up_init)) {
e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
d->type_expr = init;
d->init_expr = init;
} else if (init != NULL && up_init->kind == AstNode_ProcLit) {
e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags);
d->proc_decl = init;
} else {
e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, v_iota);
d->type_expr = prev_spec->type;
d->init_expr = init;
}
GB_ASSERT(e != NULL);
e->identifier = name;
add_entity_and_decl_info(c, name, e, d);
}
check_arity_match(c, vs, prev_spec);
} break;
}
case_end;
case_ast_node(ts, TypeSpec, spec);
if (ts->name->kind != AstNode_Ident) {
+11 -11
View File
@@ -107,14 +107,14 @@ void check_init_variables(Checker *c, Entity **lhs, isize lhs_count, AstNodeArra
gb_temp_arena_memory_end(tmp);
}
void check_var_spec_node(Checker *c, AstNodeValueSpec *vs) {
GB_ASSERT(vs->keyword == Token_var);
isize entity_count = vs->names.count;
void check_var_decl_node(Checker *c, AstNodeValueDecl *vd) {
GB_ASSERT(vd->is_var == true);
isize entity_count = vd->names.count;
isize entity_index = 0;
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
for_array(i, vs->names) {
AstNode *name = vs->names.e[i];
for_array(i, vd->names) {
AstNode *name = vd->names.e[i];
Entity *entity = NULL;
if (name->kind == AstNode_Ident) {
Token token = name->Ident;
@@ -145,8 +145,8 @@ void check_var_spec_node(Checker *c, AstNodeValueSpec *vs) {
}
Type *init_type = NULL;
if (vs->type) {
init_type = check_type_extra(c, vs->type, NULL);
if (vd->type) {
init_type = check_type_extra(c, vd->type, NULL);
if (init_type == NULL) {
init_type = t_invalid;
}
@@ -165,12 +165,12 @@ void check_var_spec_node(Checker *c, AstNodeValueSpec *vs) {
e->type = init_type;
}
check_arity_match(c, vs, NULL);
check_init_variables(c, entities, entity_count, vs->values, str_lit("variable declaration"));
check_arity_match(c, vd);
check_init_variables(c, entities, entity_count, vd->values, str_lit("variable declaration"));
for_array(i, vs->names) {
for_array(i, vd->names) {
if (entities[i] != NULL) {
add_entity(c, c->context.scope, vs->names.e[i], entities[i]);
add_entity(c, c->context.scope, vd->names.e[i], entities[i]);
}
}
+46 -59
View File
@@ -85,71 +85,58 @@ void check_local_collect_entities(Checker *c, AstNodeArray nodes, DelayedEntitie
case_ast_node(ws, WhenStmt, node);
// Will be handled later
case_end;
case_ast_node(gd, GenericDecl, node);
AstNodeValueSpec empty_spec_ = {0}, *empty_spec = &empty_spec_;
AstNodeValueSpec *last = NULL;
case_ast_node(vd, ValueDecl, node);
if (vd->is_var) {
// NOTE(bill): Handled later
} else {
for_array(i, vd->names) {
AstNode *name = vd->names.e[i];
if (name->kind != AstNode_Ident) {
error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
continue;
}
AstNode *init = NULL;
if (i < vd->values.count) {
init = vd->values.e[i];
}
DeclInfo *d = make_declaration_info(c->allocator, c->context.scope);
Entity *e = NULL;
AstNode *up_init = unparen_expr(init);
if (init != NULL && is_ast_node_type(up_init)) {
e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
d->type_expr = init;
d->init_expr = init;
} else if (init != NULL && up_init->kind == AstNode_ProcLit) {
e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags);
d->proc_decl = init;
} else {
e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, (ExactValue){0});
d->type_expr = vd->type;
d->init_expr = init;
}
GB_ASSERT(e != NULL);
e->identifier = name;
add_entity_and_decl_info(c, name, e, d);
DelayedEntity delay = {name, e, d};
array_add(delayed_entities, delay);
}
check_arity_match(c, vd);
}
case_end;
case_ast_node(gd, GenericDecl, node);
for_array(iota, gd->specs) {
AstNode *spec = gd->specs.e[iota];
switch (spec->kind) {
case_ast_node(bd, BadDecl, spec);
case_end;
case_ast_node(vs, ValueSpec, spec);
switch (vs->keyword) {
case Token_var:
break;
case Token_const: {
if (vs->type != NULL || vs->values.count > 0) {
last = vs;
} else if (last == NULL) {
last = empty_spec;
}
for_array(i, vs->names) {
AstNode *name = vs->names.e[i];
if (name->kind != AstNode_Ident) {
error_node(name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[name->kind]));
continue;
}
AstNode *init = NULL;
if (i < vs->values.count) {
init = vs->values.e[i];
}
DeclInfo *d = make_declaration_info(c->allocator, c->context.scope);
Entity *e = NULL;
ExactValue v_iota = make_exact_value_integer(iota);
AstNode *up_init = unparen_expr(init);
if (init != NULL && is_ast_node_type(up_init)) {
e = make_entity_type_name(c->allocator, d->scope, name->Ident, NULL);
d->type_expr = init;
d->init_expr = init;
} else if (init != NULL && up_init->kind == AstNode_ProcLit) {
e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags);
d->proc_decl = init;
} else {
e = make_entity_constant(c->allocator, d->scope, name->Ident, NULL, v_iota);
d->type_expr = vs->type;
d->init_expr = init;
}
GB_ASSERT(e != NULL);
e->identifier = name;
add_entity_and_decl_info(c, name, e, d);
DelayedEntity delay = {name, e, d};
array_add(delayed_entities, delay);
}
check_arity_match(c, vs, last);
} break;
}
case_end;
case_ast_node(ts, TypeSpec, spec);
if (ts->name->kind != AstNode_Ident) {
error_node(ts->name, "A declaration's name must be an identifier, got %.*s", LIT(ast_node_strings[ts->name->kind]));
+102 -111
View File
@@ -1026,48 +1026,45 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
case_end;
case_ast_node(gd, GenericDecl, us->node);
for_array(spec_index, gd->specs) {
AstNode *spec = gd->specs.e[spec_index];
switch (spec->kind) {
case_ast_node(vs, ValueSpec, spec);
if (vs->keyword != Token_var) {
error_node(spec, "`using` can only be applied to a variable declaration");
return;
}
case_ast_node(vd, ValueDecl, us->node);
if (!vd->is_var) {
error_node(us->node, "`using` can only be applied to a variable declaration");
return;
}
if (vs->names.count > 1 && vs->type != NULL) {
error(us->token, "`using` can only be applied to one variable of the same type");
}
if (vd->names.count > 1 && vd->type != NULL) {
error(us->token, "`using` can only be applied to one variable of the same type");
}
check_var_spec_node(c, vs);
check_var_decl_node(c, vd);
for_array(name_index, vs->names) {
AstNode *item = vs->names.e[name_index];
ast_node(i, Ident, item);
String name = i->string;
Entity *e = scope_lookup_entity(c->context.scope, name);
Type *t = base_type(type_deref(e->type));
if (is_type_struct(t) || is_type_raw_union(t)) {
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
GB_ASSERT(found != NULL);
for_array(i, (*found)->elements.entries) {
Entity *f = (*found)->elements.entries.e[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
Entity *prev = scope_insert_entity(c->context.scope, uvar);
if (prev != NULL) {
error(us->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
return;
}
}
for_array(name_index, vd->names) {
AstNode *item = vd->names.e[name_index];
if (item->kind != AstNode_Ident) {
// TODO(bill): Handle error here???
continue;
}
ast_node(i, Ident, item);
String name = i->string;
Entity *e = scope_lookup_entity(c->context.scope, name);
Type *t = base_type(type_deref(e->type));
if (is_type_struct(t) || is_type_raw_union(t)) {
Scope **found = map_scope_get(&c->info.scopes, hash_pointer(t->Record.node));
GB_ASSERT(found != NULL);
for_array(i, (*found)->elements.entries) {
Entity *f = (*found)->elements.entries.e[i].value;
if (f->kind == Entity_Variable) {
Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type);
Entity *prev = scope_insert_entity(c->context.scope, uvar);
if (prev != NULL) {
error(us->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string));
return;
}
} else {
error(us->token, "`using` can only be applied to variables of type struct or raw_union");
return;
}
}
case_end;
} else {
error(us->token, "`using` can only be applied to variables of type struct or raw_union");
return;
}
}
case_end;
@@ -1096,7 +1093,76 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case_end;
case_ast_node(vd, ValueDecl, node);
if (vd->is_var) {
isize entity_count = vd->names.count;
isize entity_index = 0;
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
for_array(i, vd->names) {
AstNode *name = vd->names.e[i];
Entity *entity = NULL;
if (name->kind == AstNode_Ident) {
Token token = name->Ident;
String str = token.string;
Entity *found = NULL;
// NOTE(bill): Ignore assignments to `_`
if (str_ne(str, str_lit("_"))) {
found = current_scope_lookup_entity(c->context.scope, str);
}
if (found == NULL) {
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL);
add_entity_definition(&c->info, name, entity);
} else {
TokenPos pos = found->token.pos;
error(token,
"Redeclaration of `%.*s` in this scope\n"
"\tat %.*s(%td:%td)",
LIT(str), LIT(pos.file), pos.line, pos.column);
entity = found;
}
} else {
error_node(name, "A variable declaration must be an identifier");
}
if (entity == NULL) {
entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
}
entities[entity_index++] = entity;
}
Type *init_type = NULL;
if (vd->type) {
init_type = check_type_extra(c, vd->type, NULL);
if (init_type == NULL) {
init_type = t_invalid;
}
}
for (isize i = 0; i < entity_count; i++) {
Entity *e = entities[i];
GB_ASSERT(e != NULL);
if (e->flags & EntityFlag_Visited) {
e->type = t_invalid;
continue;
}
e->flags |= EntityFlag_Visited;
if (e->type == NULL)
e->type = init_type;
}
check_arity_match(c, vd);
check_init_variables(c, entities, entity_count, vd->values, str_lit("variable declaration"));
for_array(i, vd->names) {
if (entities[i] != NULL) {
add_entity(c, c->context.scope, vd->names.e[i], entities[i]);
}
}
} else {
// NOTE(bill): Handled elsewhere
}
case_end;
case_ast_node(gd, GenericDecl, node);
for_array(spec_index, gd->specs) {
@@ -1104,81 +1170,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
switch (spec->kind) {
case_ast_node(bd, BadDecl, spec);
case_end;
case_ast_node(vs, ValueSpec, spec);
switch (vs->keyword) {
case Token_var: {
isize entity_count = vs->names.count;
isize entity_index = 0;
Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
for_array(i, vs->names) {
AstNode *name = vs->names.e[i];
Entity *entity = NULL;
if (name->kind == AstNode_Ident) {
Token token = name->Ident;
String str = token.string;
Entity *found = NULL;
// NOTE(bill): Ignore assignments to `_`
if (str_ne(str, str_lit("_"))) {
found = current_scope_lookup_entity(c->context.scope, str);
}
if (found == NULL) {
entity = make_entity_variable(c->allocator, c->context.scope, token, NULL);
add_entity_definition(&c->info, name, entity);
} else {
TokenPos pos = found->token.pos;
error(token,
"Redeclaration of `%.*s` in this scope\n"
"\tat %.*s(%td:%td)",
LIT(str), LIT(pos.file), pos.line, pos.column);
entity = found;
}
} else {
error_node(name, "A variable declaration must be an identifier");
}
if (entity == NULL) {
entity = make_entity_dummy_variable(c->allocator, c->global_scope, ast_node_token(name));
}
entities[entity_index++] = entity;
}
Type *init_type = NULL;
if (vs->type) {
init_type = check_type_extra(c, vs->type, NULL);
if (init_type == NULL) {
init_type = t_invalid;
}
}
for (isize i = 0; i < entity_count; i++) {
Entity *e = entities[i];
GB_ASSERT(e != NULL);
if (e->flags & EntityFlag_Visited) {
e->type = t_invalid;
continue;
}
e->flags |= EntityFlag_Visited;
if (e->type == NULL)
e->type = init_type;
}
check_arity_match(c, vs, NULL);
check_init_variables(c, entities, entity_count, vs->values, str_lit("variable declaration"));
for_array(i, vs->names) {
if (entities[i] != NULL) {
add_entity(c, c->context.scope, vs->names.e[i], entities[i]);
}
}
} break;
case Token_const:
// NOTE(bill): Handled elsewhere
break;
}
case_end;
case_ast_node(ts, TypeSpec, spec);
// NOTE(bill): Handled elsewhere
case_end;