Commit e0b01bd4a9

Vexu <git@vexu.eu>
2020-08-18 13:28:33
stage2: enum literals
1 parent 31d8efc
Changed files (5)
src-self-hosted/astgen.zig
@@ -130,6 +130,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
         .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr),
         .ArrayType => return rlWrap(mod, scope, rl, try arrayType(mod, scope, node.castTag(.ArrayType).?)),
         .ArrayTypeSentinel => return rlWrap(mod, scope, rl, try arrayTypeSentinel(mod, scope, node.castTag(.ArrayTypeSentinel).?)),
+        .EnumLiteral => return rlWrap(mod, scope, rl, try enumLiteral(mod, scope, node.castTag(.EnumLiteral).?)),
 
         .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
         .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}),
@@ -158,7 +159,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
         .ErrorType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorType", .{}),
         .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}),
         .AnyFrameType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyFrameType", .{}),
-        .EnumLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .EnumLiteral", .{}),
         .MultilineStringLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .MultilineStringLiteral", .{}),
         .CharLiteral => return mod.failNode(scope, node, "TODO implement astgen.expr for .CharLiteral", .{}),
         .ErrorSetDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorSetDecl", .{}),
@@ -527,6 +527,14 @@ fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSenti
     }, .{});
 }
 
+fn enumLiteral(mod: *Module, scope: *Scope, node: *ast.Node.EnumLiteral) !*zir.Inst {
+    const tree = scope.tree();
+    const src = tree.token_locs[node.name].start;
+    const name = try identifierTokenString(mod, scope, node.name);
+
+    return addZIRInst(mod, scope, src, zir.Inst.EnumLiteral, .{ .name = name }, .{});
+}
+
 fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
     const tree = scope.tree();
     const src = tree.token_locs[node.rtoken].start;
src-self-hosted/type.zig
@@ -75,6 +75,7 @@ pub const Type = extern union {
             .optional_single_const_pointer,
             .optional_single_mut_pointer,
             => return .Optional,
+            .enum_literal => return .EnumLiteral,
         }
     }
 
@@ -127,6 +128,7 @@ pub const Type = extern union {
         if (zig_tag_a != zig_tag_b)
             return false;
         switch (zig_tag_a) {
+            .EnumLiteral => return true,
             .Type => return true,
             .Void => return true,
             .Bool => return true,
@@ -211,7 +213,6 @@ pub const Type = extern union {
             .Frame,
             .AnyFrame,
             .Vector,
-            .EnumLiteral,
             => std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),
         }
     }
@@ -327,6 +328,7 @@ pub const Type = extern union {
             .fn_ccc_void_no_args,
             .single_const_pointer_to_comptime_int,
             .const_slice_u8,
+            .enum_literal,
             => unreachable,
 
             .array_u8_sentinel_0 => return self.copyPayloadShallow(allocator, Payload.Array_u8_Sentinel0),
@@ -437,6 +439,7 @@ pub const Type = extern union {
                 .noreturn,
                 => return out_stream.writeAll(@tagName(t)),
 
+                .enum_literal => return out_stream.writeAll("@TypeOf(.EnumLiteral)"),
                 .@"null" => return out_stream.writeAll("@TypeOf(null)"),
                 .@"undefined" => return out_stream.writeAll("@TypeOf(undefined)"),
 
@@ -561,6 +564,7 @@ pub const Type = extern union {
             .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type),
             .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
             .const_slice_u8 => return Value.initTag(.const_slice_u8_type),
+            .enum_literal => return Value.initTag(.enum_literal_type),
             else => {
                 const ty_payload = try allocator.create(Value.Payload.Ty);
                 ty_payload.* = .{ .ty = self };
@@ -625,6 +629,7 @@ pub const Type = extern union {
             .noreturn,
             .@"null",
             .@"undefined",
+            .enum_literal,
             => false,
         };
     }
@@ -716,6 +721,7 @@ pub const Type = extern union {
             .noreturn,
             .@"null",
             .@"undefined",
+            .enum_literal,
             => unreachable,
         };
     }
@@ -736,6 +742,7 @@ pub const Type = extern union {
             .noreturn => unreachable,
             .@"null" => unreachable,
             .@"undefined" => unreachable,
+            .enum_literal => unreachable,
 
             .u8,
             .i8,
@@ -863,6 +870,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => false,
 
             .single_const_pointer,
@@ -924,6 +932,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => false,
 
             .const_slice_u8 => true,
@@ -980,6 +989,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => false,
 
             .single_const_pointer,
@@ -1042,6 +1052,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => false,
         };
     }
