diff --git a/code/demo.odin b/code/demo.odin index 7e330eefa..c5ab3698b 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -253,7 +253,7 @@ explicit_parametric_polymorphic_procedures :: proc() { // A more complicated example using subtyping // Something like this could be used in a game - Vector2 :: struct {x, y: f32}; + Vector2 :: struct {x, y: f32;}; Entity :: struct { using position: Vector2; diff --git a/core/_soft_numbers.odin b/core/_soft_numbers.odin index 8f6751408..4e0da58ba 100644 --- a/core/_soft_numbers.odin +++ b/core/_soft_numbers.odin @@ -8,12 +8,12 @@ __multi3 :: proc(a, b: u128) -> u128 #cc_c #link_name "__multi3" { when ODIN_ENDIAN == "bit" { TWords :: raw_union { all: u128; - using _: struct {lo, hi: u64}; + using _: struct {lo, hi: u64;}; }; } else { TWords :: raw_union { all: u128; - using _: struct {hi, lo: u64}; + using _: struct {hi, lo: u64;}; }; } diff --git a/core/fmt.odin b/core/fmt.odin index 98406096f..f21a36949 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -10,8 +10,8 @@ import ( _BUFFER_SIZE :: 1<<12; StringBuffer :: union { - Static {buf: []u8}; - Dynamic{buf: [dynamic]u8}; + Static {buf: []u8;}; + Dynamic{buf: [dynamic]u8;}; } FmtInfo :: struct { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f0fc0f0e7..f807d3402 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -710,21 +710,36 @@ isize check_fields(Checker *c, AstNode *node, Array decls, isize field_index = 0; for_array(decl_index, decls) { AstNode *decl = decls[decl_index]; - if (decl->kind != AstNode_Field) { + if (decl->kind != AstNode_ValueDecl) { continue; } - ast_node(f, Field, decl); + ast_node(vd, ValueDecl, decl); - Type *type = check_type(c, f->type); - bool is_using = (f->flags&FieldFlag_using) != 0; + Type *type = nullptr; + if (vd->type != nullptr) { + type = check_type(c, vd->type); + } else { + error(vd->names[0], "Expected a type for this field"); + type = t_invalid; + } + bool is_using = (vd->flags&VarDeclFlag_using) != 0; - if (is_using && f->names.count > 1) { - error(f->names[0], "Cannot apply `using` to more than one of the same type"); + if (is_using && vd->names.count > 1) { + error(vd->names[0], "Cannot apply `using` to more than one of the same type"); is_using = false; } - for_array(name_index, f->names) { - AstNode *name = f->names[name_index]; + if (!vd->is_mutable) { + error(vd->names[0], "Immutable values in a %.*s are not yet supported", LIT(context)); + continue; + } + + if (vd->values.count) { + error(vd->values[0], "Default values are not allowed within a %.*s", LIT(context)); + } + + for_array(name_index, vd->names) { + AstNode *name = vd->names[name_index]; if (!ast_node_expect(name, AstNode_Ident)) { continue; } @@ -759,16 +774,16 @@ isize check_fields(Checker *c, AstNode *node, Array decls, if (is_using) { Type *t = base_type(type_deref(type)); if (!is_type_struct(t) && !is_type_raw_union(t) && !is_type_bit_field(t) && - f->names.count >= 1 && - f->names[0]->kind == AstNode_Ident) { - Token name_token = f->names[0]->Ident.token; + vd->names.count >= 1 && + vd->names[0]->kind == AstNode_Ident) { + Token name_token = vd->names[0]->Ident.token; if (is_type_indexable(t)) { bool ok = true; for_array(emi, entity_map.entries) { Entity *e = entity_map.entries[emi].value; if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) { if (is_type_indexable(e->type)) { - if (e->identifier != f->names[0]) { + if (e->identifier != vd->names[0]) { ok = false; using_index_expr = e; break; @@ -852,7 +867,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) { for_array(field_index, st->fields) { AstNode *field = st->fields[field_index]; switch (field->kind) { - case_ast_node(f, Field, field); + case_ast_node(f, ValueDecl, field); field_count += f->names.count; case_end; } @@ -947,9 +962,10 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n isize field_count = 0; for_array(i, ut->fields) { AstNode *field = ut->fields[i]; - if (field->kind == AstNode_Field) { - ast_node(f, Field, field); + switch (field->kind) { + case_ast_node(f, ValueDecl, field); field_count += f->names.count; + case_end; } } @@ -1005,8 +1021,12 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n isize list_count = 0; for_array(j, list) { - ast_node(f, Field, list[j]); - list_count += f->names.count; + if (list[j]->kind == AstNode_Field) { + list_count += list[j]->Field.names.count; + } else { + ast_node(f, ValueDecl, list[j]); + list_count += f->names.count; + } } @@ -1067,10 +1087,10 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) { ast_node(ut, RawUnionType, node); isize field_count = 0; - for_array(field_index, ut->fields) { - AstNode *field = ut->fields[field_index]; + for_array(i, ut->fields) { + AstNode *field = ut->fields[i]; switch (field->kind) { - case_ast_node(f, Field, field); + case_ast_node(f, ValueDecl, field); field_count += f->names.count; case_end; } diff --git a/src/parser.cpp b/src/parser.cpp index a40f8266e..2f3bdcab2 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1880,13 +1880,11 @@ void expect_semicolon(AstFile *f, AstNode *s) { return; } } else { - // switch (s->kind) { - // case AstNode_GiveExpr: - // if (f->curr_token.kind == Token_CloseBrace) { - // return; - // } - // break; - // } + if (s->kind == AstNode_ValueDecl) { + if (f->curr_token.kind == Token_CloseBrace) { + return; + } + } } String node_string = ast_node_strings[s->kind]; if (s->kind == AstNode_GenDecl) { @@ -3007,7 +3005,6 @@ AstNode *parse_value_decl(AstFile *f, Array names, CommentGroup docs) } } - if (is_mutable) { if (type == nullptr && values.count == 0) { syntax_error(f->curr_token, "Missing variable type or initialization"); @@ -3029,7 +3026,12 @@ AstNode *parse_value_decl(AstFile *f, Array names, CommentGroup docs) if (!is_mutable && values.count > 0) { end = values[values.count-1]; } - expect_semicolon(f, end); + if (f->curr_token.kind == Token_CloseBrace && + f->curr_token.pos.line == f->prev_token.pos.line) { + + } else { + expect_semicolon(f, end); + } } return ast_value_decl(f, names, type, values, is_mutable, docs, f->line_comment); @@ -3377,98 +3379,36 @@ bool parse_expect_struct_separator(AstFile *f, AstNode *param) { } -AstNode *parse_struct_field_list(AstFile *f, isize *name_count_) { +AstNode *parse_record_field_list(AstFile *f, isize *name_count_) { CommentGroup docs = f->lead_comment; Token start_token = f->curr_token; - Array params = make_ast_node_array(f); - Array list = {}; array_init(&list, heap_allocator()); - defer (array_free(&list)); + Array decls = make_ast_node_array(f); isize total_name_count = 0; while (f->curr_token.kind != Token_CloseBrace && - f->curr_token.kind != Token_Colon && f->curr_token.kind != Token_EOF) { - u32 flags = parse_field_prefixes(f); - AstNode *param = parse_var_type(f, false, false); - AstNodeAndFlags naf = {param, flags}; - array_add(&list, naf); - if (f->curr_token.kind != Token_Comma) { - break; - } - next_token(f); - } - - if (f->curr_token.kind == Token_Colon) { - Array names = convert_to_ident_list(f, list, true); // Copy for semantic reasons - if (names.count == 0) { - syntax_error(f->curr_token, "Empty field declaration"); - } - u32 set_flags = 0; - if (list.count > 0) { - set_flags = list[0].flags; - } - set_flags = check_field_prefixes(f, names.count, FieldFlag_using, set_flags); - total_name_count += names.count; - - AstNode *type = nullptr; - - expect_token_after(f, Token_Colon, "field list"); - type = parse_var_type(f, false, false); - - parse_expect_struct_separator(f, type); - AstNode *param = ast_field(f, names, type, nullptr, set_flags, docs, f->line_comment); - array_add(¶ms, param); - - - while (f->curr_token.kind != Token_CloseBrace && - f->curr_token.kind != Token_EOF) { - CommentGroup docs = f->lead_comment; - - u32 set_flags = parse_field_prefixes(f); - Array names = parse_ident_list(f); - if (names.count == 0) { - syntax_error(f->curr_token, "Empty field declaration"); - break; - } - set_flags = check_field_prefixes(f, names.count, FieldFlag_using, set_flags); - total_name_count += names.count; - - AstNode *type = nullptr; - - expect_token_after(f, Token_Colon, "field list"); - type = parse_var_type(f, false, false); - - bool ok = parse_expect_struct_separator(f, param); - AstNode *param = ast_field(f, names, type, nullptr, set_flags, docs, f->line_comment); - array_add(¶ms, param); - - if (!ok) { - break; + AstNode *decl = parse_stmt(f); + if (decl->kind != AstNode_ValueDecl) { + error(decl, "Expected a field list, got %.*s", LIT(ast_node_strings[decl->kind])); + } else { + ast_node(vd, ValueDecl, decl); + if (vd->is_mutable) { + if (vd->flags&VarDeclFlag_thread_local) { + vd->flags &= ~VarDeclFlag_thread_local; + error(decl, "Field values cannot be #thread_local"); + } + array_add(&decls, decl); + total_name_count += vd->names.count; + } else { + error(decl, "Only variable declarations are allowed at the moment"); } } - - if (name_count_) *name_count_ = total_name_count; - return ast_field_list(f, start_token, params); - } - - for_array(i, list) { - Array names = {}; - AstNode *type = list[i].node; - Token token = blank_token; - - array_init_count(&names, heap_allocator(), 1); - token.pos = ast_node_token(type).pos; - names[0] = ast_ident(f, token); - u32 flags = check_field_prefixes(f, list.count, FieldFlag_using, list[i].flags); - - AstNode *param = ast_field(f, names, list[i].node, nullptr, flags, docs, f->line_comment); - array_add(¶ms, param); } if (name_count_) *name_count_ = total_name_count; - return ast_field_list(f, start_token, params); + return ast_field_list(f, start_token, decls); } AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters) { @@ -3597,11 +3537,6 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok return ast_field_list(f, start_token, params); } - -AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) { - return parse_field_list(f, field_count_, flags, Token_CloseBrace, false); -} - AstNode *parse_type_or_ident(AstFile *f) { switch (f->curr_token.kind) { case Token_Dollar: { @@ -3748,7 +3683,7 @@ AstNode *parse_type_or_ident(AstFile *f) { Token open = expect_token_after(f, Token_OpenBrace, "struct"); isize name_count = 0; - AstNode *fields = parse_struct_field_list(f, &name_count); + AstNode *fields = parse_record_field_list(f, &name_count); Token close = expect_token(f, Token_CloseBrace); Array decls = {}; @@ -3767,50 +3702,57 @@ AstNode *parse_type_or_ident(AstFile *f) { Array 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) { CommentGroup docs = f->lead_comment; - u32 decl_flags = parse_field_prefixes(f); - if (decl_flags != 0) { - Array names = parse_ident_list(f); - if (names.count == 0) { - syntax_error(f->curr_token, "Empty field declaration"); - } - u32 set_flags = check_field_prefixes(f, names.count, FieldFlag_using, decl_flags); - total_decl_name_count += names.count; - expect_token_after(f, Token_Colon, "field list"); - AstNode *type = parse_var_type(f, false, false); - array_add(&decls, ast_field(f, names, type, nullptr, set_flags, docs, f->line_comment)); - } else { - Array names = parse_ident_list(f); - if (names.count == 0) { - break; - } - if (names.count > 1 || f->curr_token.kind == Token_Colon) { - u32 set_flags = check_field_prefixes(f, names.count, FieldFlag_using, decl_flags); - total_decl_name_count += names.count; - expect_token_after(f, Token_Colon, "field list"); - AstNode *type = parse_var_type(f, false, false); - array_add(&decls, ast_field(f, names, type, nullptr, set_flags, docs, f->line_comment)); - } else { - AstNode *name = names[0]; - Token open = expect_token(f, Token_OpenBrace); - isize decl_count = 0; - AstNode *list = parse_struct_field_list(f, &decl_count); - // AstNode *list = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("union")); - Token close = expect_token(f, Token_CloseBrace); - - array_add(&variants, ast_union_field(f, name, list)); - } - } - if (!parse_expect_struct_separator(f, nullptr)) { + u32 flags = parse_field_prefixes(f); + auto names = parse_ident_list(f); + if (names.count == 0) { break; } + u32 set_flags = check_field_prefixes(f, names.count, FieldFlag_using, flags); + if (names.count == 1 && f->curr_token.kind == Token_OpenBrace) { + if (set_flags != 0) { + error(names[0], "Variants cannot have field prefixes"); + set_flags = 0; + } + AstNode *name = names[0]; + Token open = expect_token(f, Token_OpenBrace); + isize decl_count = 0; + AstNode *list = parse_record_field_list(f, &decl_count); + Token close = expect_token(f, Token_CloseBrace); + + array_add(&variants, ast_union_field(f, name, list)); + expect_semicolon(f, nullptr); + } else { + AstNode *decl = parse_value_decl(f, names, docs); + if (decl->kind != AstNode_ValueDecl) { + error(decl, "Expected a field list, got %.*s", LIT(ast_node_strings[decl->kind])); + } else { + ast_node(vd, ValueDecl, decl); + if (vd->is_mutable) { + if (set_flags&FieldFlag_using) { + vd->flags |= VarDeclFlag_using; + } + if (vd->flags&VarDeclFlag_thread_local) { + vd->flags &= ~VarDeclFlag_thread_local; + error(decl, "Field values cannot be #thread_local"); + } + array_add(&decls, decl); + total_decl_name_count += vd->names.count; + } else { + error(decl, "Only variable declarations are allowed at the moment"); + } + } + } } Token close = expect_token(f, Token_CloseBrace); - return ast_union_type(f, token, decls, total_decl_name_count, variants); } break; @@ -3819,7 +3761,7 @@ AstNode *parse_type_or_ident(AstFile *f) { Token open = expect_token_after(f, Token_OpenBrace, "raw_union"); isize decl_count = 0; - AstNode *fields = parse_struct_field_list(f, &decl_count); + AstNode *fields = parse_record_field_list(f, &decl_count); Token close = expect_token(f, Token_CloseBrace); Array decls = {}; @@ -4391,11 +4333,7 @@ AstNode *parse_stmt(AstFile *f) { syntax_error(token, "`using` may only be applied to variable declarations"); return decl; } - if (f->curr_proc == nullptr) { - syntax_error(token, "`using` is not allowed at the file scope"); - } else { - decl->ValueDecl.flags |= VarDeclFlag_using; - } + decl->ValueDecl.flags |= VarDeclFlag_using; return decl; }