diff --git a/examples/test.odin b/examples/test.odin index e69de29bb..ea647c431 100644 --- a/examples/test.odin +++ b/examples/test.odin @@ -0,0 +1,6 @@ +type Vec2: struct { x, y: f32 } + + +main :: proc() { + +} diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 2877d1b48..7908b9ce4 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -297,12 +297,12 @@ void init_universal_scope(void) { for (isize i = 0; i < gb_count_of(basic_types); i++) { Token token = {Token_Identifier}; token.string = basic_types[i].basic.name; - add_global_entity(alloc_entity(a, Entity_TypeName, NULL, token, &basic_types[i])); + add_global_entity(make_entity_type_name(a, NULL, token, &basic_types[i])); } for (isize i = 0; i < gb_count_of(basic_type_aliases); i++) { Token token = {Token_Identifier}; token.string = basic_type_aliases[i].basic.name; - add_global_entity(alloc_entity(a, Entity_TypeName, NULL, token, &basic_type_aliases[i])); + add_global_entity(make_entity_type_name(a, NULL, token, &basic_type_aliases[i])); } // Constants @@ -555,8 +555,8 @@ void check_parsed_files(Checker *c) { add_file_entity(c, name, e, di); } - isize lhs_count = vd->name_list_count; - isize rhs_count = vd->value_list_count; + isize lhs_count = vd->name_count; + isize rhs_count = vd->value_count; if (rhs_count == 0 && vd->type_expression == NULL) { error(&c->error_collector, ast_node_token(decl), "Missing type or initial expression"); @@ -566,11 +566,11 @@ void check_parsed_files(Checker *c) { } break; case Declaration_Mutable: { - isize entity_count = vd->name_list_count; + isize entity_count = vd->name_count; isize entity_index = 0; Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count); DeclarationInfo *di = NULL; - if (vd->value_list_count == 1) { + if (vd->value_count == 1) { di = make_declaration_info(gb_heap_allocator(), c->global_scope); di->entities = entities; di->entity_count = entity_count; @@ -610,6 +610,14 @@ void check_parsed_files(Checker *c) { add_file_entity(c, identifier, e, d); } break; + case AstNode_AliasDeclaration: { + AstNode *identifier = decl->alias_declaration.name; + Entity *e = make_entity_alias_name(c->allocator, c->global_scope, identifier->identifier.token, NULL); + DeclarationInfo *d = make_declaration_info(c->allocator, e->parent); + d->type_expr = decl->alias_declaration.type_expression; + add_file_entity(c, identifier, e, d); + } break; + case AstNode_ProcedureDeclaration: { AstNode *identifier = decl->procedure_declaration.name; Token token = identifier->identifier.token; diff --git a/src/checker/entity.cpp b/src/checker/entity.cpp index aed4751ef..0553f8a50 100644 --- a/src/checker/entity.cpp +++ b/src/checker/entity.cpp @@ -8,6 +8,7 @@ enum EntityKind { Entity_Constant, Entity_Variable, Entity_TypeName, + Entity_AliasName, Entity_Procedure, Entity_Builtin, @@ -33,6 +34,7 @@ struct Entity { b8 used; } variable; struct {} type_name; + struct {} alias_name; struct {} procedure; struct { BuiltinProcedureId id; } builtin; }; @@ -70,14 +72,19 @@ Entity *make_entity_type_name(gbAllocator a, Scope *parent, Token token, Type *t return entity; } +Entity *make_entity_alias_name(gbAllocator a, Scope *parent, Token token, Type *type) { + Entity *entity = alloc_entity(a, Entity_AliasName, parent, token, type); + return entity; +} + Entity *make_entity_param(gbAllocator a, Scope *parent, Token token, Type *type) { - Entity *entity = alloc_entity(a, Entity_Variable, parent, token, type); + Entity *entity = make_entity_variable(a, parent, token, type); entity->variable.used = true; return entity; } Entity *make_entity_field(gbAllocator a, Scope *parent, Token token, Type *type) { - Entity *entity = alloc_entity(a, Entity_Variable, parent, token, type); + Entity *entity = make_entity_variable(a, parent, token, type); entity->variable.is_field = true; return entity; } diff --git a/src/checker/expression.cpp b/src/checker/expression.cpp index 1cc36cc65..9302990b5 100644 --- a/src/checker/expression.cpp +++ b/src/checker/expression.cpp @@ -123,13 +123,13 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { // gb_printf("%td -> %td\n", param_count, result_count); Type *params = check_get_params(c, c->context.scope, proc_type_node->procedure_type.param_list, param_count); - Type *results = check_get_results(c, c->context.scope, proc_type_node->procedure_type.results_list, result_count); + Type *results = check_get_results(c, c->context.scope, proc_type_node->procedure_type.result_list, result_count); - type->procedure.scope = c->context.scope; - type->procedure.params = params; - type->procedure.params_count = proc_type_node->procedure_type.param_count; - type->procedure.results = results; - type->procedure.results_count = proc_type_node->procedure_type.result_count; + type->procedure.scope = c->context.scope; + type->procedure.params = params; + type->procedure.param_count = proc_type_node->procedure_type.param_count; + type->procedure.results = results; + type->procedure.result_count = proc_type_node->procedure_type.result_count; } @@ -171,6 +171,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) { break; case Entity_TypeName: + case Entity_AliasName: o->mode = Addressing_Type; break; @@ -1416,9 +1417,9 @@ ExpressionKind check_call_expression(Checker *c, Operand *operand, AstNode *call check_call_arguments(c, operand, proc_type, call); auto *proc = &proc_type->procedure; - if (proc->results_count == 0) { + if (proc->result_count == 0) { operand->mode = Addressing_NoValue; - } else if (proc->results_count == 1) { + } else if (proc->result_count == 1) { operand->mode = Addressing_Value; operand->type = proc->results->tuple.variables[0]->type; } else { @@ -1524,7 +1525,6 @@ void check_expression_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t } } - ExpressionKind check__expression_base(Checker *c, Operand *o, AstNode *node, Type *type_hint) { ExpressionKind kind = Expression_Statement; diff --git a/src/checker/statements.cpp b/src/checker/statements.cpp index 761fb03f0..cea7b1188 100644 --- a/src/checker/statements.cpp +++ b/src/checker/statements.cpp @@ -360,6 +360,17 @@ void check_type_declaration(Checker *c, Entity *e, AstNode *type_expr, Type *nam set_base_type(named, get_base_type(get_base_type(named))); } +void check_alias_declaration(Checker *c, Entity *e, AstNode *type_expr, Type *alias_type) { + GB_ASSERT(e->type == NULL); + Type *named = make_type_alias(c->allocator, e->token.string, NULL, e); + named->alias.alias_name = e; + set_base_type(alias_type, named); + e->type = named; + + check_type(c, type_expr, named); + + set_base_type(named, get_base_type(get_base_type(named))); +} void check_procedure_body(Checker *c, Token token, DeclarationInfo *decl, Type *type, AstNode *body) { GB_ASSERT(body->kind == AstNode_BlockStatement); @@ -370,7 +381,7 @@ void check_procedure_body(Checker *c, Token token, DeclarationInfo *decl, Type * push_procedure(c, type); check_statement_list(c, body->block_statement.list, 0); - if (type->procedure.results_count > 0) { + if (type->procedure.result_count > 0) { if (!check_is_terminating(c, body)) { error(&c->error_collector, body->block_statement.close, "Missing return statement at the end of the procedure"); } @@ -498,6 +509,9 @@ void check_entity_declaration(Checker *c, Entity *e, Type *named_type) { case Entity_TypeName: check_type_declaration(c, e, d->type_expr, named_type); break; + case Entity_AliasName: + check_alias_declaration(c, e, d->type_expr, named_type); + break; case Entity_Procedure: check_procedure_declaration(c, e, d, true); break; @@ -763,7 +777,7 @@ void check_statement(Checker *c, AstNode *node, u32 flags) { // Declarations case AstNode_VariableDeclaration: { auto *vd = &node->variable_declaration; - isize entity_count = vd->name_list_count; + isize entity_count = vd->name_count; isize entity_index = 0; Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count); switch (vd->kind) { @@ -820,7 +834,7 @@ void check_statement(Checker *c, AstNode *node, u32 flags) { } - check_init_variables(c, entities, entity_count, vd->value_list, vd->value_list_count, make_string("variable declaration")); + 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) { @@ -840,8 +854,8 @@ void check_statement(Checker *c, AstNode *node, u32 flags) { check_constant_declaration(c, e, vd->type_expression, value); } - isize lhs_count = vd->name_list_count; - isize rhs_count = vd->value_list_count; + 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_expression == NULL) { @@ -881,5 +895,13 @@ void check_statement(Checker *c, AstNode *node, u32 flags) { add_entity(c, c->context.scope, name, e); check_type_declaration(c, e, td->type_expression, NULL); } break; + + case AstNode_AliasDeclaration: { + auto *ad = &node->alias_declaration; + AstNode *name = ad->name; + Entity *e = make_entity_alias_name(c->allocator, c->context.scope, name->identifier.token, NULL); + add_entity(c, c->context.scope, name, e); + check_alias_declaration(c, e, ad->type_expression, NULL); + } break; } } diff --git a/src/checker/type.cpp b/src/checker/type.cpp index e767a6d07..3a66b62ac 100644 --- a/src/checker/type.cpp +++ b/src/checker/type.cpp @@ -60,6 +60,7 @@ enum TypeKind { Type_Structure, Type_Pointer, Type_Named, + Type_Alias, Type_Tuple, Type_Procedure, @@ -81,7 +82,7 @@ struct Type { Entity **fields; // Entity_Variable isize field_count; // == offset_count i64 * offsets; - b32 offsets_set; + b32 are_offsets_set; } structure; struct { Type *element; } pointer; struct { @@ -89,6 +90,11 @@ struct Type { Type * base; Entity *type_name; // Entity_TypeName } named; + struct { + String name; + Type * base; + Entity *alias_name; // Entity_AliasName + } alias; struct { Entity **variables; // Entity_Variable isize variable_count; @@ -97,15 +103,18 @@ struct Type { Scope *scope; Type * params; // Type_Tuple Type * results; // Type_Tuple - isize params_count; - isize results_count; + isize param_count; + isize result_count; } procedure; }; }; Type *get_base_type(Type *t) { - while (t->kind == Type_Named) { - t = t->named.base; + while (t->kind == Type_Named || t->kind == Type_Alias) { + if (t->kind == Type_Named) + t = t->named.base; + else + t = t->alias.base; } return t; } @@ -113,6 +122,8 @@ Type *get_base_type(Type *t) { void set_base_type(Type *t, Type *base) { if (t && t->kind == Type_Named) { t->named.base = base; + } else if (t && t->kind == Type_Alias) { + t->alias.base = base; } } @@ -162,18 +173,26 @@ Type *make_type_named(gbAllocator a, String name, Type *base, Entity *type_name) return t; } +Type *make_type_alias(gbAllocator a, String name, Type *base, Entity *alias_name) { + Type *t = alloc_type(a, Type_Alias); + t->alias.name = name; + t->alias.base = base; + t->alias.alias_name = alias_name; + return t; +} + Type *make_type_tuple(gbAllocator a) { Type *t = alloc_type(a, Type_Tuple); return t; } -Type *make_type_procedure(gbAllocator a, Scope *scope, Type *params, isize params_count, Type *results, isize results_count) { +Type *make_type_procedure(gbAllocator a, Scope *scope, Type *params, isize param_count, Type *results, isize result_count) { Type *t = alloc_type(a, Type_Procedure); t->procedure.scope = scope; t->procedure.params = params; - t->procedure.params_count = params_count; + t->procedure.param_count = param_count; t->procedure.results = results; - t->procedure.results_count = results_count; + t->procedure.result_count = result_count; return t; } @@ -343,6 +362,10 @@ b32 are_types_identical(Type *x, Type *y) { return are_types_identical(x->pointer.element, y->pointer.element); break; + + case Type_Alias: + return are_types_identical(get_base_type(x), y); + case Type_Named: if (y->kind == Type_Named) return x->named.base == y->named.base; @@ -463,9 +486,9 @@ i64 *type_set_offsets_of(BaseTypeSizes s, gbAllocator allocator, Entity **fields b32 type_set_offsets(BaseTypeSizes s, gbAllocator allocator, Type *t) { GB_ASSERT(t->kind == Type_Structure); - if (!t->structure.offsets_set) { + if (!t->structure.are_offsets_set) { t->structure.offsets = type_set_offsets_of(s, allocator, t->structure.fields, t->structure.field_count); - t->structure.offsets_set = true; + t->structure.are_offsets_set = true; return true; } return false; @@ -571,6 +594,15 @@ gbString write_type_to_string(gbString str, Type *type) { } break; + case Type_Alias: + if (type->alias.alias_name != NULL) { + str = gb_string_append_length(str, type->alias.name.text, type->alias.name.len); + } else { + // NOTE(bill): Just in case + str = gb_string_appendc(str, ""); + } + break; + case Type_Tuple: if (type->tuple.variable_count > 0) { for (isize i = 0; i < type->tuple.variable_count; i++) { diff --git a/src/common.cpp b/src/common.cpp index 24d9e1008..5b87639cf 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -31,6 +31,19 @@ gb_inline b32 are_strings_equal(String a, String b) { return false; } +gb_inline b32 are_strings_equal_ignore_case(String a, String b) { + if (a.len == b.len) { + for (isize i = 0; i < a.len; i++) { + char x = cast(char)a.text[i]; + char y = cast(char)b.text[i]; + if (gb_char_to_lower(x) != gb_char_to_lower(y)) + return false; + } + return true; + } + return false; +} + gb_inline isize string_extension_position(String str) { isize dot_pos = -1; diff --git a/src/parser.cpp b/src/parser.cpp index 3ac0977c3..314991eef 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -112,6 +112,7 @@ AstNode__DeclarationBegin, AstNode_VariableDeclaration, AstNode_ProcedureDeclaration, AstNode_TypeDeclaration, + AstNode_AliasDeclaration, AstNode_ImportDeclaration, AstNode__DeclarationEnd, @@ -234,21 +235,16 @@ struct AstNode { AstNode *name_list; AstNode *type_expression; AstNode *value_list; - isize name_list_count, value_list_count; + isize name_count, value_count; } variable_declaration; struct { AstNode *name_list; - isize name_list_count; + isize name_count; AstNode *type_expression; } field; - struct { - Token token; - AstNode *param_list; // AstNode_Field list - isize param_count; - AstNode *results_list; // type expression list - isize result_count; - } procedure_type; + + // TODO(bill): Unify Procedure Declarations and Literals struct { DeclarationKind kind; AstNode *name; // AstNode_Identifier @@ -262,6 +258,11 @@ struct AstNode { AstNode *name; // AstNode_Identifier AstNode *type_expression; } type_declaration; + struct { + Token token; + AstNode *name; // AstNode_Identifier + AstNode *type_expression; + } alias_declaration; struct { Token token; Token filepath; @@ -282,6 +283,13 @@ struct AstNode { AstNode *field_list; // AstNode_Field isize field_count; } struct_type; + struct { + Token token; + AstNode *param_list; // AstNode_Field list + isize param_count; + AstNode *result_list; // type expression list + isize result_count; + } procedure_type; }; }; @@ -374,6 +382,8 @@ Token ast_node_token(AstNode *node) { return node->procedure_declaration.name->identifier.token; case AstNode_TypeDeclaration: return node->type_declaration.token; + case AstNode_AliasDeclaration: + return node->alias_declaration.token; case AstNode_ImportDeclaration: return node->import_declaration.token; case AstNode_Field: { @@ -717,31 +727,31 @@ gb_inline AstNode *make_bad_declaration(AstFile *f, Token begin, Token end) { return result; } -gb_inline AstNode *make_variable_declaration(AstFile *f, DeclarationKind kind, AstNode *name_list, isize name_list_count, AstNode *type_expression, AstNode *value_list, isize value_list_count) { +gb_inline AstNode *make_variable_declaration(AstFile *f, DeclarationKind kind, AstNode *name_list, isize name_count, AstNode *type_expression, AstNode *value_list, isize value_count) { AstNode *result = make_node(f, AstNode_VariableDeclaration); result->variable_declaration.kind = kind; result->variable_declaration.name_list = name_list; - result->variable_declaration.name_list_count = name_list_count; + result->variable_declaration.name_count = name_count; result->variable_declaration.type_expression = type_expression; result->variable_declaration.value_list = value_list; - result->variable_declaration.value_list_count = value_list_count; + result->variable_declaration.value_count = value_count; return result; } -gb_inline AstNode *make_field(AstFile *f, AstNode *name_list, isize name_list_count, AstNode *type_expression) { +gb_inline AstNode *make_field(AstFile *f, AstNode *name_list, isize name_count, AstNode *type_expression) { AstNode *result = make_node(f, AstNode_Field); result->field.name_list = name_list; - result->field.name_list_count = name_list_count; + result->field.name_count = name_count; result->field.type_expression = type_expression; return result; } -gb_inline AstNode *make_procedure_type(AstFile *f, Token token, AstNode *param_list, isize param_count, AstNode *results_list, isize result_count) { +gb_inline AstNode *make_procedure_type(AstFile *f, Token token, AstNode *param_list, isize param_count, AstNode *result_list, isize result_count) { AstNode *result = make_node(f, AstNode_ProcedureType); result->procedure_type.token = token; result->procedure_type.param_list = param_list; result->procedure_type.param_count = param_count; - result->procedure_type.results_list = results_list; + result->procedure_type.result_list = result_list; result->procedure_type.result_count = result_count; return result; } @@ -788,6 +798,15 @@ gb_inline AstNode *make_type_declaration(AstFile *f, Token token, AstNode *name, return result; } +gb_inline AstNode *make_alias_declaration(AstFile *f, Token token, AstNode *name, AstNode *type_expression) { + AstNode *result = make_node(f, AstNode_AliasDeclaration); + result->alias_declaration.token = token; + result->alias_declaration.name = name; + result->alias_declaration.type_expression = type_expression; + return result; +} + + gb_inline AstNode *make_import_declaration(AstFile *f, Token token, Token filepath) { AstNode *result = make_node(f, AstNode_ImportDeclaration); result->import_declaration.token = token; @@ -1293,7 +1312,7 @@ AstNode *parse_rhs_expression_list(AstFile *f, isize *list_count) { return parse_expression_list(f, false, list_count); } -AstNode *parse_declaration(AstFile *f, AstNode *name_list, isize name_list_count); +AstNode *parse_declaration(AstFile *f, AstNode *name_list, isize name_count); AstNode *parse_simple_statement(AstFile *f) { isize lhs_count = 0, rhs_count = 0; @@ -1423,9 +1442,9 @@ AstNode *parse_type(AstFile *f) { AstNode *parse_field_declaration(AstFile *f, AstScope *scope) { AstNode *name_list = NULL; - isize name_list_count = 0; - name_list = parse_lhs_expression_list(f, &name_list_count); - if (name_list_count == 0) + isize name_count = 0; + name_list = parse_lhs_expression_list(f, &name_count); + if (name_count == 0) ast_file_err(f, f->cursor[0], "Empty field declaration"); expect_token(f, Token_Colon); @@ -1434,7 +1453,7 @@ AstNode *parse_field_declaration(AstFile *f, AstScope *scope) { if (type_expression == NULL) ast_file_err(f, f->cursor[0], "Expected a type for this field declaration"); - AstNode *field = make_field(f, name_list, name_list_count, type_expression); + AstNode *field = make_field(f, name_list, name_count, type_expression); add_ast_entity(f, scope, field, name_list); return field; } @@ -1457,6 +1476,23 @@ AstNode *parse_procedure_type(AstFile *f, AstScope **scope_) { } +AstNode *parse_parameter_list(AstFile *f, AstScope *scope, isize *param_count_) { + AstNode *param_list = NULL; + AstNode *param_list_curr = NULL; + isize param_count = 0; + while (f->cursor[0].kind == Token_Identifier) { + AstNode *field = parse_field_declaration(f, scope); + DLIST_APPEND(param_list, param_list_curr, field); + param_count += field->field.name_count; + if (f->cursor[0].kind != Token_Comma) + break; + next_token(f); + } + + if (param_count_) *param_count_ = param_count; + return param_list; +} + AstNode *parse_identifier_or_type(AstFile *f) { switch (f->cursor[0].kind) { case Token_Identifier: @@ -1480,24 +1516,15 @@ AstNode *parse_identifier_or_type(AstFile *f) { case Token_struct: { Token token = expect_token(f, Token_struct); Token open, close; - AstNode *field_list = NULL; - AstNode *field_list_curr = NULL; - isize field_list_count = 0; - - open = expect_token(f, Token_OpenBrace); - + AstNode *params = NULL; + isize param_count = 0; AstScope *scope = make_ast_scope(f, NULL); // NOTE(bill): The struct needs its own scope with NO parent - while (f->cursor[0].kind == Token_Identifier || - f->cursor[0].kind == Token_Mul) { - DLIST_APPEND(field_list, field_list_curr, parse_field_declaration(f, scope)); - expect_token(f, Token_Semicolon); - field_list_count++; - } - destroy_ast_scope(scope); - close = expect_token(f, Token_CloseBrace); + open = expect_token(f, Token_OpenBrace); + params = parse_parameter_list(f, scope, ¶m_count); + close = expect_token(f, Token_CloseBrace); - return make_struct_type(f, token, field_list, field_list_count); + return make_struct_type(f, token, params, param_count); } case Token_proc: @@ -1514,6 +1541,7 @@ AstNode *parse_identifier_or_type(AstFile *f) { return make_paren_expression(f, type_expression, open, close); } + // TODO(bill): Why is this even allowed? Is this a parsing error? case Token_Colon: break; @@ -1530,24 +1558,6 @@ AstNode *parse_identifier_or_type(AstFile *f) { return NULL; } -AstNode *parse_parameters(AstFile *f, AstScope *scope, isize *param_count_) { - AstNode *param_list = NULL; - AstNode *param_list_curr = NULL; - isize param_count = 0; - expect_token(f, Token_OpenParen); - while (f->cursor[0].kind != Token_CloseParen) { - AstNode *field = parse_field_declaration(f, scope); - DLIST_APPEND(param_list, param_list_curr, field); - param_count += field->field.name_list_count; - if (f->cursor[0].kind != Token_Comma) - break; - next_token(f); - } - expect_token(f, Token_CloseParen); - - if (param_count_) *param_count_ = param_count; - return param_list; -} AstNode *parse_results(AstFile *f, AstScope *scope, isize *result_count) { if (allow_token(f, Token_ArrowRight)) { @@ -1582,7 +1592,9 @@ Token parse_procedure_signature(AstFile *f, AstScope *scope, AstNode **param_list, isize *param_count, AstNode **result_list, isize *result_count) { Token proc_token = expect_token(f, Token_proc); - *param_list = parse_parameters(f, scope, param_count); + expect_token(f, Token_OpenParen); + *param_list = parse_parameter_list(f, scope, param_count); + expect_token(f, Token_CloseParen); *result_list = parse_results(f, scope, result_count); return proc_token; } @@ -1626,10 +1638,10 @@ AstNode *parse_procedure_declaration(AstFile *f, Token proc_token, AstNode *name return make_procedure_declaration(f, kind, name, proc_type, body, tag_list, tag_count); } -AstNode *parse_declaration(AstFile *f, AstNode *name_list, isize name_list_count) { +AstNode *parse_declaration(AstFile *f, AstNode *name_list, isize name_count) { AstNode *value_list = NULL; AstNode *type_expression = NULL; - isize value_list_count = 0; + isize value_count = 0; if (allow_token(f, Token_Colon)) { type_expression = parse_identifier_or_type(f); } else if (f->cursor[0].kind != Token_Eq && f->cursor[0].kind != Token_Semicolon) { @@ -1647,26 +1659,20 @@ AstNode *parse_declaration(AstFile *f, AstNode *name_list, isize name_list_count if (f->cursor[0].kind == Token_proc) { // NOTE(bill): Procedure declarations Token proc_token = f->cursor[0]; AstNode *name = name_list; - if (name_list_count != 1) { + if (name_count != 1) { ast_file_err(f, proc_token, "You can only declare one procedure at a time (at the moment)"); return make_bad_declaration(f, name->identifier.token, proc_token); } - // TODO(bill): Allow for mutable procedures - if (declaration_kind != Declaration_Immutable) { - ast_file_err(f, proc_token, "Only immutable procedures are supported (at the moment)"); - return make_bad_declaration(f, name->identifier.token, proc_token); - } - AstNode *procedure_declaration = parse_procedure_declaration(f, proc_token, name, declaration_kind); add_ast_entity(f, f->curr_scope, procedure_declaration, name_list); return procedure_declaration; } else { - value_list = parse_rhs_expression_list(f, &value_list_count); - if (value_list_count > name_list_count) { + value_list = parse_rhs_expression_list(f, &value_count); + if (value_count > name_count) { ast_file_err(f, f->cursor[0], "Too many values on the right hand side of the declaration"); - } else if (value_list_count < name_list_count && + } else if (value_count < name_count && declaration_kind == Declaration_Immutable) { ast_file_err(f, f->cursor[0], "All constant declarations must be defined"); } else if (value_list == NULL) { @@ -1681,7 +1687,7 @@ AstNode *parse_declaration(AstFile *f, AstNode *name_list, isize name_list_count return make_bad_declaration(f, f->cursor[0], f->cursor[0]); } } else if (declaration_kind == Declaration_Immutable) { - if (type_expression == NULL && value_list == NULL && name_list_count > 0) { + if (type_expression == NULL && value_list == NULL && name_count > 0) { ast_file_err(f, f->cursor[0], "Missing constant value"); return make_bad_declaration(f, f->cursor[0], f->cursor[0]); } @@ -1692,7 +1698,7 @@ AstNode *parse_declaration(AstFile *f, AstNode *name_list, isize name_list_count return make_bad_declaration(f, begin, f->cursor[0]); } - AstNode *variable_declaration = make_variable_declaration(f, declaration_kind, name_list, name_list_count, type_expression, value_list, value_list_count); + AstNode *variable_declaration = make_variable_declaration(f, declaration_kind, name_list, name_count, type_expression, value_list, value_count); add_ast_entity(f, f->curr_scope, variable_declaration, name_list); return variable_declaration; } @@ -1858,6 +1864,21 @@ AstNode *parse_type_declaration(AstFile *f) { return type_declaration; } +AstNode *parse_alias_declaration(AstFile *f) { + Token token = expect_token(f, Token_alias); + AstNode *name = parse_identifier(f); + expect_token(f, Token_Colon); + AstNode *type_expression = parse_type(f); + + AstNode *alias_declaration = make_alias_declaration(f, token, name, type_expression); + + if (type_expression->kind != AstNode_StructType && + type_expression->kind != AstNode_ProcedureType) + expect_token(f, Token_Semicolon); + + return alias_declaration; +} + AstNode *parse_import_declaration(AstFile *f) { Token token = expect_token(f, Token_import); Token filepath = expect_token(f, Token_String); @@ -1874,6 +1895,8 @@ AstNode *parse_statement(AstFile *f) { switch (token.kind) { case Token_type: return parse_type_declaration(f); + case Token_alias: + return parse_alias_declaration(f); case Token_import: return parse_import_declaration(f); diff --git a/src/printer.cpp b/src/printer.cpp index 3ce94aefb..f0878b056 100644 --- a/src/printer.cpp +++ b/src/printer.cpp @@ -166,10 +166,10 @@ void print_ast(AstNode *node, isize indent) { print_indent(indent); gb_printf("(type:proc)(%td -> %td)\n", node->procedure_type.param_count, node->procedure_type.result_count); print_ast(node->procedure_type.param_list, indent+1); - if (node->procedure_type.results_list) { + if (node->procedure_type.result_list) { print_indent(indent+1); gb_printf("->\n"); - print_ast(node->procedure_type.results_list, indent+1); + print_ast(node->procedure_type.result_list, indent+1); } break; case AstNode_Field: diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 4263f7f52..48d1fd748 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -102,6 +102,7 @@ Token__OperatorEnd, Token__KeywordBegin, Token_type, + Token_alias, Token_proc, Token_match, // TODO(bill): switch vs match? Token_break, @@ -189,6 +190,7 @@ char const *TOKEN_STRINGS[] = { "_OperatorEnd", "_KeywordBegin", "type", + "alias", "proc", "match", "break", @@ -697,6 +699,7 @@ Token tokenizer_get_token(Tokenizer *t) { KWB KWT("type", Token_type); + KWT("alias", Token_alias); KWT("proc", Token_proc); KWT("match", Token_match); KWT("break", Token_break);