@@ -1147,6 +1158,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_const_pointer,
             .optional_single_mut_pointer,
+            .enum_literal,
             => unreachable,
 
             .array => self.cast(Payload.Array).?.elem_type,
@@ -1252,6 +1264,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => unreachable,
 
             .array => self.cast(Payload.Array).?.len,
@@ -1311,6 +1324,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => unreachable,
 
             .array, .array_u8 => return null,
@@ -1368,6 +1382,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => false,
 
             .int_signed,
@@ -1428,6 +1443,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => false,
 
             .int_unsigned,
@@ -1478,6 +1494,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => unreachable,
 
             .int_unsigned => .{ .signed = false, .bits = self.cast(Payload.IntUnsigned).?.bits },
@@ -1546,6 +1563,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => false,
 
             .usize,
@@ -1643,6 +1661,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => unreachable,
         };
     }
@@ -1706,6 +1725,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => unreachable,
         }
     }
@@ -1768,6 +1788,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => unreachable,
         }
     }
@@ -1830,6 +1851,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => unreachable,
         };
     }
@@ -1889,6 +1911,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => unreachable,
         };
     }
@@ -1948,6 +1971,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => unreachable,
         };
     }
@@ -2007,6 +2031,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => false,
         };
     }
@@ -2055,6 +2080,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => return null,
 
             .void => return Value.initTag(.void_value),
@@ -2143,6 +2169,7 @@ pub const Type = extern union {
             .optional,
             .optional_single_mut_pointer,
             .optional_single_const_pointer,
+            .enum_literal,
             => return false,
         };
     }
@@ -2186,6 +2213,7 @@ pub const Type = extern union {
         comptime_int,
         comptime_float,
         noreturn,
+        enum_literal,
         @"null",
         @"undefined",
         fn_noreturn_no_args,
src-self-hosted/value.zig
@@ -60,6 +60,7 @@ pub const Value = extern union {
         fn_ccc_void_no_args_type,
         single_const_pointer_to_comptime_int_type,
         const_slice_u8_type,
+        enum_literal_type,
 
         undef,
         zero,
@@ -87,6 +88,7 @@ pub const Value = extern union {
         float_32,
         float_64,
         float_128,
+        enum_literal,
 
         pub const last_no_payload_tag = Tag.bool_false;
         pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
@@ -164,6 +166,7 @@ pub const Value = extern union {
             .fn_ccc_void_no_args_type,
             .single_const_pointer_to_comptime_int_type,
             .const_slice_u8_type,
+            .enum_literal_type,
             .undef,
             .zero,
             .void_value,
@@ -213,7 +216,7 @@ pub const Value = extern union {
                 };
                 return Value{ .ptr_otherwise = &new_payload.base };
             },
-            .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),
+            .enum_literal, .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),
             .repeated => {
                 const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise);
                 const new_payload = try allocator.create(Payload.Repeated);
@@ -285,6 +288,7 @@ pub const Value = extern union {
             .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),
             .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
             .const_slice_u8_type => return out_stream.writeAll("[]const u8"),
+            .enum_literal_type => return out_stream.writeAll("@TypeOf(.EnumLiteral)"),
 
             .null_value => return out_stream.writeAll("null"),
             .undef => return out_stream.writeAll("undefined"),
@@ -318,7 +322,7 @@ pub const Value = extern union {
                 val = elem_ptr.array_ptr;
             },
             .empty_array => return out_stream.writeAll(".{}"),
-            .bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream),
+            .enum_literal, .bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream),
             .repeated => {
                 try out_stream.writeAll("(repeated) ");
                 val = val.cast(Payload.Repeated).?.val;
@@ -391,6 +395,7 @@ pub const Value = extern union {
             .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args),
             .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
             .const_slice_u8_type => Type.initTag(.const_slice_u8),
+            .enum_literal_type => Type.initTag(.enum_literal),
 
             .undef,
             .zero,
@@ -414,6 +419,7 @@ pub const Value = extern union {
             .float_32,
             .float_64,
             .float_128,
+            .enum_literal,
             => unreachable,
         };
     }
