diff options
| author | Ginger Bill <bill@gingerbill.org> | 2016-08-30 18:39:29 +0100 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2016-08-30 18:39:29 +0100 |
| commit | a06f70d5d95bb7889bf9e8b920d70fd10daf7c12 (patch) | |
| tree | 59e9577fa42612de96849ee4ce6d8bbd2b38c9b6 /src | |
| parent | 0eaf7bd830dcda6e00f80eefed36bdf7beb02d5d (diff) | |
Better `using`; foreign system libraries; optional semicolons
Diffstat (limited to 'src')
| -rw-r--r-- | src/checker/checker.cpp | 10 | ||||
| -rw-r--r-- | src/checker/entity.cpp | 16 | ||||
| -rw-r--r-- | src/checker/expr.cpp | 28 | ||||
| -rw-r--r-- | src/checker/stmt.cpp | 308 | ||||
| -rw-r--r-- | src/checker/type.cpp | 6 | ||||
| -rw-r--r-- | src/codegen/ssa.cpp | 37 | ||||
| -rw-r--r-- | src/main.cpp | 16 | ||||
| -rw-r--r-- | src/parser.cpp | 93 |
8 files changed, 376 insertions, 138 deletions
diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 717c70b57..d239d0995 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -530,7 +530,7 @@ void add_entity_definition(CheckerInfo *i, AstNode *identifier, Entity *entity) map_set(&i->definitions, key, entity); } -void add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) { +b32 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) { @@ -541,18 +541,20 @@ void add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) { "\tat %.*s(%td:%td)", LIT(entity->token.string), LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column); + return false; } else { error(&c->error_collector, entity->token, "Redeclararation of `%.*s` in this scope\n" "\tat %.*s(%td:%td)", LIT(entity->token.string), LIT(entity->token.pos.file), entity->token.pos.line, entity->token.pos.column); + return false; } - return; } } if (identifier != NULL) add_entity_definition(&c->info, identifier, entity); + return true; } void add_entity_use(CheckerInfo *i, AstNode *identifier, Entity *entity) { @@ -733,6 +735,10 @@ void check_parsed_files(Checker *c) { case_ast_node(ld, LoadDecl, decl); // NOTE(bill): ignore case_end; + case_ast_node(fsl, ForeignSystemLibrary, decl); + // NOTE(bill): ignore + case_end; + default: error(&c->error_collector, ast_node_token(decl), "Only declarations are allowed at file scope"); diff --git a/src/checker/entity.cpp b/src/checker/entity.cpp index de4095766..8667aa0c7 100644 --- a/src/checker/entity.cpp +++ b/src/checker/entity.cpp @@ -6,6 +6,7 @@ enum BuiltinProcId; ENTITY_KIND(Invalid), \ ENTITY_KIND(Constant), \ ENTITY_KIND(Variable), \ + ENTITY_KIND(UsingVariable), \ ENTITY_KIND(TypeName), \ ENTITY_KIND(Procedure), \ ENTITY_KIND(Builtin), \ @@ -35,6 +36,7 @@ struct Entity { Token token; Type *type; Entity *using_parent; + AstNode *using_expr; union { struct { ExactValue value; } Constant; @@ -44,9 +46,9 @@ struct Entity { b8 is_field; // Is struct field b8 anonymous; // Variable is an anonymous } Variable; - struct { - b8 used; - } Procedure; + struct {} UsingVariable; + struct {} TypeName; + struct { b8 used; } Procedure; struct { BuiltinProcId id; } Builtin; }; }; @@ -72,6 +74,14 @@ Entity *make_entity_variable(gbAllocator a, Scope *scope, Token token, Type *typ return entity; } +Entity *make_entity_using_variable(gbAllocator a, Entity *parent, Token token, Type *type) { + GB_ASSERT(parent != NULL); + Entity *entity = alloc_entity(a, Entity_UsingVariable, parent->scope, token, type); + entity->using_parent = parent; + return entity; +} + + Entity *make_entity_constant(gbAllocator a, Scope *scope, Token token, Type *type, ExactValue value) { Entity *entity = alloc_entity(a, Entity_Constant, scope, token, type); entity->Constant.value = value; diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index c252871a8..b0ec95805 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -4,7 +4,7 @@ void check_expr_or_type (Checker *c, Operand *operand, AstNode *expre ExprKind check_expr_base (Checker *c, Operand *operand, AstNode *expression, Type *type_hint = NULL); Type * check_type (Checker *c, AstNode *expression, Type *named_type = NULL, CycleChecker *cycle_checker = NULL); void check_type_decl (Checker *c, Entity *e, AstNode *type_expr, Type *def, CycleChecker *cycle_checker); -void check_selector (Checker *c, Operand *operand, AstNode *node); +Entity * check_selector (Checker *c, Operand *operand, AstNode *node); void check_not_tuple (Checker *c, Operand *operand); b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, ExactValue *out_value); void convert_to_typed (Checker *c, Operand *operand, Type *target_type); @@ -143,6 +143,7 @@ void populate_using_entity_map(Checker *c, AstNode *node, Type *t, Map<Entity *> error(&c->error_collector, e->token, "`%.*s` is already declared in `%s`", LIT(name), str); } else { map_set(entity_map, key, f); + add_entity(c, c->context.scope, NULL, f); if (f->Variable.anonymous) { populate_using_entity_map(c, node, f->type, entity_map); } @@ -338,6 +339,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, CycleChecke } else { map_set(&entity_map, key, e); fields[field_index++] = e; + add_entity(c, c->context.scope, name, e); } add_entity_use(&c->info, name, e); } @@ -610,6 +612,11 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl o->mode = Addressing_Builtin; break; + case Entity_UsingVariable: + // TODO(bill): Entity_UsingVariable: is this correct? + o->mode = Addressing_Variable; + break; + default: GB_PANIC("Compiler error: Unknown EntityKind"); break; @@ -727,6 +734,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c check_open_scope(c, e); check_struct_type(c, type, e, cycle_checker); check_close_scope(c); + type->Struct.node = e; goto end; case_end; @@ -736,6 +744,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c check_open_scope(c, e); check_union_type(c, type, e, cycle_checker); check_close_scope(c); + type->Union.node = e; goto end; case_end; @@ -1746,7 +1755,7 @@ Selection lookup_field(Type *type_, String field_name, AddressingMode mode, Sele return sel; } -void check_selector(Checker *c, Operand *operand, AstNode *node) { +Entity *check_selector(Checker *c, Operand *operand, AstNode *node) { GB_ASSERT(node->kind == AstNode_SelectorExpr); ast_node(se, SelectorExpr, node); @@ -1764,7 +1773,7 @@ void check_selector(Checker *c, Operand *operand, AstNode *node) { error(&c->error_collector, ast_node_token(op_expr), "`%s` (`%s`) has no field `%s`", op_str, type_str, sel_str); operand->mode = Addressing_Invalid; operand->expr = node; - return; + return NULL; } add_entity_use(&c->info, selector, entity); @@ -1779,11 +1788,12 @@ void check_selector(Checker *c, Operand *operand, AstNode *node) { if (operand->mode != Addressing_Variable) operand->mode = Addressing_Value; } + return entity; } else { operand->mode = Addressing_Invalid; operand->expr = node; } - + return NULL; } b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) { @@ -1886,7 +1896,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) return false; } - operand->mode = Addressing_Value; + operand->mode = Addressing_NoValue; operand->type = NULL; } break; @@ -2967,6 +2977,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint case AstNode_ArrayType: case AstNode_VectorType: case AstNode_StructType: + case AstNode_UnionType: o->mode = Addressing_Type; o->type = check_type(c, node); break; @@ -3240,6 +3251,13 @@ gbString write_expr_to_string(gbString str, AstNode *node) { str = gb_string_appendc(str, "}"); case_end; + case_ast_node(st, UnionType, node); + str = gb_string_appendc(str, "union{"); + // str = write_field_list_to_string(str, st->decl_list, ", "); + str = gb_string_appendc(str, "}"); + case_end; + + case_ast_node(et, EnumType, node); str = gb_string_appendc(str, "enum "); if (et->base_type != NULL) { diff --git a/src/checker/stmt.cpp b/src/checker/stmt.cpp index a0d1838a8..1bbaf1040 100644 --- a/src/checker/stmt.cpp +++ b/src/checker/stmt.cpp @@ -436,6 +436,107 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, Cyc +void check_var_decl(Checker *c, AstNode *node) { + ast_node(vd, VarDecl, node); + isize entity_count = vd->name_count; + isize entity_index = 0; + Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count); + switch (vd->kind) { + case Declaration_Mutable: { + Entity **new_entities = gb_alloc_array(c->allocator, Entity *, entity_count); + isize new_entity_count = 0; + + for (AstNode *name = vd->name_list; name != NULL; name = name->next) { + Entity *entity = NULL; + Token token = name->Ident.token; + if (name->kind == AstNode_Ident) { + 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->context.scope, str); + } + if (found == NULL) { + entity = make_entity_variable(c->allocator, c->context.scope, token, NULL); + if (!can_be_ignored) { + new_entities[new_entity_count++] = entity; + } + add_entity_definition(&c->info, name, entity); + } else { + entity = found; + } + } else { + error(&c->error_collector, token, "A variable declaration must be an identifier"); + } + if (entity == NULL) + entity = make_entity_dummy_variable(c->allocator, c->global_scope, token); + entities[entity_index++] = entity; + } + + Type *init_type = NULL; + if (vd->type) { + init_type = check_type(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->Variable.visited) { + e->type = t_invalid; + continue; + } + e->Variable.visited = true; + + if (e->type == NULL) + e->type = init_type; + } + + check_init_variables(c, entities, entity_count, vd->value_list, vd->value_count, make_string("variable declaration")); + + AstNode *name = vd->name_list; + for (isize i = 0; i < new_entity_count; i++, name = name->next) { + add_entity(c, c->context.scope, name, new_entities[i]); + } + + } break; + + 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_Ident); + ExactValue v = {ExactValue_Invalid}; + ast_node(i, Ident, name); + Entity *e = make_entity_constant(c->allocator, c->context.scope, i->token, NULL, v); + entities[entity_index++] = e; + check_const_decl(c, e, vd->type, value); + } + + isize lhs_count = vd->name_count; + isize rhs_count = vd->value_count; + + // TODO(bill): Better error messages or is this good enough? + if (rhs_count == 0 && vd->type == NULL) { + error(&c->error_collector, ast_node_token(node), "Missing type or initial expression"); + } else if (lhs_count < rhs_count) { + error(&c->error_collector, ast_node_token(node), "Extra initial expression"); + } + + AstNode *name = vd->name_list; + for (isize i = 0; i < entity_count; i++, name = name->next) { + add_entity(c, c->context.scope, name, entities[i]); + } + } break; + + default: + error(&c->error_collector, ast_node_token(node), "Unknown variable declaration kind. Probably an invalid AST."); + return; + } +} + void check_stmt(Checker *c, AstNode *node, u32 flags) { switch (node->kind) { @@ -688,16 +789,28 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_ast_node(us, UsingStmt, node); switch (us->node->kind) { case_ast_node(es, ExprStmt, us->node); - AstNode *ident = es->expr; - GB_ASSERT(ident->kind == AstNode_Ident); - String name = ident->Ident.token.string; + Entity *e = NULL; + + b32 is_selector = false; + AstNode *expr = unparen_expr(es->expr); + if (expr->kind == AstNode_Ident) { + String name = expr->Ident.token.string; + e = scope_lookup_entity(c, c->context.scope, name); + } else if (expr->kind == AstNode_SelectorExpr) { + Operand o = {}; + check_expr_base(c, &o, expr->SelectorExpr.expr); + e = check_selector(c, &o, expr); + is_selector = true; + } - Entity *e = scope_lookup_entity(c, c->context.scope, name); if (e == NULL) { error(&c->error_collector, us->token, "`using` applied to an unknown entity"); return; } + gbString expr_str = expr_to_string(expr); + defer (gb_string_free(expr_str)); + switch (e->kind) { case Entity_TypeName: { Type *t = get_base_type(e->type); @@ -706,20 +819,34 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { Entity *f = t->Enum.fields[i]; Entity *found = scope_insert_entity(c->context.scope, f); if (found != NULL) { - error(&c->error_collector, us->token, "Namespace collision while `using` `%.*s` of the constant: %.*s", LIT(name), LIT(found->token.string)); + error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of the constant: %.*s", expr_str, LIT(found->token.string)); return; } f->using_parent = e; } } else if (t->kind == Type_Struct) { - for (isize i = 0; i < t->Struct.other_field_count; i++) { - Entity *f = t->Struct.other_fields[i]; - Entity *found = scope_insert_entity(c->context.scope, f); - if (found != NULL) { - error(&c->error_collector, us->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(found->token.string)); - return; + Scope **found = map_get(&c->info.scopes, hash_pointer(t->Struct.node)); + if (found != NULL) { + gb_for_array(i, (*found)->elements.entries) { + Entity *f = (*found)->elements.entries[i].value; + Entity *found = scope_insert_entity(c->context.scope, f); + if (found != NULL) { + error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string)); + return; + } + f->using_parent = e; + } + } else { + for (isize i = 0; i < t->Struct.other_field_count; i++) { + // TODO(bill): using field types too + Entity *f = t->Struct.other_fields[i]; + Entity *found = scope_insert_entity(c->context.scope, f); + if (found != NULL) { + error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string)); + return; + } + f->using_parent = e; } - f->using_parent = e; } } } break; @@ -733,13 +860,70 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { error(&c->error_collector, us->token, "`using` cannot be applied to a procedure"); break; + case Entity_Variable: + case Entity_UsingVariable: { + Type *t = get_base_type(type_deref(e->type)); + if (t->kind == Type_Struct || t->kind == Type_Union) { + // IMPORTANT HACK(bill): Entity_(Struct|Union) overlap in some memory allowing + // for some variables to accessed to same + Scope **found = map_get(&c->info.scopes, hash_pointer(t->Struct.node)); + GB_ASSERT(found != NULL); + gb_for_array(i, (*found)->elements.entries) { + Entity *f = (*found)->elements.entries[i].value; + if (f->kind == Entity_Variable) { + Entity *uvar = make_entity_using_variable(c->allocator, e, f->token, f->type); + if (is_selector) { + uvar->using_expr = expr; + } + Entity *prev = scope_insert_entity(c->context.scope, uvar); + if (prev != NULL) { + error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(prev->token.string)); + return; + } + } + } + } else { + error(&c->error_collector, us->token, "`using` can only be applied to variables of type struct or union"); + return; + } + } break; + default: GB_PANIC("TODO(bill): using Ident"); } case_end; case_ast_node(vd, VarDecl, us->node); - GB_PANIC("TODO(bill): using VarDecl"); + if (vd->name_count > 1) { + error(&c->error_collector, us->token, "`using` can only be applied to one variable of the same type"); + } + check_var_decl(c, us->node); + ast_node(i, Ident, vd->name_list); + + String name = i->token.string; + Entity *e = scope_lookup_entity(c, c->context.scope, name); + + Type *t = get_base_type(type_deref(e->type)); + if (t->kind == Type_Struct || t->kind == Type_Union) { + // IMPORTANT HACK(bill): Entity_(Struct|Union) overlap in some memory allowing + // for some variables to accessed to same + Scope **found = map_get(&c->info.scopes, hash_pointer(t->Struct.node)); + GB_ASSERT(found != NULL); + gb_for_array(i, (*found)->elements.entries) { + Entity *f = (*found)->elements.entries[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(&c->error_collector, us->token, "Namespace collision while `using` `%.*s` of: %.*s", LIT(name), LIT(prev->token.string)); + return; + } + } + } + } else { + error(&c->error_collector, us->token, "`using` can only be applied to variables of type struct or union"); + return; + } case_end; @@ -755,103 +939,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) { case_ast_node(vd, VarDecl, node); - isize entity_count = vd->name_count; - isize entity_index = 0; - Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count); - switch (vd->kind) { - case Declaration_Mutable: { - Entity **new_entities = gb_alloc_array(c->allocator, Entity *, entity_count); - isize new_entity_count = 0; - - for (AstNode *name = vd->name_list; name != NULL; name = name->next) { - Entity *entity = NULL; - Token token = name->Ident.token; - if (name->kind == AstNode_Ident) { - 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->context.scope, str); - } - if (found == NULL) { - entity = make_entity_variable(c->allocator, c->context.scope, token, NULL); - if (!can_be_ignored) { - new_entities[new_entity_count++] = entity; - } - add_entity_definition(&c->info, name, entity); - } else { - entity = found; - } - } else { - error(&c->error_collector, token, "A variable declaration must be an identifier"); - } - if (entity == NULL) - entity = make_entity_dummy_variable(c->allocator, c->global_scope, token); - entities[entity_index++] = entity; - } - - Type *init_type = NULL; - if (vd->type) { - init_type = check_type(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->Variable.visited) { - e->type = t_invalid; - continue; - } - e->Variable.visited = true; - - if (e->type == NULL) - e->type = init_type; - } - - check_init_variables(c, entities, entity_count, vd->value_list, vd->value_count, make_string("variable declaration")); - - AstNode *name = vd->name_list; - for (isize i = 0; i < new_entity_count; i++, name = name->next) { - add_entity(c, c->context.scope, name, new_entities[i]); - } - - } break; - - 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_Ident); - ExactValue v = {ExactValue_Invalid}; - ast_node(i, Ident, name); - Entity *e = make_entity_constant(c->allocator, c->context.scope, i->token, NULL, v); - entities[entity_index++] = e; - check_const_decl(c, e, vd->type, value); - } - - isize lhs_count = vd->name_count; - isize rhs_count = vd->value_count; - - // TODO(bill): Better error messages or is this good enough? - if (rhs_count == 0 && vd->type == NULL) { - error(&c->error_collector, ast_node_token(node), "Missing type or initial expression"); - } else if (lhs_count < rhs_count) { - error(&c->error_collector, ast_node_token(node), "Extra initial expression"); - } - - AstNode *name = vd->name_list; - for (isize i = 0; i < entity_count; i++, name = name->next) { - add_entity(c, c->context.scope, name, entities[i]); - } - } break; - - default: - error(&c->error_collector, ast_node_token(node), "Unknown variable declaration kind. Probably an invalid AST."); - return; - } + check_var_decl(c, node); case_end; case_ast_node(pd, ProcDecl, node); diff --git a/src/checker/type.cpp b/src/checker/type.cpp index bd1ff223e..d5cef4b07 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -107,18 +107,22 @@ struct Type { // Theses are arrays Entity **fields; // Entity_Variable isize field_count; // == offset_count + AstNode *node; + i64 * offsets; b32 are_offsets_set; b32 is_packed; Entity **other_fields; // Entity_Constant or Entity_TypeName isize other_field_count; + } Struct; struct { - // IMPORTANT HACK(bill): The positions of fields and field_count + // IMPORTANT HACK(bill): The positions of fields, field_count, and node // must be same for Struct and Union Entity **fields; // Entity_Variable isize field_count; + AstNode *node; } Union; struct { Type *elem; } Pointer; struct { diff --git a/src/codegen/ssa.cpp b/src/codegen/ssa.cpp index bf2470a28..b01a50d33 100644 --- a/src/codegen/ssa.cpp +++ b/src/codegen/ssa.cpp @@ -2034,6 +2034,30 @@ ssaValue *ssa_emit_deep_field_gep(ssaProcedure *proc, Type *type, ssaValue *e, S } +ssaValue *ssa_add_using_variable(ssaProcedure *proc, Entity *e) { + GB_ASSERT(e->kind == Entity_UsingVariable); + String name = e->token.string; + Entity *parent = e->using_parent; + ssaValue *p = NULL; + if (parent->kind == Entity_UsingVariable) { + p = ssa_add_using_variable(proc, parent); + } + + Selection sel = lookup_field(parent->type, name, Addressing_Variable); + GB_ASSERT(sel.entity != NULL); + ssaValue **pv = map_get(&proc->module->values, hash_pointer(parent)); + ssaValue *v = NULL; + if (pv != NULL) { + v = *pv; + } else { + v = ssa_build_addr(proc, e->using_expr).addr; + } + GB_ASSERT(v != NULL); + ssaValue *var = ssa_emit_deep_field_gep(proc, parent->type, v, sel); + map_set(&proc->module->values, hash_pointer(e), var); + return var; +} + ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { switch (expr->kind) { case_ast_node(i, Ident, expr); @@ -2047,9 +2071,13 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) { ssaValue **found = map_get(&proc->module->values, hash_pointer(e)); if (found) { v = *found; - } else { + } else if (e->kind == Entity_UsingVariable) { + v = ssa_add_using_variable(proc, e); + } + if (v == NULL) { GB_PANIC("Unknown value: %s, entity: %p\n", expr_to_string(expr), e); } + return ssa_make_addr(v, expr); case_end; @@ -2286,6 +2314,13 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) { case_ast_node(bs, EmptyStmt, node); case_end; + case_ast_node(us, UsingStmt, node); + AstNode *decl = unparen_expr(us->node); + if (decl->kind == AstNode_VarDecl) { + ssa_build_stmt(proc, decl); + } + case_end; + case_ast_node(vd, VarDecl, node); if (vd->kind == Declaration_Mutable) { if (vd->name_count == vd->value_count) { // 1:1 assigment diff --git a/src/main.cpp b/src/main.cpp index 26ef255ce..b37ffad48 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -93,14 +93,26 @@ int main(int argc, char **argv) { #if 1 #endif + gbString lib_str = gb_string_make(gb_heap_allocator(), "-lKernel32.lib"); + char lib_str_buf[1024] = {}; + gb_for_array(i, parser.system_libraries) { + String lib = parser.system_libraries[i]; + isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), + " -l%.*s.lib", LIT(lib)); + lib_str = gb_string_appendc(lib_str, lib_str_buf); + } + + exit_code = win32_exec_command_line_app( "clang -o %.*s.exe %.*s.bc " "-Wno-override-module " // "-nostartfiles " - "-lKernel32.lib -lUser32.lib -lGdi32.lib -lOpengl32.lib " + "%s " , cast(int)base_name_len, output_name, - cast(int)base_name_len, output_name); + cast(int)base_name_len, output_name, + lib_str); + gb_string_free(lib_str); if (exit_code != 0) return exit_code; diff --git a/src/parser.cpp b/src/parser.cpp index e3be11940..e4544dae9 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -32,6 +32,7 @@ struct AstFile { AstScope *file_scope; AstScope *curr_scope; + AstNode *curr_proc; isize scope_level; ErrorCollector error_collector; @@ -60,6 +61,8 @@ struct Parser { String init_fullpath; gbArray(AstFile) files; gbArray(String) loads; + gbArray(String) libraries; + gbArray(String) system_libraries; isize load_index; isize total_token_count; }; @@ -193,6 +196,7 @@ AST_NODE_KIND(_DeclBegin, struct{}) \ }) \ AST_NODE_KIND(TypeDecl, struct { Token token; AstNode *name, *type; }) \ AST_NODE_KIND(LoadDecl, struct { Token token, filepath; }) \ + AST_NODE_KIND(ForeignSystemLibrary, struct { Token token, filepath; }) \ AST_NODE_KIND(_DeclEnd, struct{}) \ AST_NODE_KIND(_TypeBegin, struct{}) \ AST_NODE_KIND(Field, struct { \ @@ -368,6 +372,8 @@ Token ast_node_token(AstNode *node) { return node->TypeDecl.token; case AstNode_LoadDecl: return node->LoadDecl.token; + case AstNode_ForeignSystemLibrary: + return node->ForeignSystemLibrary.token; case AstNode_Field: { if (node->Field.name_list) return ast_node_token(node->Field.name_list); @@ -831,6 +837,12 @@ gb_inline AstNode *make_load_decl(AstFile *f, Token token, Token filepath) { return result; } +gb_inline AstNode *make_foreign_system_library(AstFile *f, Token token, Token filepath) { + AstNode *result = make_node(f, AstNode_ForeignSystemLibrary); + result->ForeignSystemLibrary.token = token; + result->ForeignSystemLibrary.filepath = filepath; + return result; +} gb_inline b32 next_token(AstFile *f) { if (f->cursor+1 < f->tokens + gb_array_count(f->tokens)) { @@ -967,11 +979,15 @@ b32 expect_semicolon_after_stmt(AstFile *f, AstNode *s) { } if (!allow_token(f, Token_Semicolon)) { - // CLEANUP(bill): Semicolon handling in parser - ast_file_err(f, f->cursor[0], - "Expected `;` after %.*s, got `%.*s`", - LIT(ast_node_strings[s->kind]), LIT(token_strings[f->cursor[0].kind])); - return false; + if (f->cursor[0].pos.line == f->cursor[-1].pos.line) { + if (f->cursor[0].kind != Token_CloseBrace) { + // CLEANUP(bill): Semicolon handling in parser + ast_file_err(f, f->cursor[0], + "Expected `;` after %.*s, got `%.*s`", + LIT(ast_node_strings[s->kind]), LIT(token_strings[f->cursor[0].kind])); + return false; + } + } } return true; } @@ -1203,7 +1219,10 @@ AstNode *parse_operand(AstFile *f, b32 lhs) { // Parse Procedure Type or Literal case Token_proc: { AstScope *scope = NULL; + AstNode *curr_proc = f->curr_proc; AstNode *type = parse_proc_type(f, &scope); + f->curr_proc = type; + defer (f->curr_proc = curr_proc); u64 tags = 0; String foreign_name = {}; @@ -1862,8 +1881,13 @@ AstNode *parse_identifier_or_type(AstFile *f) { return make_enum_type(f, token, base_type, root, field_count); } - case Token_proc: - return parse_proc_type(f, NULL); + case Token_proc: { + AstNode *curr_proc = f->curr_proc; + AstNode *type = parse_proc_type(f, NULL); + f->curr_proc = type; + f->curr_proc = curr_proc; + return type; + } case Token_OpenParen: { @@ -2126,10 +2150,14 @@ AstNode *parse_return_stmt(AstFile *f) { Token token = expect_token(f, Token_return); AstNode *result = NULL; isize result_count = 0; - if (f->cursor[0].kind != Token_Semicolon) + + if (f->cursor[0].kind != Token_Semicolon && f->cursor[0].kind != Token_CloseBrace && + f->cursor[0].pos.line == token.pos.line) { result = parse_rhs_expr_list(f, &result_count); - if (f->cursor[0].kind != Token_CloseBrace) - expect_token(f, Token_Semicolon); + } + if (f->cursor[0].kind != Token_CloseBrace) { + expect_semicolon_after_stmt(f, result); + } return make_return_stmt(f, token, result, result_count); } @@ -2248,11 +2276,15 @@ AstNode *parse_stmt(AstFile *f) { b32 valid = false; switch (node->kind) { - case AstNode_ExprStmt: - if (node->ExprStmt.expr->kind == AstNode_Ident) { + case AstNode_ExprStmt: { + AstNode *e = unparen_expr(node->ExprStmt.expr); + while (e->kind == AstNode_SelectorExpr) { + e = unparen_expr(e->SelectorExpr.selector); + } + if (e->kind == AstNode_Ident) { valid = true; } - break; + } break; case AstNode_VarDecl: if (node->VarDecl.kind == Declaration_Mutable) { valid = true; @@ -2279,6 +2311,13 @@ AstNode *parse_stmt(AstFile *f) { } ast_file_err(f, token, "You cannot `load` within a procedure. This must be done at the file scope."); return make_bad_decl(f, token, file_path); + } else if (are_strings_equal(s->TagStmt.name.string, make_string("foreign_system_library"))) { + Token file_path = expect_token(f, Token_String); + if (f->curr_scope == f->file_scope) { + return make_foreign_system_library(f, s->TagStmt.token, file_path); + } + ast_file_err(f, token, "You cannot using `foreign_system_library` within a procedure. This must be done at the file scope."); + return make_bad_decl(f, token, file_path); } else if (are_strings_equal(s->TagStmt.name.string, make_string("thread_local"))) { AstNode *var_decl = parse_simple_stmt(f); if (var_decl->kind != AstNode_VarDecl || @@ -2387,6 +2426,8 @@ void destroy_ast_file(AstFile *f) { b32 init_parser(Parser *p) { gb_array_init(p->files, gb_heap_allocator()); gb_array_init(p->loads, gb_heap_allocator()); + gb_array_init(p->libraries, gb_heap_allocator()); + gb_array_init(p->system_libraries, gb_heap_allocator()); return true; } @@ -2402,6 +2443,8 @@ void destroy_parser(Parser *p) { #endif gb_array_free(p->files); gb_array_free(p->loads); + gb_array_free(p->libraries); + gb_array_free(p->system_libraries); } // NOTE(bill): Returns true if it's added @@ -2417,6 +2460,18 @@ b32 try_add_load_path(Parser *p, String import_file) { return true; } +// NOTE(bill): Returns true if it's added +b32 try_add_foreign_system_library_path(Parser *p, String import_file) { + gb_for_array(i, p->system_libraries) { + String import = p->system_libraries[i]; + if (are_strings_equal(import, import_file)) { + return false; + } + } + gb_array_append(p->system_libraries, import_file); + return true; +} + gb_global Rune illegal_import_runes[] = { '"', '\'', '`', ' ', '\\', // NOTE(bill): Disallow windows style filepaths @@ -2480,7 +2535,7 @@ void parse_file(Parser *p, AstFile *f) { String file_str = id->filepath.string; if (!is_load_path_valid(file_str)) { - ast_file_err(f, ast_node_token(node), "Invalid import path"); + ast_file_err(f, ast_node_token(node), "Invalid `load` path"); continue; } @@ -2498,6 +2553,16 @@ void parse_file(Parser *p, AstFile *f) { if (!try_add_load_path(p, import_file)) { gb_free(gb_heap_allocator(), import_file.text); } + } else if (node->kind == AstNode_ForeignSystemLibrary) { + auto *id = &node->ForeignSystemLibrary; + String file_str = id->filepath.string; + + if (!is_load_path_valid(file_str)) { + ast_file_err(f, ast_node_token(node), "Invalid `foreign_system_library` path"); + continue; + } + + try_add_foreign_system_library_path(p, file_str); } } } |