diff options
| author | Ginger Bill <bill@gingerbill.org> | 2017-07-13 16:20:07 +0100 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2017-07-13 16:20:07 +0100 |
| commit | b8697fb4ed34d0da0fa0888b57e6edcc37a0ce81 (patch) | |
| tree | fe3dd4008b6878b1b0b5015131e9a35129845123 /src | |
| parent | 03570275c1cfd14014d81bcdf085c320c1902c40 (diff) | |
Change precedence order for types e.g. ^T(x) == ^(T(x))
Diffstat (limited to 'src')
| -rw-r--r-- | src/check_decl.cpp | 2 | ||||
| -rw-r--r-- | src/check_expr.cpp | 28 | ||||
| -rw-r--r-- | src/check_stmt.cpp | 11 | ||||
| -rw-r--r-- | src/checker.cpp | 8 | ||||
| -rw-r--r-- | src/ir.cpp | 31 | ||||
| -rw-r--r-- | src/ir_print.cpp | 3 | ||||
| -rw-r--r-- | src/parser.cpp | 465 | ||||
| -rw-r--r-- | src/types.cpp | 2 |
8 files changed, 395 insertions, 155 deletions
diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 52f785ef6..96827590d 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -365,7 +365,7 @@ void init_entity_foreign_library(Checker *c, Entity *e) { String name = ident->Ident.token.string; Entity *found = scope_lookup_entity(c->context.scope, name); if (found == nullptr) { - if (name == "_") { + if (is_blank_ident(name)) { error(ident, "`_` cannot be used as a value type"); } else { error(ident, "Undeclared name: %.*s", LIT(name)); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c19fc9afb..a5557ee86 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -823,7 +823,7 @@ void check_record_field_decl(Checker *c, AstNode *decl, Array<Entity *> *fields, Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, is_using, cast(i32)fields->count); e->identifier = name; - if (name_token.string == "_") { + if (is_blank_ident(name_token)) { array_add(fields, e); } else if (name_token.string == "__tag") { error(name, "`__tag` is a reserved identifier for fields"); @@ -1223,7 +1223,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod // NOTE(bill): Skip blank identifiers - if (name == "_") { + if (is_blank_ident(name)) { continue; } else if (name == "count") { error(field, "`count` is a reserved identifier for enumerations"); @@ -1331,7 +1331,7 @@ void check_bit_field_type(Checker *c, Type *bit_field_type, Type *named_type, As e->flags |= EntityFlag_BitFieldValue; HashKey key = hash_string(name); - if (name != "_" && + if (!is_blank_ident(name) && map_get(&entity_map, key) != nullptr) { error(ident, "`%.*s` is already declared in this bit field", LIT(name)); } else { @@ -1879,12 +1879,12 @@ Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) { for (isize i = 0; i < variable_index; i++) { String x = variables[i]->token.string; - if (x.len == 0 || x == "_") { + if (x.len == 0 || is_blank_ident(x)) { continue; } for (isize j = i+1; j < variable_index; j++) { String y = variables[j]->token.string; - if (y.len == 0 || y == "_") { + if (y.len == 0 || is_blank_ident(y)) { continue; } if (x == y) { @@ -2162,7 +2162,7 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type * Entity *e = scope_lookup_entity(c->context.scope, name); if (e == nullptr) { - if (name == "_") { + if (is_blank_ident(name)) { error(n, "`_` cannot be used as a value type"); } else { error(n, "Undeclared name: %.*s", LIT(name)); @@ -2603,7 +2603,7 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type) Type *elem = check_type(c, at->elem, nullptr); i64 count = check_array_or_map_count(c, at->count, false); if (count < 0) { - error(at->count, ".. can only be used in conjuction with compound literals"); + error(at->count, "... can only be used in conjuction with compound literals"); count = 0; } #if 0 @@ -5735,7 +5735,7 @@ isize lookup_procedure_parameter(TypeProc *pt, String parameter_name) { for (isize i = 0; i < param_count; i++) { Entity *e = pt->params->Tuple.variables[i]; String name = e->token.string; - if (name == "_") { + if (is_blank_ident(name)) { continue; } if (name == parameter_name) { @@ -5749,7 +5749,7 @@ isize lookup_procedure_result(TypeProc *pt, String result_name) { for (isize i = 0; i < result_count; i++) { Entity *e = pt->results->Tuple.variables[i]; String name = e->token.string; - if (name == "_") { + if (is_blank_ident(name)) { continue; } if (name == result_name) { @@ -5818,7 +5818,7 @@ CALL_ARGUMENT_CHECKER(check_named_call_arguments) { for (isize i = 0; i < param_count_to_check; i++) { if (!visited[i]) { Entity *e = pt->params->Tuple.variables[i]; - if (e->token.string == "_") { + if (is_blank_ident(e->token)) { continue; } if (e->kind == Entity_Variable) { @@ -6664,7 +6664,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t bool all_fields_are_blank = true; for (isize i = 0; i < t->Record.field_count; i++) { Entity *field = t->Record.fields_in_src_order[i]; - if (field->token.string != "_") { + if (!is_blank_ident(field->token)) { all_fields_are_blank = false; break; } @@ -6682,7 +6682,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t } Entity *field = t->Record.fields_in_src_order[index]; - if (!all_fields_are_blank && field->token.string == "_") { + if (!all_fields_are_blank && is_blank_ident(field->token)) { // NOTE(bill): Ignore blank identifiers continue; } @@ -7599,9 +7599,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) { if (field->names.count == 0) { continue; } - AstNode *name = field->names[0]; - ast_node(n, Ident, name); - if (n->token.string != "_") { + if (!is_blank_ident(field->names[0])) { has_name = true; break; } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 4d07ce1cf..6bf873bd3 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -186,8 +186,7 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) { AstNode *node = unparen_expr(lhs_node); // NOTE(bill): Ignore assignments to `_` - if (node->kind == AstNode_Ident && - node->Ident.token.string == "_") { + if (is_blank_ident(node)) { add_entity_definition(&c->info, node, nullptr); check_assignment(c, rhs, nullptr, str_lit("assignment to `_` identifier")); if (rhs->mode == Addressing_Invalid) { @@ -429,7 +428,7 @@ void check_label(Checker *c, AstNode *label) { return; } String name = l->name->Ident.token.string; - if (name == "_") { + if (is_blank_ident(name)) { error(l->name, "A label's name cannot be a blank identifier"); return; } @@ -884,7 +883,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { for (isize i = 0; i < result_count; i++) { if (!visited[i]) { Entity *e = pt->results->Tuple.variables[i]; - if (e->token.string == "_") { + if (is_blank_ident(e->token)) { continue; } GB_ASSERT(e->kind == Entity_Variable); @@ -1133,7 +1132,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { String str = token.string; Entity *found = nullptr; - if (str != "_") { + if (!is_blank_ident(str)) { found = current_scope_lookup_entity(c->context.scope, str); } if (found == nullptr) { @@ -1686,7 +1685,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { String str = token.string; Entity *found = nullptr; // NOTE(bill): Ignore assignments to `_` - if (str != "_") { + if (!is_blank_ident(str)) { found = current_scope_lookup_entity(c->context.scope, str); } if (found == nullptr) { diff --git a/src/checker.cpp b/src/checker.cpp index e2133144f..d7882414a 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -979,7 +979,7 @@ void add_type_and_value(CheckerInfo *i, AstNode *expression, AddressingMode mode void add_entity_definition(CheckerInfo *i, AstNode *identifier, Entity *entity) { GB_ASSERT(identifier != nullptr); if (identifier->kind == AstNode_Ident) { - if (identifier->Ident.token.string == "_") { + if (is_blank_ident(identifier)) { return; } HashKey key = hash_node(identifier); @@ -994,7 +994,7 @@ bool add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) { return false; } String name = entity->token.string; - if (name != "_") { + if (!is_blank_ident(name)) { Entity *ie = scope_insert_entity(scope, entity); if (ie) { TokenPos pos = ie->token.pos; @@ -2202,7 +2202,7 @@ void check_import_entities(Checker *c, Map<Scope *> *file_scopes) { } } else { String import_name = path_to_entity_name(id->import_name.string, id->fullpath); - if (import_name == "_") { + if (is_blank_ident(import_name)) { error(token, "File name, %.*s, cannot be as an import name as it is not a valid identifier", LIT(id->import_name.string)); } else { GB_ASSERT(id->import_name.pos.line != 0); @@ -2254,7 +2254,7 @@ void check_import_entities(Checker *c, Map<Scope *> *file_scopes) { String library_name = path_to_entity_name(fl->library_name.string, file_str); - if (library_name == "_") { + if (is_blank_ident(library_name)) { error(spec, "File name, %.*s, cannot be as a library name as it is not a valid identifier", LIT(fl->library_name.string)); } else { GB_ASSERT(fl->library_name.pos.line != 0); diff --git a/src/ir.cpp b/src/ir.cpp index b11255cf1..8746b676b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -653,13 +653,6 @@ Type *ir_type(irValue *value) { } -bool ir_is_blank_ident(AstNode *node) { - if (node->kind == AstNode_Ident) { - ast_node(i, Ident, node); - return is_blank_ident(i->token.string); - } - return false; -} irInstr *ir_get_last_instr(irBlock *block) { @@ -5001,7 +4994,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { case_end; case_ast_node(i, Ident, expr); - if (ir_is_blank_ident(expr)) { + if (is_blank_ident(expr)) { irAddr val = {}; return val; } @@ -5614,6 +5607,15 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { return ir_addr(v); case_end; + + case_ast_node(tc, TypeCast, expr); + Type *type = type_of_expr(proc->module->info, expr); + irValue *x = ir_build_expr(proc, tc->expr); + irValue *e = ir_emit_conv(proc, x, type); + irValue *v = ir_add_local_generated(proc, type); + ir_emit_store(proc, v, e); + return ir_addr(v); + case_end; } TokenPos token_pos = ast_node_token(expr).pos; @@ -6143,7 +6145,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { if (vd->values.count == 0) { // declared and zero-initialized for_array(i, vd->names) { AstNode *name = vd->names[i]; - if (!ir_is_blank_ident(name)) { + if (!is_blank_ident(name)) { ir_add_local_for_identifier(proc, name, true); } } @@ -6156,7 +6158,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { for_array(i, vd->names) { AstNode *name = vd->names[i]; irAddr lval = ir_addr(nullptr); - if (!ir_is_blank_ident(name)) { + if (!is_blank_ident(name)) { ir_add_local_for_identifier(proc, name, false); lval = ir_build_addr(proc, name); } @@ -6200,7 +6202,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { for_array(i, as->lhs) { AstNode *lhs = as->lhs[i]; irAddr lval = {}; - if (!ir_is_blank_ident(lhs)) { + if (!is_blank_ident(lhs)) { lval = ir_build_addr(proc, lhs); } array_add(&lvals, lval); @@ -6498,10 +6500,10 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { Type *val_type = nullptr; Type *idx_type = nullptr; - if (rs->value != nullptr && !ir_is_blank_ident(rs->value)) { + if (rs->value != nullptr && !is_blank_ident(rs->value)) { val_type = type_of_expr(proc->module->info, rs->value); } - if (rs->index != nullptr && !ir_is_blank_ident(rs->index)) { + if (rs->index != nullptr && !is_blank_ident(rs->index)) { idx_type = type_of_expr(proc->module->info, rs->index); } @@ -7073,8 +7075,7 @@ void ir_begin_procedure_body(irProcedure *proc) { } Type *abi_type = proc->type->Proc.abi_compat_params[i]; - if (e->token.string != "" && - e->token.string != "_") { + if (e->token.string != "" && !is_blank_ident(e->token)) { irValue *param = ir_add_param(proc, e, name, abi_type); array_add(&proc->params, param); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index bad0e6eca..7bd79fe2e 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1580,8 +1580,7 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { ir_fprintf(f, " noalias"); } if (proc->body != nullptr) { - if (e->token.string != "" && - e->token.string != "_") { + if (e->token.string != "" && !is_blank_ident(e->token)) { ir_fprintf(f, " "); ir_print_encoded_local(f, e->token.string); } else { diff --git a/src/parser.cpp b/src/parser.cpp index 6836e901f..a2d8ab1f9 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -35,6 +35,7 @@ struct AstFile { isize expr_level; bool allow_range; // NOTE(bill): Ranges are only allowed in certain cases bool in_foreign_block; + bool allow_type; Array<AstNode *> decls; bool is_global_scope; @@ -712,6 +713,10 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) { n->TypeAssertion.expr = clone_ast_node(a, n->TypeAssertion.expr); n->TypeAssertion.type = clone_ast_node(a, n->TypeAssertion.type); break; + case AstNode_TypeCast: + n->TypeCast.type = clone_ast_node(a, n->TypeCast.type); + n->TypeCast.expr = clone_ast_node(a, n->TypeCast.expr); + break; case AstNode_BadStmt: break; case AstNode_EmptyStmt: break; @@ -1623,39 +1628,39 @@ CommentGroup consume_comment_group(AstFile *f, isize n, isize *end_line_) { return comments; } +void comsume_comment_groups(AstFile *f, Token prev) { + if (f->curr_token.kind != Token_Comment) return; + CommentGroup comment = {}; + isize end_line = 0; -bool next_token(AstFile *f) { - gb_zero_item(&f->lead_comment); - gb_zero_item(&f->line_comment); - Token prev = f->prev_token = f->curr_token; - - bool ok = next_token0(f); - if (!ok) { - return false; - } - if (f->curr_token.kind == Token_Comment) { - CommentGroup comment = {}; - isize end_line = 0; - - if (f->curr_token.pos.line == prev.pos.line) { - comment = consume_comment_group(f, 0, &end_line); - if (f->curr_token.pos.line != end_line) { - f->line_comment = comment; - } + if (f->curr_token.pos.line == prev.pos.line) { + comment = consume_comment_group(f, 0, &end_line); + if (f->curr_token.pos.line != end_line) { + f->line_comment = comment; } + } - end_line = -1; - while (f->curr_token.kind == Token_Comment) { - comment = consume_comment_group(f, 1, &end_line); - } + end_line = -1; + while (f->curr_token.kind == Token_Comment) { + comment = consume_comment_group(f, 1, &end_line); + } - if (end_line+1 == f->curr_token.pos.line) { - f->lead_comment = comment; - } + if (end_line+1 == f->curr_token.pos.line) { + f->lead_comment = comment; } + GB_ASSERT(f->curr_token.kind != Token_Comment); +} - return true; + +Token advance_token(AstFile *f) { + gb_zero_item(&f->lead_comment); + gb_zero_item(&f->line_comment); + Token prev = f->prev_token = f->curr_token; + + bool ok = next_token0(f); + if (ok) comsume_comment_groups(f, prev); + return prev; } TokenKind look_ahead_token_kind(AstFile *f, isize amount) { @@ -1685,7 +1690,7 @@ Token expect_token(AstFile *f, TokenKind kind) { } } - next_token(f); + advance_token(f); return prev; } @@ -1698,7 +1703,7 @@ Token expect_token_after(AstFile *f, TokenKind kind, char *msg) { msg, LIT(p)); } - next_token(f); + advance_token(f); return prev; } @@ -1712,7 +1717,7 @@ Token expect_operator(AstFile *f) { syntax_error(f->curr_token, "Expected an non-range operator, got `%.*s`", LIT(token_strings[prev.kind])); } - next_token(f); + advance_token(f); return prev; } @@ -1722,14 +1727,14 @@ Token expect_keyword(AstFile *f) { syntax_error(f->curr_token, "Expected a keyword, got `%.*s`", LIT(token_strings[prev.kind])); } - next_token(f); + advance_token(f); return prev; } bool allow_token(AstFile *f, TokenKind kind) { Token prev = f->curr_token; if (prev.kind == kind) { - next_token(f); + advance_token(f); return true; } return false; @@ -1742,6 +1747,20 @@ bool is_blank_ident(String str) { } return false; } +bool is_blank_ident(Token token) { + if (token.kind == Token_Ident) { + return is_blank_ident(token.string); + } + return false; +} +bool is_blank_ident(AstNode *node) { + if (node->kind == AstNode_Ident) { + ast_node(i, Ident, node); + return is_blank_ident(i->token.string); + } + return false; +} + // NOTE(bill): Go to next statement to prevent numerous error messages popping up @@ -1791,7 +1810,7 @@ void fix_advance_to_next_stmt(AstFile *f) { // NOTE(bill): Reaching here means there is a parsing bug } break; } - next_token(f); + advance_token(f); } #endif } @@ -1801,7 +1820,7 @@ Token expect_closing(AstFile *f, TokenKind kind, String context) { f->curr_token.kind == Token_Semicolon && f->curr_token.string == "\n") { error(f->curr_token, "Missing `,` before newline in %.*s", LIT(context)); - next_token(f); + advance_token(f); } return expect_token(f, kind); } @@ -1923,7 +1942,7 @@ AstNode * parse_body(AstFile *f); AstNode *parse_ident(AstFile *f) { Token token = f->curr_token; if (token.kind == Token_Ident) { - next_token(f); + advance_token(f); } else { token.string = str_lit("_"); expect_token(f, Token_Ident); @@ -2079,7 +2098,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *link_name, ProcCallingConven syntax_error(tag_expr, "Invalid alternative link procedure name `%.*s`", LIT(*link_name)); } - next_token(f); + advance_token(f); } else { expect_token(f, Token_String); } @@ -2157,11 +2176,12 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *link_name, ProcCallingConven } -Array<AstNode *> parse_lhs_expr_list(AstFile *f); -Array<AstNode *> parse_rhs_expr_list(AstFile *f); -AstNode * parse_simple_stmt (AstFile *f, StmtAllowFlag flags); -AstNode * parse_type (AstFile *f); -AstNode * parse_call_expr (AstFile *f, AstNode *operand); +Array<AstNode *> parse_lhs_expr_list (AstFile *f); +Array<AstNode *> parse_rhs_expr_list (AstFile *f); +AstNode * parse_simple_stmt (AstFile *f, StmtAllowFlag flags); +AstNode * parse_type (AstFile *f); +AstNode * parse_call_expr (AstFile *f, AstNode *operand); +AstNode * parse_record_field_list(AstFile *f, isize *name_count_); AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) { if (statement == nullptr) { @@ -2195,6 +2215,7 @@ AstNode *convert_stmt_to_body(AstFile *f, AstNode *stmt) { + AstNode *parse_operand(AstFile *f, bool lhs) { AstNode *operand = nullptr; // Operand switch (f->curr_token.kind) { @@ -2211,21 +2232,16 @@ AstNode *parse_operand(AstFile *f, bool lhs) { case Token_Float: case Token_Imag: case Token_Rune: - operand = ast_basic_lit(f, f->curr_token); - next_token(f); - return operand; + return ast_basic_lit(f, advance_token(f)); case Token_size_of: case Token_align_of: - case Token_offset_of: { - operand = ast_implicit(f, f->curr_token); next_token(f); - return parse_call_expr(f, operand); - } + case Token_offset_of: + return parse_call_expr(f, ast_implicit(f, advance_token(f))); case Token_String: { - Token token = f->curr_token; - next_token(f); + Token token = advance_token(f); if (f->curr_token.kind == Token_String) { // NOTE(bill): Allow neighbouring string literals to be merge together to // become one big string @@ -2240,7 +2256,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) { isize old_count = data.count; array_resize(&data, data.count + s.len); gb_memmove(data.data+old_count, s.text, s.len); - next_token(f); + advance_token(f); } token.string = make_string(data.data, data.count); @@ -2332,7 +2348,242 @@ AstNode *parse_operand(AstFile *f, bool lhs) { return type; } + + // Check for Types + case Token_Dollar: { + Token token = expect_token(f, Token_Dollar); + AstNode *type = parse_ident(f); + return ast_poly_type(f, token, type); + } break; + + case Token_type_of: { + AstNode *i = ast_implicit(f, expect_token(f, Token_type_of)); + AstNode *type = parse_call_expr(f, i); + while (f->curr_token.kind == Token_Period) { + Token token = advance_token(f); + AstNode *sel = parse_ident(f); + type = ast_selector_expr(f, token, type, sel); + } + return type; + } break; + + case Token_Pointer: { + Token token = expect_token(f, Token_Pointer); + AstNode *elem = parse_type(f); + return ast_pointer_type(f, token, elem); + } break; + + case Token_atomic: { + Token token = expect_token(f, Token_atomic); + AstNode *elem = parse_type(f); + return ast_atomic_type(f, token, elem); + } break; + + case Token_OpenBracket: { + Token token = expect_token(f, Token_OpenBracket); + AstNode *count_expr = nullptr; + bool is_vector = false; + + if (f->curr_token.kind == Token_Ellipsis) { + count_expr = ast_unary_expr(f, expect_token(f, Token_Ellipsis), nullptr); + } else if (allow_token(f, Token_vector)) { + if (f->curr_token.kind != Token_CloseBracket) { + f->expr_level++; + count_expr = parse_expr(f, false); + f->expr_level--; + } else { + syntax_error(f->curr_token, "Vector type missing count"); + } + is_vector = true; + } else if (allow_token(f, Token_dynamic)) { + expect_token(f, Token_CloseBracket); + return ast_dynamic_array_type(f, token, parse_type(f)); + } else if (f->curr_token.kind != Token_CloseBracket) { + f->expr_level++; + count_expr = parse_expr(f, false); + f->expr_level--; + } + expect_token(f, Token_CloseBracket); + if (is_vector) { + return ast_vector_type(f, token, count_expr, parse_type(f)); + } + return ast_array_type(f, token, count_expr, parse_type(f)); + } break; + + case Token_map: { + Token token = expect_token(f, Token_map); + AstNode *count = nullptr; + AstNode *key = nullptr; + AstNode *value = nullptr; + + Token open = expect_token_after(f, Token_OpenBracket, "map"); + key = parse_expr(f, true); + if (allow_token(f, Token_Comma)) { + count = key; + key = parse_type(f); + } + Token close = expect_token(f, Token_CloseBracket); + value = parse_type(f); + + return ast_map_type(f, token, count, key, value); + } break; + + case Token_struct: { + Token token = expect_token(f, Token_struct); + bool is_packed = false; + bool is_ordered = false; + AstNode *align = nullptr; + + isize prev_level = f->expr_level; + f->expr_level = -1; + + while (allow_token(f, Token_Hash)) { + Token tag = expect_token_after(f, Token_Ident, "#"); + if (tag.string == "packed") { + if (is_packed) { + syntax_error(tag, "Duplicate struct tag `#%.*s`", LIT(tag.string)); + } + is_packed = true; + } else if (tag.string == "ordered") { + if (is_ordered) { + syntax_error(tag, "Duplicate struct tag `#%.*s`", LIT(tag.string)); + } + is_ordered = true; + } else if (tag.string == "align") { + if (align) { + syntax_error(tag, "Duplicate struct tag `#%.*s`", LIT(tag.string)); + } + align = parse_expr(f, true); + } else { + syntax_error(tag, "Invalid struct tag `#%.*s`", LIT(tag.string)); + } + } + + f->expr_level = prev_level; + + if (is_packed && is_ordered) { + syntax_error(token, "`#ordered` is not needed with `#packed` which implies ordering"); + } + + Token open = expect_token_after(f, Token_OpenBrace, "struct"); + + isize name_count = 0; + AstNode *fields = parse_record_field_list(f, &name_count); + Token close = expect_token(f, Token_CloseBrace); + + Array<AstNode *> decls = {}; + if (fields != nullptr) { + GB_ASSERT(fields->kind == AstNode_FieldList); + decls = fields->FieldList.list; + } + + return ast_struct_type(f, token, decls, name_count, is_packed, is_ordered, align); + } break; + + case Token_union: { + Token token = expect_token(f, Token_union); + Token open = expect_token_after(f, Token_OpenBrace, "union"); + Array<AstNode *> variants = make_ast_node_array(f); + isize total_decl_name_count = 0; + + CommentGroup docs = f->lead_comment; + Token start_token = f->curr_token; + + + while (f->curr_token.kind != Token_CloseBrace && + f->curr_token.kind != Token_EOF) { + AstNode *type = parse_type(f); + if (type->kind != AstNode_BadExpr) { + array_add(&variants, type); + } + if (!allow_token(f, Token_Comma)) { + break; + } + } + + Token close = expect_token(f, Token_CloseBrace); + + return ast_union_type(f, token, variants); + } break; + + case Token_raw_union: { + Token token = expect_token(f, Token_raw_union); + Token open = expect_token_after(f, Token_OpenBrace, "raw_union"); + + isize decl_count = 0; + AstNode *fields = parse_record_field_list(f, &decl_count); + Token close = expect_token(f, Token_CloseBrace); + + Array<AstNode *> decls = {}; + if (fields != nullptr) { + GB_ASSERT(fields->kind == AstNode_FieldList); + decls = fields->FieldList.list; + } + + return ast_raw_union_type(f, token, decls, decl_count); + } break; + + case Token_enum: { + Token token = expect_token(f, Token_enum); + AstNode *base_type = nullptr; + if (f->curr_token.kind != Token_OpenBrace) { + base_type = parse_type(f); + } + Token open = expect_token(f, Token_OpenBrace); + + Array<AstNode *> values = parse_element_list(f); + Token close = expect_token(f, Token_CloseBrace); + + return ast_enum_type(f, token, base_type, values); + } break; + + case Token_bit_field: { + Token token = expect_token(f, Token_bit_field); + Array<AstNode *> fields = make_ast_node_array(f); + AstNode *align = nullptr; + Token open, close; + + isize prev_level = f->expr_level; + f->expr_level = -1; + + while (allow_token(f, Token_Hash)) { + Token tag = expect_token_after(f, Token_Ident, "#"); + if (tag.string == "align") { + if (align) { + syntax_error(tag, "Duplicate bit_field tag `#%.*s`", LIT(tag.string)); + } + align = parse_expr(f, true); + } else { + syntax_error(tag, "Invalid bit_field tag `#%.*s`", LIT(tag.string)); + } + } + + f->expr_level = prev_level; + + open = expect_token_after(f, Token_OpenBrace, "bit_field"); + + while (f->curr_token.kind != Token_EOF && + f->curr_token.kind != Token_CloseBrace) { + AstNode *name = parse_ident(f); + Token colon = expect_token(f, Token_Colon); + AstNode *value = parse_expr(f, true); + + AstNode *field = ast_field_value(f, name, value, colon); + array_add(&fields, field); + + if (f->curr_token.kind != Token_Comma) { + break; + } + advance_token(f); + } + + close = expect_token(f, Token_CloseBrace); + + return ast_bit_field_type(f, token, fields, align); + } break; + default: { + #if 0 AstNode *type = parse_type_or_ident(f); if (type != nullptr) { // TODO(bill): Is this correct??? @@ -2341,6 +2592,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) { GB_ASSERT_MSG(type->kind != AstNode_Ident, "Type cannot be identifier %.*s(%td:%td)", LIT(pos.file), pos.line, pos.column); return type; } + #endif break; } } @@ -2385,7 +2637,7 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) { if (f->curr_token.kind == Token_Ellipsis) { prefix_ellipsis = true; ellipsis = f->curr_token; - next_token(f); + advance_token(f); } AstNode *arg = parse_expr(f, false); @@ -2397,7 +2649,7 @@ AstNode *parse_call_expr(AstFile *f, AstNode *operand) { } if (f->curr_token.kind == Token_Ellipsis) { ellipsis = f->curr_token; - next_token(f); + advance_token(f); } AstNode *value = parse_value(f); @@ -2450,6 +2702,7 @@ AstNode *parse_macro_call_expr(AstFile *f, AstNode *operand) { AstNode *parse_atom_expr(AstFile *f, AstNode *operand, bool lhs) { if (operand == nullptr) { + if (f->allow_type) return nullptr; Token begin = f->curr_token; syntax_error(begin, "Expected an operand"); fix_advance_to_next_stmt(f); @@ -2467,8 +2720,7 @@ AstNode *parse_atom_expr(AstFile *f, AstNode *operand, bool lhs) { break; case Token_Period: { - Token token = f->curr_token; - next_token(f); + Token token = advance_token(f); switch (f->curr_token.kind) { case Token_Ident: operand = ast_selector_expr(f, token, operand, parse_ident(f)); @@ -2485,7 +2737,7 @@ AstNode *parse_atom_expr(AstFile *f, AstNode *operand, bool lhs) { default: syntax_error(f->curr_token, "Expected a selector"); - next_token(f); + advance_token(f); operand = ast_bad_expr(f, ast_node_token(operand), f->curr_token); // operand = ast_selector_expr(f, f->curr_token, operand, nullptr); break; @@ -2516,8 +2768,7 @@ AstNode *parse_atom_expr(AstFile *f, AstNode *operand, bool lhs) { while ((f->curr_token.kind == Token_Ellipsis || f->curr_token.kind == Token_HalfClosed) && ellipsis_count < gb_count_of(ellipses)) { - ellipses[ellipsis_count++] = f->curr_token; - next_token(f); + ellipses[ellipsis_count++] = advance_token(f); if (f->curr_token.kind != Token_Ellipsis && f->curr_token.kind != Token_HalfClosed && f->curr_token.kind != Token_CloseBracket && @@ -2583,8 +2834,7 @@ AstNode *parse_unary_expr(AstFile *f, bool lhs) { case Token_Not: case Token_Xor: case Token_And: { - Token op = f->curr_token; - next_token(f); + Token op = advance_token(f); return ast_unary_expr(f, op, parse_unary_expr(f, lhs)); } break; case Token_cast: { @@ -2703,7 +2953,7 @@ Array<AstNode *> parse_expr_list(AstFile *f, bool lhs) { f->curr_token.kind == Token_EOF) { break; } - next_token(f); + advance_token(f); } return list; @@ -2726,7 +2976,7 @@ Array<AstNode *> parse_ident_list(AstFile *f) { f->curr_token.kind == Token_EOF) { break; } - next_token(f); + advance_token(f); } while (true); return list; @@ -2744,9 +2994,8 @@ AstNode *parse_type_attempt(AstFile *f) { AstNode *parse_type(AstFile *f) { AstNode *type = parse_type_attempt(f); if (type == nullptr) { - Token token = f->curr_token; + Token token = advance_token(f); syntax_error(token, "Expected a type"); - next_token(f); return ast_bad_expr(f, token, f->curr_token); } return type; @@ -2798,20 +3047,18 @@ PARSE_SPEC_FUNC(parse_import_spec) { switch (f->curr_token.kind) { case Token_Period: - import_name = f->curr_token; + import_name = advance_token(f); import_name.kind = Token_Ident; - next_token(f); break; case Token_Ident: - import_name = f->curr_token; - next_token(f); + import_name = advance_token(f); break; default: import_name.pos = f->curr_token.pos; break; } - if (import_name.string == "_") { + if (is_blank_ident(import_name)) { syntax_error(import_name, "Illegal import name: `_`"); } @@ -2856,15 +3103,13 @@ PARSE_SPEC_FUNC(parse_foreign_library_spec) { switch (f->curr_token.kind) { case Token_Ident: - lib_name = f->curr_token; - next_token(f); + lib_name = advance_token(f); break; default: lib_name.pos = f->curr_token.pos; break; } - - if (lib_name.string == "_") { + if (is_blank_ident(lib_name)) { syntax_error(lib_name, "Illegal foreign_library name: `_`"); } Token file_path = expect_token(f, Token_String); @@ -2887,15 +3132,14 @@ PARSE_SPEC_FUNC(parse_foreign_library_spec) { switch (f->curr_token.kind) { case Token_Ident: - lib_name = f->curr_token; - next_token(f); + lib_name = advance_token(f); break; default: lib_name.pos = f->curr_token.pos; break; } - if (lib_name.string == "_") { + if (is_blank_ident(lib_name)) { syntax_error(lib_name, "Illegal foreign_library name: `_`"); } Token file_path = expect_token(f, Token_String); @@ -2986,9 +3230,7 @@ AstNode *parse_decl(AstFile *f) { } } - Token token = f->curr_token; - next_token(f); - return parse_gen_decl(f, token, func); + return parse_gen_decl(f, advance_token(f), func); } AstNode *parse_value_decl(AstFile *f, Array<AstNode *> names, CommentGroup docs) { @@ -3002,7 +3244,7 @@ AstNode *parse_value_decl(AstFile *f, Array<AstNode *> names, CommentGroup docs) if (f->curr_token.kind == Token_Eq || f->curr_token.kind == Token_Colon) { - Token sep = f->curr_token; next_token(f); + Token sep = advance_token(f); is_mutable = sep.kind != Token_Colon; values = parse_rhs_expr_list(f); if (values.count > names.count) { @@ -3073,7 +3315,7 @@ AstNode *parse_simple_stmt(AstFile *f, StmtAllowFlag flags) { syntax_error(f->curr_token, "You cannot use a simple statement in the file scope"); return ast_bad_stmt(f, f->curr_token, f->curr_token); } - next_token(f); + advance_token(f); Array<AstNode *> rhs = parse_rhs_expr_list(f); if (rhs.count == 0) { syntax_error(token, "No right-hand side in assignment statement."); @@ -3103,7 +3345,7 @@ AstNode *parse_simple_stmt(AstFile *f, StmtAllowFlag flags) { switch (next) { case Token_for: case Token_match: { - next_token(f); + advance_token(f); AstNode *name = lhs[0]; AstNode *label = ast_label_decl(f, ast_node_token(name), name); AstNode *stmt = parse_stmt(f); @@ -3135,7 +3377,7 @@ AstNode *parse_simple_stmt(AstFile *f, StmtAllowFlag flags) { switch (token.kind) { case Token_Inc: case Token_Dec: - next_token(f); + advance_token(f); return ast_inc_dec_stmt(f, token, lhs[0]); } @@ -3212,8 +3454,7 @@ AstNode *parse_proc_type(AstFile *f, Token proc_token, String *link_name_) { AstNode *parse_var_type(AstFile *f, bool allow_ellipsis, bool allow_type_token) { if (allow_ellipsis && f->curr_token.kind == Token_Ellipsis) { - Token tok = f->curr_token; - next_token(f); + Token tok = advance_token(f); AstNode *type = parse_type_or_ident(f); if (type == nullptr) { error(tok, "variadic field missing type after `...`"); @@ -3254,7 +3495,7 @@ FieldPrefixKind is_token_field_prefix(AstFile *f) { return FieldPrefix_Using; case Token_Hash: { - next_token(f); + advance_token(f); switch (f->curr_token.kind) { case Token_Ident: if (f->curr_token.string == "no_alias") { @@ -3282,9 +3523,9 @@ u32 parse_field_prefixes(AstFile *f) { break; } switch (kind) { - case FieldPrefix_Using: using_count += 1; next_token(f); break; - case FieldPrefix_NoAlias: no_alias_count += 1; next_token(f); break; - case FieldPrefix_CVarArg: c_vararg_count += 1; next_token(f); break; + case FieldPrefix_Using: using_count += 1; advance_token(f); break; + case FieldPrefix_NoAlias: no_alias_count += 1; advance_token(f); break; + case FieldPrefix_CVarArg: c_vararg_count += 1; advance_token(f); break; } } if (using_count > 1) syntax_error(f->curr_token, "Multiple `using` in this field list"); @@ -3358,8 +3599,8 @@ bool parse_expect_field_separator(AstFile *f, AstNode *param) { return true; } if (token.kind == Token_Semicolon) { - next_token(f); error(f->curr_token, "Expected a comma, got a semicolon"); + advance_token(f); return true; } return false; @@ -3372,8 +3613,8 @@ bool parse_expect_struct_separator(AstFile *f, AstNode *param) { } if (token.kind == Token_Colon) { - next_token(f); error(f->curr_token, "Expected a semicolon, got a comma"); + advance_token(f); return true; } @@ -3453,7 +3694,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok if (f->curr_token.kind != Token_Comma) { break; } - next_token(f); + advance_token(f); } if (f->curr_token.kind == Token_Colon) { @@ -3555,6 +3796,14 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok } AstNode *parse_type_or_ident(AstFile *f) { +#if 1 + bool prev_allow_type = f->allow_type; + f->allow_type = true; + AstNode *operand = parse_operand(f, true); + AstNode *type = parse_atom_expr(f, operand, true); + f->allow_type = prev_allow_type; + return type; +#else switch (f->curr_token.kind) { case Token_Dollar: { Token token = expect_token(f, Token_Dollar); @@ -3566,8 +3815,7 @@ AstNode *parse_type_or_ident(AstFile *f) { AstNode *i = ast_implicit(f, expect_token(f, Token_type_of)); AstNode *type = parse_call_expr(f, i); while (f->curr_token.kind == Token_Period) { - Token token = f->curr_token; - next_token(f); + Token token = advance_token(f); AstNode *sel = parse_ident(f); type = ast_selector_expr(f, token, type, sel); } @@ -3577,8 +3825,7 @@ AstNode *parse_type_or_ident(AstFile *f) { case Token_Ident: { AstNode *e = parse_ident(f); while (f->curr_token.kind == Token_Period) { - Token token = f->curr_token; - next_token(f); + Token token = advance_token(f); AstNode *sel = parse_ident(f); e = ast_selector_expr(f, token, e, sel); } @@ -3616,8 +3863,7 @@ AstNode *parse_type_or_ident(AstFile *f) { if (f->curr_token.kind == Token_Ellipsis) { count_expr = ast_unary_expr(f, expect_token(f, Token_Ellipsis), nullptr); - } else if (f->curr_token.kind == Token_vector) { - next_token(f); + } else if (allow_token(f, Token_vector)) { if (f->curr_token.kind != Token_CloseBracket) { f->expr_level++; count_expr = parse_expr(f, false); @@ -3626,8 +3872,7 @@ AstNode *parse_type_or_ident(AstFile *f) { syntax_error(f->curr_token, "Vector type missing count"); } is_vector = true; - } else if (f->curr_token.kind == Token_dynamic) { - next_token(f); + } else if (allow_token(f, Token_dynamic)) { expect_token(f, Token_CloseBracket); return ast_dynamic_array_type(f, token, parse_type(f)); } else if (f->curr_token.kind != Token_CloseBracket) { @@ -3806,7 +4051,7 @@ AstNode *parse_type_or_ident(AstFile *f) { if (f->curr_token.kind != Token_Comma) { break; } - next_token(f); + advance_token(f); } close = expect_token(f, Token_CloseBrace); @@ -3815,7 +4060,7 @@ AstNode *parse_type_or_ident(AstFile *f) { } break; case Token_proc: { - Token token = f->curr_token; next_token(f); + Token token = advance_token(f); AstNode *pt = parse_proc_type(f, token, nullptr); if (pt->ProcType.tags != 0) { syntax_error(token, "A procedure type cannot have tags"); @@ -3832,6 +4077,7 @@ AstNode *parse_type_or_ident(AstFile *f) { } return nullptr; +#endif } @@ -3984,7 +4230,7 @@ AstNode *parse_return_stmt(AstFile *f) { f->curr_token.kind == Token_EOF) { break; } - next_token(f); + advance_token(f); } AstNode *end = nullptr; @@ -4061,8 +4307,7 @@ AstNode *parse_for_stmt(AstFile *f) { } } - if (!is_range && f->curr_token.kind == Token_Semicolon) { - next_token(f); + if (!is_range && allow_token(f, Token_Semicolon)) { init = cond; cond = nullptr; if (f->curr_token.kind != Token_Semicolon) { @@ -4291,8 +4536,8 @@ AstNode *parse_stmt(AstFile *f) { case Token_break: case Token_continue: case Token_fallthrough: { + Token token = advance_token(f); AstNode *label = nullptr; - next_token(f); if (token.kind != Token_fallthrough && f->curr_token.kind == Token_Ident) { label = parse_ident(f); @@ -4333,7 +4578,7 @@ AstNode *parse_stmt(AstFile *f) { } break; case Token_push_allocator: { - next_token(f); + advance_token(f); AstNode *body = nullptr; isize prev_level = f->expr_level; f->expr_level = -1; @@ -4350,7 +4595,7 @@ AstNode *parse_stmt(AstFile *f) { } break; case Token_push_context: { - next_token(f); + advance_token(f); AstNode *body = nullptr; isize prev_level = f->expr_level; f->expr_level = -1; @@ -4432,7 +4677,7 @@ AstNode *parse_stmt(AstFile *f) { case Token_Semicolon: s = ast_empty_stmt(f, token); - next_token(f); + advance_token(f); return s; } @@ -4694,9 +4939,7 @@ void parse_file(Parser *p, AstFile *f) { base_dir.len--; } - while (f->curr_token.kind == Token_Comment) { - next_token(f); - } + comsume_comment_groups(f, f->prev_token); f->decls = parse_stmt_list(f); parse_setup_file_decls(p, f, base_dir, f->decls); diff --git a/src/types.cpp b/src/types.cpp index 1604ec3f2..d25f3fba9 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1476,7 +1476,7 @@ Entity *current_scope_lookup_entity(Scope *s, String name); Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_name, bool is_type, Selection sel) { GB_ASSERT(type_ != nullptr); - if (field_name == "_") { + if (is_blank_ident(field_name)) { return empty_selection; } |