@@ -462,6 +468,7 @@ pub const Value = extern union {
             .fn_ccc_void_no_args_type,
             .single_const_pointer_to_comptime_int_type,
             .const_slice_u8_type,
+            .enum_literal_type,
             .null_value,
             .function,
             .ref_val,
@@ -476,6 +483,7 @@ pub const Value = extern union {
             .void_value,
             .unreachable_value,
             .empty_array,
+            .enum_literal,
             => unreachable,
 
             .undef => unreachable,
@@ -537,6 +545,7 @@ pub const Value = extern union {
             .fn_ccc_void_no_args_type,
             .single_const_pointer_to_comptime_int_type,
             .const_slice_u8_type,
+            .enum_literal_type,
             .null_value,
             .function,
             .ref_val,
@@ -551,6 +560,7 @@ pub const Value = extern union {
             .void_value,
             .unreachable_value,
             .empty_array,
+            .enum_literal,
             => unreachable,
 
             .undef => unreachable,
@@ -612,6 +622,7 @@ pub const Value = extern union {
             .fn_ccc_void_no_args_type,
             .single_const_pointer_to_comptime_int_type,
             .const_slice_u8_type,
+            .enum_literal_type,
             .null_value,
             .function,
             .ref_val,
@@ -626,6 +637,7 @@ pub const Value = extern union {
             .void_value,
             .unreachable_value,
             .empty_array,
+            .enum_literal,
             => unreachable,
 
             .undef => unreachable,
@@ -713,6 +725,7 @@ pub const Value = extern union {
             .fn_ccc_void_no_args_type,
             .single_const_pointer_to_comptime_int_type,
             .const_slice_u8_type,
+            .enum_literal_type,
             .null_value,
             .function,
             .ref_val,
@@ -728,6 +741,7 @@ pub const Value = extern union {
             .void_value,
             .unreachable_value,
             .empty_array,
+            .enum_literal,
             => unreachable,
 
             .zero,
@@ -793,6 +807,7 @@ pub const Value = extern union {
             .fn_ccc_void_no_args_type,
             .single_const_pointer_to_comptime_int_type,
             .const_slice_u8_type,
+            .enum_literal_type,
             .null_value,
             .function,
             .ref_val,
@@ -807,6 +822,7 @@ pub const Value = extern union {
             .void_value,
             .unreachable_value,
             .empty_array,
+            .enum_literal,
             => unreachable,
 
             .zero,
@@ -953,6 +969,7 @@ pub const Value = extern union {
             .fn_ccc_void_no_args_type,
             .single_const_pointer_to_comptime_int_type,
             .const_slice_u8_type,
+            .enum_literal_type,
             .bool_true,
             .bool_false,
             .null_value,
@@ -970,6 +987,7 @@ pub const Value = extern union {
             .empty_array,
             .void_value,
             .unreachable_value,
+            .enum_literal,
             => unreachable,
 
             .zero => false,
@@ -1025,6 +1043,7 @@ pub const Value = extern union {
             .fn_ccc_void_no_args_type,
             .single_const_pointer_to_comptime_int_type,
             .const_slice_u8_type,
+            .enum_literal_type,
             .null_value,
             .function,
             .ref_val,
@@ -1036,6 +1055,7 @@ pub const Value = extern union {
             .void_value,
             .unreachable_value,
             .empty_array,
+            .enum_literal,
             => unreachable,
 
             .zero,
@@ -1102,6 +1122,11 @@ pub const Value = extern union {
     }
 
     pub fn eql(a: Value, b: Value) bool {
+        if (a.tag() == b.tag() and a.tag() == .enum_literal) {
+            const a_name = @fieldParentPtr(Payload.Bytes, "base", a.ptr_otherwise).data;
+            const b_name = @fieldParentPtr(Payload.Bytes, "base", b.ptr_otherwise).data;
+            return std.mem.eql(u8, a_name, b_name);
+        }
         // TODO non numerical comparisons
         return compare(a, .eq, b);
     }
@@ -1151,6 +1176,7 @@ pub const Value = extern union {
             .fn_ccc_void_no_args_type,
             .single_const_pointer_to_comptime_int_type,
             .const_slice_u8_type,
+            .enum_literal_type,
             .zero,
             .bool_true,
             .bool_false,
@@ -1170,6 +1196,7 @@ pub const Value = extern union {
             .void_value,
             .unreachable_value,
             .empty_array,
+            .enum_literal,
             => unreachable,
 
             .ref_val => self.cast(Payload.RefVal).?.val,
@@ -1227,6 +1254,7 @@ pub const Value = extern union {
             .fn_ccc_void_no_args_type,
             .single_const_pointer_to_comptime_int_type,
             .const_slice_u8_type,
+            .enum_literal_type,
             .zero,
             .bool_true,
             .bool_false,
@@ -1246,6 +1274,7 @@ pub const Value = extern union {
             .float_128,
             .void_value,
             .unreachable_value,
+            .enum_literal,
             => unreachable,
 
             .empty_array => unreachable, // out of bounds array index
@@ -1320,6 +1349,7 @@ pub const Value = extern union {
             .fn_ccc_void_no_args_type,
             .single_const_pointer_to_comptime_int_type,
             .const_slice_u8_type,
+            .enum_literal_type,
             .zero,
             .empty_array,
             .bool_true,
@@ -1339,6 +1369,7 @@ pub const Value = extern union {
             .float_64,
             .float_128,
             .void_value,
+            .enum_literal,
             => false,
 
             .undef => unreachable,
src-self-hosted/zir.zig
@@ -231,6 +231,8 @@ pub const Inst = struct {
         unwrap_err_unsafe,
         /// Takes a *E!T and raises a compiler error if T != void
         ensure_err_payload_void,
+        /// Enum literal
+        enum_literal,
 
         pub fn Type(tag: Tag) type {
             return switch (tag) {
@@ -326,6 +328,7 @@ pub const Inst = struct {
                 .elemptr => ElemPtr,
                 .condbr => CondBr,
                 .ptr_type => PtrType,
+                .enum_literal => EnumLiteral,
             };
         }
 
@@ -410,6 +413,7 @@ pub const Inst = struct {
                 .unwrap_err_unsafe,
                 .ptr_type,
                 .ensure_err_payload_void,
+                .enum_literal,
                 => false,
 
                 .@"break",
@@ -869,6 +873,16 @@ pub const Inst = struct {
         },
         kw_args: struct {},
     };
+
+    pub const EnumLiteral = struct {
+        pub const base_tag = Tag.enum_literal;
+        base: Inst,
+
+        positionals: struct {
+            name: []const u8,
+        },
+        kw_args: struct {},
+    };
 };
 
 pub const ErrorMsg = struct {
src-self-hosted/zir_sema.zig
@@ -115,6 +115,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
         .ensure_err_payload_void => return analyzeInstEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?),
         .array_type => return analyzeInstArrayType(mod, scope, old_inst.castTag(.array_type).?),
         .array_type_sentinel => return analyzeInstArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?),
+        .enum_literal => return analyzeInstEnumLiteral(mod, scope, old_inst.castTag(.enum_literal).?),
     }
 }
 
@@ -701,6 +702,18 @@ fn analyzeInstArrayTypeSentinel(mod: *Module, scope: *Scope, array: *zir.Inst.Ar
     return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), sentinel.val, elem_type));
 }
 
+fn analyzeInstEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiteral) InnerError!*Inst {
+    const payload = try scope.arena().create(Value.Payload.Bytes);
+    payload.* = .{
+        .base = .{ .tag = .enum_literal },
+        .data = try scope.arena().dupe(u8, inst.positionals.name),
+    };
+    return mod.constInst(scope, inst.base.src, .{
+        .ty = Type.initTag(.enum_literal),
+        .val = Value.initPayload(&payload.base),
+    });
+}
+
 fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst {
     const operand = try resolveInst(mod, scope, unwrap.positionals.operand);
     assert(operand.ty.zigTypeTag() == .Pointer);