diff --git a/doc/langref.md b/doc/langref.md index 70ac701f90..035b32f817 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -15,7 +15,7 @@ GlobalVarDecl = VariableDeclaration ";" VariableDeclaration = ("var" | "const") "Symbol" option(":" TypeExpr) "=" Expression -ContainerDecl = ("struct" | "enum") "Symbol" "{" many(StructMember) "}" +ContainerDecl = ("struct" | "enum" | "union") "Symbol" "{" many(StructMember) "}" StructMember = many(Directive) option(VisibleMod) (StructField | FnDef) diff --git a/doc/vim/syntax/zig.vim b/doc/vim/syntax/zig.vim index 18319002b8..f8485c3e6f 100644 --- a/doc/vim/syntax/zig.vim +++ b/doc/vim/syntax/zig.vim @@ -8,7 +8,7 @@ if exists("b:current_syntax") endif syn keyword zigStorage const var extern volatile export pub noalias inline -syn keyword zigStructure struct enum +syn keyword zigStructure struct enum union syn keyword zigStatement goto break return continue asm defer syn keyword zigConditional if else switch syn keyword zigRepeat while for diff --git a/src/all_types.hpp b/src/all_types.hpp index af6a40bde9..bbb69779ea 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -135,7 +135,7 @@ struct TopLevelDecl { struct TypeEnumField { Buf *name; TypeTableEntry *type_entry; - uint32_t value; + uint32_t value; // TODO is this used? }; enum NodeType { @@ -590,6 +590,7 @@ struct AstNodeAsmExpr { enum ContainerKind { ContainerKindStruct, ContainerKindEnum, + ContainerKindUnion, }; struct AstNodeStructDecl { @@ -905,6 +906,22 @@ struct TypeTableEntryEnum { bool complete; }; +struct TypeTableEntryUnion { + AstNode *decl_node; + uint32_t src_field_count; + uint32_t gen_field_count; + TypeStructField *fields; + uint64_t size_bytes; + bool is_invalid; // true if any fields are invalid + BlockContext *block_context; + + // set this flag temporarily to detect infinite loops + bool embedded_in_current; + bool reported_infinite_err; + // whether we've finished resolving it + bool complete; +}; + struct FnGenParamInfo { int src_index; int gen_index; @@ -949,6 +966,7 @@ enum TypeTableEntryId { TypeTableEntryIdErrorUnion, TypeTableEntryIdPureError, TypeTableEntryIdEnum, + TypeTableEntryIdUnion, TypeTableEntryIdFn, TypeTableEntryIdTypeDecl, TypeTableEntryIdNamespace, @@ -974,6 +992,7 @@ struct TypeTableEntry { TypeTableEntryMaybe maybe; TypeTableEntryError error; TypeTableEntryEnum enumeration; + TypeTableEntryUnion unionation; TypeTableEntryFn fn; TypeTableEntryTypeDecl type_decl; TypeTableEntryGenericFn generic_fn; diff --git a/src/analyze.cpp b/src/analyze.cpp index ae8a4213db..eb3fb4cd6d 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -141,6 +141,8 @@ static BlockContext **get_container_block_context_ptr(TypeTableEntry *type_entry return &type_entry->data.structure.block_context; } else if (type_entry->id == TypeTableEntryIdEnum) { return &type_entry->data.enumeration.block_context; + } else if (type_entry->id == TypeTableEntryIdUnion) { + return &type_entry->data.unionation.block_context; } zig_unreachable(); } @@ -178,6 +180,8 @@ static bool type_is_complete(TypeTableEntry *type_entry) { return type_entry->data.structure.complete; case TypeTableEntryIdEnum: return type_entry->data.enumeration.complete; + case TypeTableEntryIdUnion: + return type_entry->data.unionation.complete; case TypeTableEntryIdMetaType: case TypeTableEntryIdVoid: case TypeTableEntryIdBool: @@ -732,6 +736,8 @@ static TypeTableEntryId container_to_type(ContainerKind kind) { return TypeTableEntryIdStruct; case ContainerKindEnum: return TypeTableEntryIdEnum; + case ContainerKindUnion: + return TypeTableEntryIdUnion; } zig_unreachable(); } @@ -749,6 +755,9 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import, case ContainerKindEnum: entry->data.enumeration.decl_node = decl_node; break; + case ContainerKindUnion: + entry->data.unionation.decl_node = decl_node; + break; } unsigned line = decl_node ? decl_node->line : 0; @@ -874,6 +883,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor case TypeTableEntryIdErrorUnion: case TypeTableEntryIdPureError: case TypeTableEntryIdEnum: + case TypeTableEntryIdUnion: case TypeTableEntryIdFn: case TypeTableEntryIdTypeDecl: break; @@ -1397,6 +1407,10 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE struct_type->zero_bits = (debug_size_in_bits == 0); } +static void resolve_union_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *enum_type) { + zig_panic("TODO"); +} + static void get_fully_qualified_decl_name(Buf *buf, AstNode *decl_node, uint8_t sep) { TopLevelDecl *tld = get_as_top_level_decl(decl_node); AstNode *parent_decl = tld->parent_decl; @@ -1541,6 +1555,9 @@ static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) case ContainerKindEnum: resolve_enum_type(g, import, type_entry); break; + case ContainerKindUnion: + resolve_union_type(g, import, type_entry); + break; } break; @@ -1672,6 +1689,7 @@ static bool type_has_codegen_value(TypeTableEntry *type_entry) { case TypeTableEntryIdErrorUnion: case TypeTableEntryIdPureError: case TypeTableEntryIdEnum: + case TypeTableEntryIdUnion: case TypeTableEntryIdFn: return true; @@ -4450,6 +4468,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry case TypeTableEntryIdErrorUnion: case TypeTableEntryIdPureError: case TypeTableEntryIdEnum: + case TypeTableEntryIdUnion: case TypeTableEntryIdFn: case TypeTableEntryIdTypeDecl: return resolve_expr_const_val_as_type(g, node, type_entry); @@ -6179,6 +6198,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { return false; case TypeTableEntryIdArray: case TypeTableEntryIdStruct: + case TypeTableEntryIdUnion: return true; case TypeTableEntryIdErrorUnion: return type_has_bits(type_entry->data.error.child_type); @@ -6280,6 +6300,9 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val) case TypeTableEntryIdStruct: // TODO better hashing algorithm return 1532530855; + case TypeTableEntryIdUnion: + // TODO better hashing algorithm + return 2709806591; case TypeTableEntryIdMaybe: if (const_val->data.x_maybe) { TypeTableEntry *child_type = type->data.maybe.child_type; @@ -6374,6 +6397,8 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry) return type_of_first_thing_in_memory(type_entry->data.array.child_type); case TypeTableEntryIdStruct: return type_of_first_thing_in_memory(first_struct_field_type(type_entry)); + case TypeTableEntryIdUnion: + zig_panic("TODO"); case TypeTableEntryIdMaybe: return type_of_first_thing_in_memory(type_entry->data.maybe.child_type); case TypeTableEntryIdErrorUnion: diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 5e7a5c3fce..3686a9af22 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -84,6 +84,7 @@ static const char *container_string(ContainerKind kind) { switch (kind) { case ContainerKindEnum: return "enum"; case ContainerKindStruct: return "struct"; + case ContainerKindUnion: return "union"; } zig_unreachable(); } diff --git a/src/codegen.cpp b/src/codegen.cpp index 394ab398bb..26ccb77d7f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2972,6 +2972,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count); } + case TypeTableEntryIdUnion: + { + zig_panic("TODO"); + } case TypeTableEntryIdArray: { TypeTableEntry *child_type = type_entry->data.array.child_type; diff --git a/src/eval.cpp b/src/eval.cpp index 620dd8350a..3f62d179ee 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -41,6 +41,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *ty zig_panic("TODO"); case TypeTableEntryIdStruct: zig_panic("TODO"); + case TypeTableEntryIdUnion: + zig_panic("TODO"); case TypeTableEntryIdUndefLit: zig_panic("TODO"); case TypeTableEntryIdMaybe: diff --git a/src/parser.cpp b/src/parser.cpp index d73bacead2..311bbe093a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2504,11 +2504,11 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index, } /* -ContainerDecl : ("struct" | "enum") "Symbol" "{" many(StructMember) "}" +ContainerDecl = ("struct" | "enum" | "union") "Symbol" "{" many(StructMember) "}" StructMember: many(Directive) option(VisibleMod) (StructField | FnDef) StructField : "Symbol" option(":" Expression) ",") */ -static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index, +static AstNode *ast_parse_container_decl(ParseContext *pc, int *token_index, ZigList *directives, VisibMod visib_mod) { Token *first_token = &pc->tokens->at(*token_index); @@ -2519,6 +2519,8 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index, kind = ContainerKindStruct; } else if (first_token->id == TokenIdKeywordEnum) { kind = ContainerKindEnum; + } else if (first_token->id == TokenIdKeywordUnion) { + kind = ContainerKindUnion; } else { return nullptr; } @@ -2689,7 +2691,7 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis continue; } - AstNode *struct_node = ast_parse_struct_decl(pc, token_index, directives, visib_mod); + AstNode *struct_node = ast_parse_container_decl(pc, token_index, directives, visib_mod); if (struct_node) { top_level_decls->append(struct_node); continue; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 246bf6ba68..62a43fc40c 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -108,7 +108,7 @@ const char * zig_keywords[] = { "pub", "export", "use", "if", "else", "goto", "asm", "volatile", "struct", "enum", "while", "for", "continue", "break", "null", "noalias", "switch", "undefined", "error", "type", "inline", - "defer", + "defer", "union", }; bool is_zig_keyword(Buf *buf) { @@ -269,6 +269,8 @@ static void end_token(Tokenize *t) { t->cur_tok->id = TokenIdKeywordStruct; } else if (mem_eql_str(token_mem, token_len, "enum")) { t->cur_tok->id = TokenIdKeywordEnum; + } else if (mem_eql_str(token_mem, token_len, "union")) { + t->cur_tok->id = TokenIdKeywordUnion; } else if (mem_eql_str(token_mem, token_len, "for")) { t->cur_tok->id = TokenIdKeywordFor; } else if (mem_eql_str(token_mem, token_len, "while")) { @@ -1195,6 +1197,7 @@ const char * token_name(TokenId id) { case TokenIdKeywordAsm: return "asm"; case TokenIdKeywordStruct: return "struct"; case TokenIdKeywordEnum: return "enum"; + case TokenIdKeywordUnion: return "union"; case TokenIdKeywordWhile: return "while"; case TokenIdKeywordFor: return "for"; case TokenIdKeywordContinue: return "continue"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 22767adbba..eac7b0a69b 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -30,6 +30,7 @@ enum TokenId { TokenIdKeywordVolatile, TokenIdKeywordStruct, TokenIdKeywordEnum, + TokenIdKeywordUnion, TokenIdKeywordWhile, TokenIdKeywordFor, TokenIdKeywordContinue,