diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index 3f8c45aad7..8cdac92326 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -1186,6 +1186,7 @@ pub const Builder = struct { ast.Node.Id.AsyncAttribute => return error.Unimplemented, ast.Node.Id.ParamDecl => return error.Unimplemented, ast.Node.Id.FieldInitializer => return error.Unimplemented, + ast.Node.Id.EnumLiteral => return error.Unimplemented, } } diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 4c9fb58a18..5a8dc47ef9 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -32,6 +32,7 @@ pub const Type = struct { Id.Array => @fieldParentPtr(Array, "base", base).destroy(comp), Id.ComptimeFloat => @fieldParentPtr(ComptimeFloat, "base", base).destroy(comp), Id.ComptimeInt => @fieldParentPtr(ComptimeInt, "base", base).destroy(comp), + Id.EnumLiteral => @fieldParentPtr(EnumLiteral, "base", base).destroy(comp), Id.Undefined => @fieldParentPtr(Undefined, "base", base).destroy(comp), Id.Null => @fieldParentPtr(Null, "base", base).destroy(comp), Id.Optional => @fieldParentPtr(Optional, "base", base).destroy(comp), @@ -65,6 +66,7 @@ pub const Type = struct { Id.Array => return @fieldParentPtr(Array, "base", base).getLlvmType(allocator, llvm_context), Id.ComptimeFloat => unreachable, Id.ComptimeInt => unreachable, + Id.EnumLiteral => unreachable, Id.Undefined => unreachable, Id.Null => unreachable, Id.Optional => return @fieldParentPtr(Optional, "base", base).getLlvmType(allocator, llvm_context), @@ -85,6 +87,7 @@ pub const Type = struct { Id.Type, Id.ComptimeFloat, Id.ComptimeInt, + Id.EnumLiteral, Id.Undefined, Id.Null, Id.BoundFn, @@ -118,6 +121,7 @@ pub const Type = struct { Id.Type, Id.ComptimeFloat, Id.ComptimeInt, + Id.EnumLiteral, Id.Undefined, Id.Null, Id.BoundFn, @@ -940,6 +944,20 @@ pub const Type = struct { } }; + pub const EnumLiteral = struct { + base: Type, + + /// Adds 1 reference to the resulting type + pub fn get(comp: *Compilation) *EnumLiteral { + comp.comptime_int_type.base.base.ref(); + return comp.comptime_int_type; + } + + pub fn destroy(self: *EnumLiteral, comp: *Compilation) void { + comp.gpa().destroy(self); + } + }; + pub const Undefined = struct { base: Type, diff --git a/src/all_types.hpp b/src/all_types.hpp index b49b42d495..92adac094d 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -317,6 +317,7 @@ struct ConstExprValue { ConstArrayValue x_array; ConstPtrValue x_ptr; ConstArgTuple x_arg_tuple; + Buf *x_enum_literal; // populated if special == ConstValSpecialRuntime RuntimeHintErrorUnion rh_error_union; @@ -468,6 +469,7 @@ enum NodeType { NodeTypeAwaitExpr, NodeTypeSuspend, NodeTypePromiseType, + NodeTypeEnumLiteral, }; enum CallingConvention { @@ -929,6 +931,11 @@ struct AstNodePromiseType { AstNode *payload_type; // can be NULL }; +struct AstNodeEnumLiteral { + Token *period; + Token *identifier; +}; + struct AstNode { enum NodeType type; size_t line; @@ -989,6 +996,7 @@ struct AstNode { AstNodeAwaitExpr await_expr; AstNodeSuspend suspend; AstNodePromiseType promise_type; + AstNodeEnumLiteral enum_literal; } data; }; @@ -1252,6 +1260,7 @@ enum ZigTypeId { ZigTypeIdOpaque, ZigTypeIdPromise, ZigTypeIdVector, + ZigTypeIdEnumLiteral, }; enum OnePossibleValue { @@ -1741,6 +1750,7 @@ struct CodeGen { ZigType *entry_global_error_set; ZigType *entry_arg_tuple; ZigType *entry_promise; + ZigType *entry_enum_literal; } builtin_types; ZigType *align_amt_type; ZigType *stack_trace_type; diff --git a/src/analyze.cpp b/src/analyze.cpp index c83327bbdf..f54da2a16b 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -242,6 +242,7 @@ AstNode *type_decl_node(ZigType *type_entry) { case ZigTypeIdArray: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdOptional: @@ -303,6 +304,7 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { case ZigTypeIdArray: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdOptional: @@ -1463,6 +1465,7 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType case ZigTypeIdUnreachable: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdErrorUnion: @@ -1550,6 +1553,7 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) { case ZigTypeIdMetaType: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdErrorUnion: @@ -1712,6 +1716,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc return g->builtin_types.entry_invalid; case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdBoundFn: case ZigTypeIdMetaType: case ZigTypeIdVoid: @@ -1806,6 +1811,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdBoundFn: case ZigTypeIdMetaType: case ZigTypeIdUnreachable: @@ -3621,6 +3627,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeAwaitExpr: case NodeTypeSuspend: case NodeTypePromiseType: + case NodeTypeEnumLiteral: zig_unreachable(); } } @@ -3658,6 +3665,7 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry return g->builtin_types.entry_invalid; case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdMetaType: case ZigTypeIdVoid: case ZigTypeIdBool: @@ -3807,7 +3815,8 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { implicit_type = g->builtin_types.entry_invalid; } else if ((!is_const || linkage == VarLinkageExternal) && (implicit_type->id == ZigTypeIdComptimeFloat || - implicit_type->id == ZigTypeIdComptimeInt)) + implicit_type->id == ZigTypeIdComptimeInt || + implicit_type->id == ZigTypeIdEnumLiteral)) { add_node_error(g, source_node, buf_sprintf("unable to infer variable type")); implicit_type = g->builtin_types.entry_invalid; @@ -4051,6 +4060,7 @@ static bool is_container(ZigType *type_entry) { case ZigTypeIdArray: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdOptional: @@ -4109,6 +4119,7 @@ void resolve_container_type(CodeGen *g, ZigType *type_entry) { case ZigTypeIdArray: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdOptional: @@ -4647,6 +4658,7 @@ bool handle_is_ptr(ZigType *type_entry) { case ZigTypeIdMetaType: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdBoundFn: @@ -4827,6 +4839,8 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { } return result; } + case ZigTypeIdEnumLiteral: + return buf_hash(const_val->data.x_enum_literal) * 2691276464; case ZigTypeIdEnum: { uint32_t result = 31643936; @@ -4974,6 +4988,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { case ZigTypeIdFloat: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdBoundFn: @@ -5043,6 +5058,7 @@ static bool return_type_is_cacheable(ZigType *return_type) { case ZigTypeIdFloat: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdBoundFn: @@ -5173,6 +5189,7 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { case ZigTypeIdOpaque: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdMetaType: case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: @@ -5236,6 +5253,7 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { zig_unreachable(); case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdMetaType: @@ -5794,6 +5812,8 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { case ZigTypeIdInt: case ZigTypeIdComptimeInt: return bigint_cmp(&a->data.x_bigint, &b->data.x_bigint) == CmpEQ; + case ZigTypeIdEnumLiteral: + return buf_eql_buf(a->data.x_enum_literal, b->data.x_enum_literal); case ZigTypeIdPointer: case ZigTypeIdFn: return const_values_equal_ptr(a, b); @@ -6044,6 +6064,9 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { case ZigTypeIdInt: bigint_append_buf(buf, &const_val->data.x_bigint, 10); return; + case ZigTypeIdEnumLiteral: + buf_append_buf(buf, const_val->data.x_enum_literal); + return; case ZigTypeIdMetaType: buf_appendf(buf, "%s", buf_ptr(&const_val->data.x_type->name)); return; @@ -6213,6 +6236,7 @@ uint32_t type_id_hash(TypeId x) { case ZigTypeIdStruct: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdOptional: @@ -6260,6 +6284,7 @@ bool type_id_eql(TypeId a, TypeId b) { case ZigTypeIdStruct: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdOptional: @@ -6439,6 +6464,7 @@ static const ZigTypeId all_type_ids[] = { ZigTypeIdOpaque, ZigTypeIdPromise, ZigTypeIdVector, + ZigTypeIdEnumLiteral, }; ZigTypeId type_id_at_index(size_t index) { @@ -6504,6 +6530,8 @@ size_t type_id_index(ZigType *entry) { return 22; case ZigTypeIdVector: return 23; + case ZigTypeIdEnumLiteral: + return 24; } zig_unreachable(); } @@ -6534,6 +6562,8 @@ const char *type_id_name(ZigTypeId id) { return "ComptimeFloat"; case ZigTypeIdComptimeInt: return "ComptimeInt"; + case ZigTypeIdEnumLiteral: + return "EnumLiteral"; case ZigTypeIdUndefined: return "Undefined"; case ZigTypeIdNull: diff --git a/src/ast_render.cpp b/src/ast_render.cpp index eb4b4e56c4..16f2aafa78 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -259,6 +259,8 @@ static const char *node_type_str(NodeType node_type) { return "PromiseType"; case NodeTypePointerType: return "PointerType"; + case NodeTypeEnumLiteral: + return "EnumLiteral"; } zig_unreachable(); } @@ -1154,6 +1156,11 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { } break; } + case NodeTypeEnumLiteral: + { + fprintf(ar->f, ".%s", buf_ptr(&node->data.enum_literal.identifier->data.str_lit.str)); + break; + } case NodeTypeParamDecl: case NodeTypeTestDecl: case NodeTypeStructField: diff --git a/src/codegen.cpp b/src/codegen.cpp index cfd26af461..c9ceb5ee7d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5818,6 +5818,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con case ZigTypeIdUnreachable: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdErrorUnion: @@ -6419,6 +6420,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c case ZigTypeIdUnreachable: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdBoundFn: @@ -7005,6 +7007,12 @@ static void define_builtin_types(CodeGen *g) { g->builtin_types.entry_num_lit_int = entry; g->primitive_type_table.put(&entry->name, entry); } + { + ZigType *entry = new_type_table_entry(ZigTypeIdEnumLiteral); + buf_init_from_str(&entry->name, "(enum literal)"); + entry->zero_bits = true; + g->builtin_types.entry_enum_literal = entry; + } { ZigType *entry = new_type_table_entry(ZigTypeIdUndefined); buf_init_from_str(&entry->name, "(undefined)"); @@ -7175,7 +7183,6 @@ static void define_builtin_types(CodeGen *g) { ZigType *entry = get_promise_type(g, nullptr); g->primitive_type_table.put(&entry->name, entry); } - } @@ -7527,6 +7534,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " Opaque: void,\n" " Promise: Promise,\n" " Vector: Vector,\n" + " EnumLiteral: void,\n" "\n\n" " pub const Int = struct {\n" " is_signed: bool,\n" @@ -8626,6 +8634,7 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e case ZigTypeIdMetaType: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdBoundFn: @@ -8812,6 +8821,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu case ZigTypeIdBoundFn: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdArgTuple: @@ -8965,6 +8975,7 @@ static void gen_h_file(CodeGen *g) { case ZigTypeIdPointer: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdArray: case ZigTypeIdUndefined: case ZigTypeIdNull: diff --git a/src/ir.cpp b/src/ir.cpp index 62ac5ba970..21c15a7f70 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -257,6 +257,7 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) { case ZigTypeIdBool: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdPointer: case ZigTypeIdUndefined: case ZigTypeIdNull: @@ -1144,6 +1145,14 @@ static IrInstruction *ir_build_const_bool(IrBuilder *irb, Scope *scope, AstNode return &const_instruction->base; } +static IrInstruction *ir_build_const_enum_literal(IrBuilder *irb, Scope *scope, AstNode *source_node, Buf *name) { + IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node); + const_instruction->base.value.type = irb->codegen->builtin_types.entry_enum_literal; + const_instruction->base.value.special = ConstValSpecialStatic; + const_instruction->base.value.data.x_enum_literal = name; + return &const_instruction->base; +} + static IrInstruction *ir_build_const_bound_fn(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigFn *fn_entry, IrInstruction *first_arg) { @@ -5794,6 +5803,12 @@ static IrInstruction *ir_gen_bool_literal(IrBuilder *irb, Scope *scope, AstNode return ir_build_const_bool(irb, scope, node, node->data.bool_literal.value); } +static IrInstruction *ir_gen_enum_literal(IrBuilder *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeEnumLiteral); + Buf *name = &node->data.enum_literal.identifier->data.str_lit.str; + return ir_build_const_enum_literal(irb, scope, node, name); +} + static IrInstruction *ir_gen_string_literal(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeStringLiteral); @@ -7564,6 +7579,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval); case NodeTypeSuspend: return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval); + case NodeTypeEnumLiteral: + return ir_lval_wrap(irb, scope, ir_gen_enum_literal(irb, scope, node), lval); } zig_unreachable(); } @@ -12264,6 +12281,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * case ZigTypeIdArgTuple: case ZigTypeIdPromise: case ZigTypeIdEnum: + case ZigTypeIdEnumLiteral: operator_allowed = is_equality_cmp; break; @@ -13596,6 +13614,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio case ZigTypeIdUnreachable: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdOptional: @@ -13629,6 +13648,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio case ZigTypeIdArgTuple: case ZigTypeIdOpaque: case ZigTypeIdPromise: + case ZigTypeIdEnumLiteral: ir_add_error(ira, target, buf_sprintf("invalid export target type '%s'", buf_ptr(&target->value.type->name))); break; @@ -14805,6 +14825,7 @@ static IrInstruction *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_ case ZigTypeIdStruct: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdOptional: @@ -16448,6 +16469,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, case ZigTypeIdStruct: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdOptional: case ZigTypeIdErrorUnion: case ZigTypeIdErrorSet: @@ -16560,6 +16582,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, case ZigTypeIdStruct: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdOptional: case ZigTypeIdErrorUnion: case ZigTypeIdErrorSet: @@ -16613,6 +16636,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, case ZigTypeIdNull: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdBoundFn: case ZigTypeIdMetaType: case ZigTypeIdArgTuple: @@ -17019,6 +17043,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, case ZigTypeIdFloat: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdPointer: case ZigTypeIdPromise: case ZigTypeIdFn: @@ -18237,6 +18262,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr case ZigTypeIdUnreachable: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdArgTuple: @@ -20443,6 +20469,7 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct case ZigTypeIdUnreachable: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdBoundFn: @@ -21293,6 +21320,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue case ZigTypeIdUnreachable: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdPromise: @@ -21452,6 +21480,7 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou case ZigTypeIdUnreachable: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdPromise: @@ -21609,6 +21638,7 @@ static bool type_can_bit_cast(ZigType *t) { case ZigTypeIdUnreachable: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdPointer: diff --git a/src/parser.cpp b/src/parser.cpp index 104a110f45..a2c17f401f 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -81,6 +81,7 @@ static AstNode *ast_parse_for_type_expr(ParseContext *pc); static AstNode *ast_parse_while_type_expr(ParseContext *pc); static AstNode *ast_parse_switch_expr(ParseContext *pc); static AstNode *ast_parse_asm_expr(ParseContext *pc); +static AstNode *ast_parse_enum_lit(ParseContext *pc); static AstNode *ast_parse_asm_output(ParseContext *pc); static AsmOutput *ast_parse_asm_output_item(ParseContext *pc); static AstNode *ast_parse_asm_input(ParseContext *pc); @@ -1161,6 +1162,10 @@ static AstNode *ast_parse_prefix_expr(ParseContext *pc) { // / Block // / CurlySuffixExpr static AstNode *ast_parse_primary_expr(ParseContext *pc) { + AstNode *enum_lit = ast_parse_enum_lit(pc); + if (enum_lit != nullptr) + return enum_lit; + AstNode *asm_expr = ast_parse_asm_expr(pc); if (asm_expr != nullptr) return asm_expr; @@ -1831,6 +1836,18 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc) { return res; } +static AstNode *ast_parse_enum_lit(ParseContext *pc) { + Token *period = eat_token_if(pc, TokenIdDot); + if (period == nullptr) + return nullptr; + + Token *identifier = expect_token(pc, TokenIdSymbol); + AstNode *res = ast_create_node(pc, NodeTypeEnumLiteral, period); + res->data.enum_literal.period = period; + res->data.enum_literal.identifier = identifier; + return res; +} + // AsmOutput <- COLON AsmOutputList AsmInput? static AstNode *ast_parse_asm_output(ParseContext *pc) { if (eat_token_if(pc, TokenIdColon) == nullptr) @@ -3000,5 +3017,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont case NodeTypeSuspend: visit_field(&node->data.suspend.block, visit, context); break; + case NodeTypeEnumLiteral: + break; } } diff --git a/std/hash_map.zig b/std/hash_map.zig index d31fcdb597..f4c0b87167 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -490,6 +490,7 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type builtin.TypeId.ComptimeFloat, builtin.TypeId.ComptimeInt, builtin.TypeId.Type, + builtin.TypeId.EnumLiteral, => return 0, builtin.TypeId.Pointer => |info| switch (info.size) { @@ -531,6 +532,7 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool { builtin.TypeId.Float, builtin.TypeId.ComptimeFloat, builtin.TypeId.ComptimeInt, + builtin.TypeId.EnumLiteral, builtin.TypeId.Promise, builtin.TypeId.Enum, builtin.TypeId.BoundFn, diff --git a/std/testing.zig b/std/testing.zig index 7ed60ed2ba..f4b10a3776 100644 --- a/std/testing.zig +++ b/std/testing.zig @@ -42,6 +42,7 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void { TypeId.Float, TypeId.ComptimeFloat, TypeId.ComptimeInt, + TypeId.EnumLiteral, TypeId.Enum, TypeId.Fn, TypeId.Promise, diff --git a/std/zig/ast.zig b/std/zig/ast.zig index 77daeb16e1..2560c47e80 100644 --- a/std/zig/ast.zig +++ b/std/zig/ast.zig @@ -296,6 +296,7 @@ pub const Node = struct { // Primary expressions IntegerLiteral, FloatLiteral, + EnumLiteral, StringLiteral, MultilineStringLiteral, CharLiteral, @@ -1849,6 +1850,24 @@ pub const Node = struct { } }; + pub const EnumLiteral = struct { + base: Node, + dot: TokenIndex, + name: TokenIndex, + + pub fn iterate(self: *EnumLiteral, index: usize) ?*Node { + return null; + } + + pub fn firstToken(self: *const EnumLiteral) TokenIndex { + return self.dot; + } + + pub fn lastToken(self: *const EnumLiteral) TokenIndex { + return self.name; + } + }; + pub const FloatLiteral = struct { base: Node, token: TokenIndex, diff --git a/std/zig/parse.zig b/std/zig/parse.zig index 7ab656413f..fe946fb802 100644 --- a/std/zig/parse.zig +++ b/std/zig/parse.zig @@ -2543,6 +2543,27 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.IntegerLiteral, token.index); continue; }, + Token.Id.Period => { + const name_token = nextToken(&tok_it, &tree); + if (name_token.ptr.id != Token.Id.Identifier) { + ((try tree.errors.addOne())).* = Error{ + .ExpectedToken = Error.ExpectedToken{ + .token = name_token.index, + .expected_id = Token.Id.Identifier, + }, + }; + return tree; + } + + const node = try arena.create(ast.Node.EnumLiteral); + node.* = ast.Node.EnumLiteral{ + .base = ast.Node{ .id = ast.Node.Id.EnumLiteral }, + .dot = token.index, + .name = name_token.index, + }; + opt_ctx.store(&node.base); + continue; + }, Token.Id.FloatLiteral => { _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.FloatLiteral, token.index); continue; diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index 8b9c0c2d64..8ffad3ab77 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -1,3 +1,10 @@ +test "zig fmt: enum literal" { + try testCanonical( + \\const x = .hi; + \\ + ); +} + test "zig fmt: character literal larger than u8" { try testCanonical( \\const x = '\U01f4a9'; diff --git a/std/zig/render.zig b/std/zig/render.zig index 3adf67c23b..fe14c2ef8c 100644 --- a/std/zig/render.zig +++ b/std/zig/render.zig @@ -1667,6 +1667,13 @@ fn renderExpression( return renderToken(tree, stream, asm_output.lastToken(), indent, start_col, space); // ) }, + ast.Node.Id.EnumLiteral => { + const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base); + + try renderToken(tree, stream, enum_literal.dot, indent, start_col, Space.None); // . + return renderToken(tree, stream, enum_literal.name, indent, start_col, space); // name + }, + ast.Node.Id.StructField, ast.Node.Id.UnionTag, ast.Node.Id.EnumTag, diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig index 899aeea67d..fb6fa63593 100644 --- a/test/stage1/behavior/enum.zig +++ b/test/stage1/behavior/enum.zig @@ -892,3 +892,12 @@ test "tag name with assigned enum values" { var b = LocalFoo.B; expect(mem.eql(u8, @tagName(b), "B")); } + +test "enum literal equality" { + const x = .hi; + const y = .ok; + const z = .hi; + + expect(x != y); + expect(x == z); +} diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index 8676c7628d..2d088fa261 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -190,7 +190,7 @@ fn testUnion() void { expect(TypeId(typeinfo_info) == TypeId.Union); expect(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto); expect(typeinfo_info.Union.tag_type.? == TypeId); - expect(typeinfo_info.Union.fields.len == 24); + expect(typeinfo_info.Union.fields.len == 25); expect(typeinfo_info.Union.fields[4].enum_field != null); expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4); expect(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));