blob eacbd4e9 (55129B) - Raw
1 const std = @import("std"); 2 const Type = @import("type.zig").Type; 3 const log2 = std.math.log2; 4 const assert = std.debug.assert; 5 const BigIntConst = std.math.big.int.Const; 6 const BigIntMutable = std.math.big.int.Mutable; 7 const Target = std.Target; 8 const Allocator = std.mem.Allocator; 9 const Module = @import("Module.zig"); 10 11 /// This is the raw data, with no bookkeeping, no memory awareness, 12 /// no de-duplication, and no type system awareness. 13 /// It's important for this type to be small. 14 /// This union takes advantage of the fact that the first page of memory 15 /// is unmapped, giving us 4096 possible enum tags that have no payload. 16 pub const Value = extern union { 17 /// If the tag value is less than Tag.no_payload_count, then no pointer 18 /// dereference is needed. 19 tag_if_small_enough: usize, 20 ptr_otherwise: *Payload, 21 22 pub const Tag = enum { 23 // The first section of this enum are tags that require no payload. 24 u8_type, 25 i8_type, 26 u16_type, 27 i16_type, 28 u32_type, 29 i32_type, 30 u64_type, 31 i64_type, 32 usize_type, 33 isize_type, 34 c_short_type, 35 c_ushort_type, 36 c_int_type, 37 c_uint_type, 38 c_long_type, 39 c_ulong_type, 40 c_longlong_type, 41 c_ulonglong_type, 42 c_longdouble_type, 43 f16_type, 44 f32_type, 45 f64_type, 46 f128_type, 47 c_void_type, 48 bool_type, 49 void_type, 50 type_type, 51 anyerror_type, 52 comptime_int_type, 53 comptime_float_type, 54 noreturn_type, 55 null_type, 56 undefined_type, 57 fn_noreturn_no_args_type, 58 fn_void_no_args_type, 59 fn_naked_noreturn_no_args_type, 60 fn_ccc_void_no_args_type, 61 single_const_pointer_to_comptime_int_type, 62 const_slice_u8_type, 63 enum_literal_type, 64 anyframe_type, 65 66 undef, 67 zero, 68 void_value, 69 unreachable_value, 70 empty_array, 71 null_value, 72 bool_true, 73 bool_false, // See last_no_payload_tag below. 74 // After this, the tag requires a payload. 75 76 ty, 77 int_type, 78 int_u64, 79 int_i64, 80 int_big_positive, 81 int_big_negative, 82 function, 83 variable, 84 ref_val, 85 decl_ref, 86 elem_ptr, 87 bytes, 88 repeated, // the value is a value repeated some number of times 89 float_16, 90 float_32, 91 float_64, 92 float_128, 93 enum_literal, 94 error_set, 95 @"error", 96 97 pub const last_no_payload_tag = Tag.bool_false; 98 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; 99 }; 100 101 pub fn initTag(small_tag: Tag) Value { 102 assert(@enumToInt(small_tag) < Tag.no_payload_count); 103 return .{ .tag_if_small_enough = @enumToInt(small_tag) }; 104 } 105 106 pub fn initPayload(payload: *Payload) Value { 107 assert(@enumToInt(payload.tag) >= Tag.no_payload_count); 108 return .{ .ptr_otherwise = payload }; 109 } 110 111 pub fn tag(self: Value) Tag { 112 if (self.tag_if_small_enough < Tag.no_payload_count) { 113 return @intToEnum(Tag, @intCast(@TagType(Tag), self.tag_if_small_enough)); 114 } else { 115 return self.ptr_otherwise.tag; 116 } 117 } 118 119 pub fn cast(self: Value, comptime T: type) ?*T { 120 if (self.tag_if_small_enough < Tag.no_payload_count) 121 return null; 122 123 const expected_tag = std.meta.fieldInfo(T, "base").default_value.?.tag; 124 if (self.ptr_otherwise.tag != expected_tag) 125 return null; 126 127 return @fieldParentPtr(T, "base", self.ptr_otherwise); 128 } 129 130 pub fn copy(self: Value, allocator: *Allocator) error{OutOfMemory}!Value { 131 if (self.tag_if_small_enough < Tag.no_payload_count) { 132 return Value{ .tag_if_small_enough = self.tag_if_small_enough }; 133 } else switch (self.ptr_otherwise.tag) { 134 .u8_type, 135 .i8_type, 136 .u16_type, 137 .i16_type, 138 .u32_type, 139 .i32_type, 140 .u64_type, 141 .i64_type, 142 .usize_type, 143 .isize_type, 144 .c_short_type, 145 .c_ushort_type, 146 .c_int_type, 147 .c_uint_type, 148 .c_long_type, 149 .c_ulong_type, 150 .c_longlong_type, 151 .c_ulonglong_type, 152 .c_longdouble_type, 153 .f16_type, 154 .f32_type, 155 .f64_type, 156 .f128_type, 157 .c_void_type, 158 .bool_type, 159 .void_type, 160 .type_type, 161 .anyerror_type, 162 .comptime_int_type, 163 .comptime_float_type, 164 .noreturn_type, 165 .null_type, 166 .undefined_type, 167 .fn_noreturn_no_args_type, 168 .fn_void_no_args_type, 169 .fn_naked_noreturn_no_args_type, 170 .fn_ccc_void_no_args_type, 171 .single_const_pointer_to_comptime_int_type, 172 .const_slice_u8_type, 173 .enum_literal_type, 174 .anyframe_type, 175 .undef, 176 .zero, 177 .void_value, 178 .unreachable_value, 179 .empty_array, 180 .null_value, 181 .bool_true, 182 .bool_false, 183 => unreachable, 184 185 .ty => { 186 const payload = @fieldParentPtr(Payload.Ty, "base", self.ptr_otherwise); 187 const new_payload = try allocator.create(Payload.Ty); 188 new_payload.* = .{ 189 .base = payload.base, 190 .ty = try payload.ty.copy(allocator), 191 }; 192 return Value{ .ptr_otherwise = &new_payload.base }; 193 }, 194 .int_type => return self.copyPayloadShallow(allocator, Payload.IntType), 195 .int_u64 => return self.copyPayloadShallow(allocator, Payload.Int_u64), 196 .int_i64 => return self.copyPayloadShallow(allocator, Payload.Int_i64), 197 .int_big_positive => { 198 @panic("TODO implement copying of big ints"); 199 }, 200 .int_big_negative => { 201 @panic("TODO implement copying of big ints"); 202 }, 203 .function => return self.copyPayloadShallow(allocator, Payload.Function), 204 .variable => return self.copyPayloadShallow(allocator, Payload.Variable), 205 .ref_val => { 206 const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise); 207 const new_payload = try allocator.create(Payload.RefVal); 208 new_payload.* = .{ 209 .base = payload.base, 210 .val = try payload.val.copy(allocator), 211 }; 212 return Value{ .ptr_otherwise = &new_payload.base }; 213 }, 214 .decl_ref => return self.copyPayloadShallow(allocator, Payload.DeclRef), 215 .elem_ptr => { 216 const payload = @fieldParentPtr(Payload.ElemPtr, "base", self.ptr_otherwise); 217 const new_payload = try allocator.create(Payload.ElemPtr); 218 new_payload.* = .{ 219 .base = payload.base, 220 .array_ptr = try payload.array_ptr.copy(allocator), 221 .index = payload.index, 222 }; 223 return Value{ .ptr_otherwise = &new_payload.base }; 224 }, 225 .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes), 226 .repeated => { 227 const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise); 228 const new_payload = try allocator.create(Payload.Repeated); 229 new_payload.* = .{ 230 .base = payload.base, 231 .val = try payload.val.copy(allocator), 232 }; 233 return Value{ .ptr_otherwise = &new_payload.base }; 234 }, 235 .float_16 => return self.copyPayloadShallow(allocator, Payload.Float_16), 236 .float_32 => return self.copyPayloadShallow(allocator, Payload.Float_32), 237 .float_64 => return self.copyPayloadShallow(allocator, Payload.Float_64), 238 .float_128 => return self.copyPayloadShallow(allocator, Payload.Float_128), 239 .enum_literal => { 240 const payload = @fieldParentPtr(Payload.Bytes, "base", self.ptr_otherwise); 241 const new_payload = try allocator.create(Payload.Bytes); 242 new_payload.* = .{ 243 .base = payload.base, 244 .data = try allocator.dupe(u8, payload.data), 245 }; 246 return Value{ .ptr_otherwise = &new_payload.base }; 247 }, 248 .@"error" => return self.copyPayloadShallow(allocator, Payload.Error), 249 250 // memory is managed by the declaration 251 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet), 252 } 253 } 254 255 fn copyPayloadShallow(self: Value, allocator: *Allocator, comptime T: type) error{OutOfMemory}!Value { 256 const payload = @fieldParentPtr(T, "base", self.ptr_otherwise); 257 const new_payload = try allocator.create(T); 258 new_payload.* = payload.*; 259 return Value{ .ptr_otherwise = &new_payload.base }; 260 } 261 262 pub fn format( 263 self: Value, 264 comptime fmt: []const u8, 265 options: std.fmt.FormatOptions, 266 out_stream: anytype, 267 ) !void { 268 comptime assert(fmt.len == 0); 269 var val = self; 270 while (true) switch (val.tag()) { 271 .u8_type => return out_stream.writeAll("u8"), 272 .i8_type => return out_stream.writeAll("i8"), 273 .u16_type => return out_stream.writeAll("u16"), 274 .i16_type => return out_stream.writeAll("i16"), 275 .u32_type => return out_stream.writeAll("u32"), 276 .i32_type => return out_stream.writeAll("i32"), 277 .u64_type => return out_stream.writeAll("u64"), 278 .i64_type => return out_stream.writeAll("i64"), 279 .isize_type => return out_stream.writeAll("isize"), 280 .usize_type => return out_stream.writeAll("usize"), 281 .c_short_type => return out_stream.writeAll("c_short"), 282 .c_ushort_type => return out_stream.writeAll("c_ushort"), 283 .c_int_type => return out_stream.writeAll("c_int"), 284 .c_uint_type => return out_stream.writeAll("c_uint"), 285 .c_long_type => return out_stream.writeAll("c_long"), 286 .c_ulong_type => return out_stream.writeAll("c_ulong"), 287 .c_longlong_type => return out_stream.writeAll("c_longlong"), 288 .c_ulonglong_type => return out_stream.writeAll("c_ulonglong"), 289 .c_longdouble_type => return out_stream.writeAll("c_longdouble"), 290 .f16_type => return out_stream.writeAll("f16"), 291 .f32_type => return out_stream.writeAll("f32"), 292 .f64_type => return out_stream.writeAll("f64"), 293 .f128_type => return out_stream.writeAll("f128"), 294 .c_void_type => return out_stream.writeAll("c_void"), 295 .bool_type => return out_stream.writeAll("bool"), 296 .void_type => return out_stream.writeAll("void"), 297 .type_type => return out_stream.writeAll("type"), 298 .anyerror_type => return out_stream.writeAll("anyerror"), 299 .comptime_int_type => return out_stream.writeAll("comptime_int"), 300 .comptime_float_type => return out_stream.writeAll("comptime_float"), 301 .noreturn_type => return out_stream.writeAll("noreturn"), 302 .null_type => return out_stream.writeAll("@TypeOf(null)"), 303 .undefined_type => return out_stream.writeAll("@TypeOf(undefined)"), 304 .fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"), 305 .fn_void_no_args_type => return out_stream.writeAll("fn() void"), 306 .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"), 307 .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"), 308 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"), 309 .const_slice_u8_type => return out_stream.writeAll("[]const u8"), 310 .enum_literal_type => return out_stream.writeAll("@TypeOf(.EnumLiteral)"), 311 .anyframe_type => return out_stream.writeAll("anyframe"), 312 313 .null_value => return out_stream.writeAll("null"), 314 .undef => return out_stream.writeAll("undefined"), 315 .zero => return out_stream.writeAll("0"), 316 .void_value => return out_stream.writeAll("{}"), 317 .unreachable_value => return out_stream.writeAll("unreachable"), 318 .bool_true => return out_stream.writeAll("true"), 319 .bool_false => return out_stream.writeAll("false"), 320 .ty => return val.cast(Payload.Ty).?.ty.format("", options, out_stream), 321 .int_type => { 322 const int_type = val.cast(Payload.IntType).?; 323 return out_stream.print("{}{}", .{ 324 if (int_type.signed) "s" else "u", 325 int_type.bits, 326 }); 327 }, 328 .int_u64 => return std.fmt.formatIntValue(val.cast(Payload.Int_u64).?.int, "", options, out_stream), 329 .int_i64 => return std.fmt.formatIntValue(val.cast(Payload.Int_i64).?.int, "", options, out_stream), 330 .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}), 331 .int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}), 332 .function => return out_stream.writeAll("(function)"), 333 .variable => return out_stream.writeAll("(variable)"), 334 .ref_val => { 335 const ref_val = val.cast(Payload.RefVal).?; 336 try out_stream.writeAll("&const "); 337 val = ref_val.val; 338 }, 339 .decl_ref => return out_stream.writeAll("(decl ref)"), 340 .elem_ptr => { 341 const elem_ptr = val.cast(Payload.ElemPtr).?; 342 try out_stream.print("&[{}] ", .{elem_ptr.index}); 343 val = elem_ptr.array_ptr; 344 }, 345 .empty_array => return out_stream.writeAll(".{}"), 346 .enum_literal, .bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream), 347 .repeated => { 348 try out_stream.writeAll("(repeated) "); 349 val = val.cast(Payload.Repeated).?.val; 350 }, 351 .float_16 => return out_stream.print("{}", .{val.cast(Payload.Float_16).?.val}), 352 .float_32 => return out_stream.print("{}", .{val.cast(Payload.Float_32).?.val}), 353 .float_64 => return out_stream.print("{}", .{val.cast(Payload.Float_64).?.val}), 354 .float_128 => return out_stream.print("{}", .{val.cast(Payload.Float_128).?.val}), 355 .error_set => { 356 const error_set = val.cast(Payload.ErrorSet).?; 357 try out_stream.writeAll("error{"); 358 for (error_set.fields.items()) |entry| { 359 try out_stream.print("{},", .{entry.value}); 360 } 361 return out_stream.writeAll("}"); 362 }, 363 .@"error" => return out_stream.print("error.{}", .{val.cast(Payload.Error).?.name}), 364 }; 365 } 366 367 /// Asserts that the value is representable as an array of bytes. 368 /// Copies the value into a freshly allocated slice of memory, which is owned by the caller. 369 pub fn toAllocatedBytes(self: Value, allocator: *Allocator) ![]u8 { 370 if (self.cast(Payload.Bytes)) |bytes| { 371 return std.mem.dupe(allocator, u8, bytes.data); 372 } 373 if (self.cast(Payload.Repeated)) |repeated| { 374 @panic("TODO implement toAllocatedBytes for this Value tag"); 375 } 376 if (self.cast(Payload.DeclRef)) |declref| { 377 const val = try declref.decl.value(); 378 return val.toAllocatedBytes(allocator); 379 } 380 unreachable; 381 } 382 383 /// Asserts that the value is representable as a type. 384 pub fn toType(self: Value) Type { 385 return switch (self.tag()) { 386 .ty => self.cast(Payload.Ty).?.ty, 387 .int_type => @panic("TODO int type to type"), 388 389 .u8_type => Type.initTag(.u8), 390 .i8_type => Type.initTag(.i8), 391 .u16_type => Type.initTag(.u16), 392 .i16_type => Type.initTag(.i16), 393 .u32_type => Type.initTag(.u32), 394 .i32_type => Type.initTag(.i32), 395 .u64_type => Type.initTag(.u64), 396 .i64_type => Type.initTag(.i64), 397 .usize_type => Type.initTag(.usize), 398 .isize_type => Type.initTag(.isize), 399 .c_short_type => Type.initTag(.c_short), 400 .c_ushort_type => Type.initTag(.c_ushort), 401 .c_int_type => Type.initTag(.c_int), 402 .c_uint_type => Type.initTag(.c_uint), 403 .c_long_type => Type.initTag(.c_long), 404 .c_ulong_type => Type.initTag(.c_ulong), 405 .c_longlong_type => Type.initTag(.c_longlong), 406 .c_ulonglong_type => Type.initTag(.c_ulonglong), 407 .c_longdouble_type => Type.initTag(.c_longdouble), 408 .f16_type => Type.initTag(.f16), 409 .f32_type => Type.initTag(.f32), 410 .f64_type => Type.initTag(.f64), 411 .f128_type => Type.initTag(.f128), 412 .c_void_type => Type.initTag(.c_void), 413 .bool_type => Type.initTag(.bool), 414 .void_type => Type.initTag(.void), 415 .type_type => Type.initTag(.type), 416 .anyerror_type => Type.initTag(.anyerror), 417 .comptime_int_type => Type.initTag(.comptime_int), 418 .comptime_float_type => Type.initTag(.comptime_float), 419 .noreturn_type => Type.initTag(.noreturn), 420 .null_type => Type.initTag(.@"null"), 421 .undefined_type => Type.initTag(.@"undefined"), 422 .fn_noreturn_no_args_type => Type.initTag(.fn_noreturn_no_args), 423 .fn_void_no_args_type => Type.initTag(.fn_void_no_args), 424 .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args), 425 .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args), 426 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int), 427 .const_slice_u8_type => Type.initTag(.const_slice_u8), 428 .enum_literal_type => Type.initTag(.enum_literal), 429 .anyframe_type => Type.initTag(.@"anyframe"), 430 .error_set => @panic("TODO error set to type"), 431 432 .undef, 433 .zero, 434 .void_value, 435 .unreachable_value, 436 .empty_array, 437 .bool_true, 438 .bool_false, 439 .null_value, 440 .int_u64, 441 .int_i64, 442 .int_big_positive, 443 .int_big_negative, 444 .function, 445 .variable, 446 .ref_val, 447 .decl_ref, 448 .elem_ptr, 449 .bytes, 450 .repeated, 451 .float_16, 452 .float_32, 453 .float_64, 454 .float_128, 455 .enum_literal, 456 .@"error", 457 => unreachable, 458 }; 459 } 460 461 /// Asserts the value is an integer. 462 pub fn toBigInt(self: Value, space: *BigIntSpace) BigIntConst { 463 switch (self.tag()) { 464 .ty, 465 .int_type, 466 .u8_type, 467 .i8_type, 468 .u16_type, 469 .i16_type, 470 .u32_type, 471 .i32_type, 472 .u64_type, 473 .i64_type, 474 .usize_type, 475 .isize_type, 476 .c_short_type, 477 .c_ushort_type, 478 .c_int_type, 479 .c_uint_type, 480 .c_long_type, 481 .c_ulong_type, 482 .c_longlong_type, 483 .c_ulonglong_type, 484 .c_longdouble_type, 485 .f16_type, 486 .f32_type, 487 .f64_type, 488 .f128_type, 489 .c_void_type, 490 .bool_type, 491 .void_type, 492 .type_type, 493 .anyerror_type, 494 .comptime_int_type, 495 .comptime_float_type, 496 .noreturn_type, 497 .null_type, 498 .undefined_type, 499 .fn_noreturn_no_args_type, 500 .fn_void_no_args_type, 501 .fn_naked_noreturn_no_args_type, 502 .fn_ccc_void_no_args_type, 503 .single_const_pointer_to_comptime_int_type, 504 .const_slice_u8_type, 505 .enum_literal_type, 506 .anyframe_type, 507 .null_value, 508 .function, 509 .variable, 510 .ref_val, 511 .decl_ref, 512 .elem_ptr, 513 .bytes, 514 .repeated, 515 .float_16, 516 .float_32, 517 .float_64, 518 .float_128, 519 .void_value, 520 .unreachable_value, 521 .empty_array, 522 .enum_literal, 523 .error_set, 524 .@"error", 525 => unreachable, 526 527 .undef => unreachable, 528 529 .zero, 530 .bool_false, 531 => return BigIntMutable.init(&space.limbs, 0).toConst(), 532 533 .bool_true => return BigIntMutable.init(&space.limbs, 1).toConst(), 534 535 .int_u64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_u64).?.int).toConst(), 536 .int_i64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_i64).?.int).toConst(), 537 .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt(), 538 .int_big_negative => return self.cast(Payload.IntBigPositive).?.asBigInt(), 539 } 540 } 541 542 /// Asserts the value is an integer and it fits in a u64 543 pub fn toUnsignedInt(self: Value) u64 { 544 switch (self.tag()) { 545 .ty, 546 .int_type, 547 .u8_type, 548 .i8_type, 549 .u16_type, 550 .i16_type, 551 .u32_type, 552 .i32_type, 553 .u64_type, 554 .i64_type, 555 .usize_type, 556 .isize_type, 557 .c_short_type, 558 .c_ushort_type, 559 .c_int_type, 560 .c_uint_type, 561 .c_long_type, 562 .c_ulong_type, 563 .c_longlong_type, 564 .c_ulonglong_type, 565 .c_longdouble_type, 566 .f16_type, 567 .f32_type, 568 .f64_type, 569 .f128_type, 570 .c_void_type, 571 .bool_type, 572 .void_type, 573 .type_type, 574 .anyerror_type, 575 .comptime_int_type, 576 .comptime_float_type, 577 .noreturn_type, 578 .null_type, 579 .undefined_type, 580 .fn_noreturn_no_args_type, 581 .fn_void_no_args_type, 582 .fn_naked_noreturn_no_args_type, 583 .fn_ccc_void_no_args_type, 584 .single_const_pointer_to_comptime_int_type, 585 .const_slice_u8_type, 586 .enum_literal_type, 587 .anyframe_type, 588 .null_value, 589 .function, 590 .variable, 591 .ref_val, 592 .decl_ref, 593 .elem_ptr, 594 .bytes, 595 .repeated, 596 .float_16, 597 .float_32, 598 .float_64, 599 .float_128, 600 .void_value, 601 .unreachable_value, 602 .empty_array, 603 .enum_literal, 604 .error_set, 605 .@"error", 606 => unreachable, 607 608 .undef => unreachable, 609 610 .zero, 611 .bool_false, 612 => return 0, 613 614 .bool_true => return 1, 615 616 .int_u64 => return self.cast(Payload.Int_u64).?.int, 617 .int_i64 => return @intCast(u64, self.cast(Payload.Int_i64).?.int), 618 .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(u64) catch unreachable, 619 .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().to(u64) catch unreachable, 620 } 621 } 622 623 /// Asserts the value is an integer and it fits in a i64 624 pub fn toSignedInt(self: Value) i64 { 625 switch (self.tag()) { 626 .ty, 627 .int_type, 628 .u8_type, 629 .i8_type, 630 .u16_type, 631 .i16_type, 632 .u32_type, 633 .i32_type, 634 .u64_type, 635 .i64_type, 636 .usize_type, 637 .isize_type, 638 .c_short_type, 639 .c_ushort_type, 640 .c_int_type, 641 .c_uint_type, 642 .c_long_type, 643 .c_ulong_type, 644 .c_longlong_type, 645 .c_ulonglong_type, 646 .c_longdouble_type, 647 .f16_type, 648 .f32_type, 649 .f64_type, 650 .f128_type, 651 .c_void_type, 652 .bool_type, 653 .void_type, 654 .type_type, 655 .anyerror_type, 656 .comptime_int_type, 657 .comptime_float_type, 658 .noreturn_type, 659 .null_type, 660 .undefined_type, 661 .fn_noreturn_no_args_type, 662 .fn_void_no_args_type, 663 .fn_naked_noreturn_no_args_type, 664 .fn_ccc_void_no_args_type, 665 .single_const_pointer_to_comptime_int_type, 666 .const_slice_u8_type, 667 .enum_literal_type, 668 .anyframe_type, 669 .null_value, 670 .function, 671 .variable, 672 .ref_val, 673 .decl_ref, 674 .elem_ptr, 675 .bytes, 676 .repeated, 677 .float_16, 678 .float_32, 679 .float_64, 680 .float_128, 681 .void_value, 682 .unreachable_value, 683 .empty_array, 684 .enum_literal, 685 .error_set, 686 .@"error", 687 => unreachable, 688 689 .undef => unreachable, 690 691 .zero, 692 .bool_false, 693 => return 0, 694 695 .bool_true => return 1, 696 697 .int_u64 => return @intCast(i64, self.cast(Payload.Int_u64).?.int), 698 .int_i64 => return self.cast(Payload.Int_i64).?.int, 699 .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(i64) catch unreachable, 700 .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().to(i64) catch unreachable, 701 } 702 } 703 704 pub fn toBool(self: Value) bool { 705 return switch (self.tag()) { 706 .bool_true => true, 707 .bool_false, .zero => false, 708 else => unreachable, 709 }; 710 } 711 712 /// Asserts that the value is a float or an integer. 713 pub fn toFloat(self: Value, comptime T: type) T { 714 return switch (self.tag()) { 715 .float_16 => @panic("TODO soft float"), 716 .float_32 => @floatCast(T, self.cast(Payload.Float_32).?.val), 717 .float_64 => @floatCast(T, self.cast(Payload.Float_64).?.val), 718 .float_128 => @floatCast(T, self.cast(Payload.Float_128).?.val), 719 720 .zero => 0, 721 .int_u64 => @intToFloat(T, self.cast(Payload.Int_u64).?.int), 722 .int_i64 => @intToFloat(T, self.cast(Payload.Int_i64).?.int), 723 724 .int_big_positive, .int_big_negative => @panic("big int to f128"), 725 else => unreachable, 726 }; 727 } 728 729 /// Asserts the value is an integer and not undefined. 730 /// Returns the number of bits the value requires to represent stored in twos complement form. 731 pub fn intBitCountTwosComp(self: Value) usize { 732 switch (self.tag()) { 733 .ty, 734 .int_type, 735 .u8_type, 736 .i8_type, 737 .u16_type, 738 .i16_type, 739 .u32_type, 740 .i32_type, 741 .u64_type, 742 .i64_type, 743 .usize_type, 744 .isize_type, 745 .c_short_type, 746 .c_ushort_type, 747 .c_int_type, 748 .c_uint_type, 749 .c_long_type, 750 .c_ulong_type, 751 .c_longlong_type, 752 .c_ulonglong_type, 753 .c_longdouble_type, 754 .f16_type, 755 .f32_type, 756 .f64_type, 757 .f128_type, 758 .c_void_type, 759 .bool_type, 760 .void_type, 761 .type_type, 762 .anyerror_type, 763 .comptime_int_type, 764 .comptime_float_type, 765 .noreturn_type, 766 .null_type, 767 .undefined_type, 768 .fn_noreturn_no_args_type, 769 .fn_void_no_args_type, 770 .fn_naked_noreturn_no_args_type, 771 .fn_ccc_void_no_args_type, 772 .single_const_pointer_to_comptime_int_type, 773 .const_slice_u8_type, 774 .enum_literal_type, 775 .anyframe_type, 776 .null_value, 777 .function, 778 .variable, 779 .ref_val, 780 .decl_ref, 781 .elem_ptr, 782 .bytes, 783 .undef, 784 .repeated, 785 .float_16, 786 .float_32, 787 .float_64, 788 .float_128, 789 .void_value, 790 .unreachable_value, 791 .empty_array, 792 .enum_literal, 793 .error_set, 794 .@"error", 795 => unreachable, 796 797 .zero, 798 .bool_false, 799 => return 0, 800 801 .bool_true => return 1, 802 803 .int_u64 => { 804 const x = self.cast(Payload.Int_u64).?.int; 805 if (x == 0) return 0; 806 return std.math.log2(x) + 1; 807 }, 808 .int_i64 => { 809 @panic("TODO implement i64 intBitCountTwosComp"); 810 }, 811 .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().bitCountTwosComp(), 812 .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().bitCountTwosComp(), 813 } 814 } 815 816 /// Asserts the value is an integer, and the destination type is ComptimeInt or Int. 817 pub fn intFitsInType(self: Value, ty: Type, target: Target) bool { 818 switch (self.tag()) { 819 .ty, 820 .int_type, 821 .u8_type, 822 .i8_type, 823 .u16_type, 824 .i16_type, 825 .u32_type, 826 .i32_type, 827 .u64_type, 828 .i64_type, 829 .usize_type, 830 .isize_type, 831 .c_short_type, 832 .c_ushort_type, 833 .c_int_type, 834 .c_uint_type, 835 .c_long_type, 836 .c_ulong_type, 837 .c_longlong_type, 838 .c_ulonglong_type, 839 .c_longdouble_type, 840 .f16_type, 841 .f32_type, 842 .f64_type, 843 .f128_type, 844 .c_void_type, 845 .bool_type, 846 .void_type, 847 .type_type, 848 .anyerror_type, 849 .comptime_int_type, 850 .comptime_float_type, 851 .noreturn_type, 852 .null_type, 853 .undefined_type, 854 .fn_noreturn_no_args_type, 855 .fn_void_no_args_type, 856 .fn_naked_noreturn_no_args_type, 857 .fn_ccc_void_no_args_type, 858 .single_const_pointer_to_comptime_int_type, 859 .const_slice_u8_type, 860 .enum_literal_type, 861 .anyframe_type, 862 .null_value, 863 .function, 864 .variable, 865 .ref_val, 866 .decl_ref, 867 .elem_ptr, 868 .bytes, 869 .repeated, 870 .float_16, 871 .float_32, 872 .float_64, 873 .float_128, 874 .void_value, 875 .unreachable_value, 876 .empty_array, 877 .enum_literal, 878 .error_set, 879 .@"error", 880 => unreachable, 881 882 .zero, 883 .undef, 884 .bool_false, 885 => return true, 886 887 .bool_true => { 888 const info = ty.intInfo(target); 889 if (info.signed) { 890 return info.bits >= 2; 891 } else { 892 return info.bits >= 1; 893 } 894 }, 895 896 .int_u64 => switch (ty.zigTypeTag()) { 897 .Int => { 898 const x = self.cast(Payload.Int_u64).?.int; 899 if (x == 0) return true; 900 const info = ty.intInfo(target); 901 const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signed); 902 return info.bits >= needed_bits; 903 }, 904 .ComptimeInt => return true, 905 else => unreachable, 906 }, 907 .int_i64 => switch (ty.zigTypeTag()) { 908 .Int => { 909 const x = self.cast(Payload.Int_i64).?.int; 910 if (x == 0) return true; 911 const info = ty.intInfo(target); 912 if (!info.signed and x < 0) 913 return false; 914 @panic("TODO implement i64 intFitsInType"); 915 }, 916 .ComptimeInt => return true, 917 else => unreachable, 918 }, 919 .int_big_positive => switch (ty.zigTypeTag()) { 920 .Int => { 921 const info = ty.intInfo(target); 922 return self.cast(Payload.IntBigPositive).?.asBigInt().fitsInTwosComp(info.signed, info.bits); 923 }, 924 .ComptimeInt => return true, 925 else => unreachable, 926 }, 927 .int_big_negative => switch (ty.zigTypeTag()) { 928 .Int => { 929 const info = ty.intInfo(target); 930 return self.cast(Payload.IntBigNegative).?.asBigInt().fitsInTwosComp(info.signed, info.bits); 931 }, 932 .ComptimeInt => return true, 933 else => unreachable, 934 }, 935 } 936 } 937 938 /// Converts an integer or a float to a float. 939 /// Returns `error.Overflow` if the value does not fit in the new type. 940 pub fn floatCast(self: Value, allocator: *Allocator, ty: Type, target: Target) !Value { 941 const dest_bit_count = switch (ty.tag()) { 942 .comptime_float => 128, 943 else => ty.floatBits(target), 944 }; 945 switch (dest_bit_count) { 946 16, 32, 64, 128 => {}, 947 else => std.debug.panic("TODO float cast bit count {}\n", .{dest_bit_count}), 948 } 949 if (ty.isInt()) { 950 @panic("TODO int to float"); 951 } 952 953 switch (dest_bit_count) { 954 16 => { 955 @panic("TODO soft float"); 956 // var res_payload = Value.Payload.Float_16{.val = self.toFloat(f16)}; 957 // if (!self.eql(Value.initPayload(&res_payload.base))) 958 // return error.Overflow; 959 // return Value.initPayload(&res_payload.base).copy(allocator); 960 }, 961 32 => { 962 var res_payload = Value.Payload.Float_32{ .val = self.toFloat(f32) }; 963 if (!self.eql(Value.initPayload(&res_payload.base))) 964 return error.Overflow; 965 return Value.initPayload(&res_payload.base).copy(allocator); 966 }, 967 64 => { 968 var res_payload = Value.Payload.Float_64{ .val = self.toFloat(f64) }; 969 if (!self.eql(Value.initPayload(&res_payload.base))) 970 return error.Overflow; 971 return Value.initPayload(&res_payload.base).copy(allocator); 972 }, 973 128 => { 974 const float_payload = try allocator.create(Value.Payload.Float_128); 975 float_payload.* = .{ .val = self.toFloat(f128) }; 976 return Value.initPayload(&float_payload.base); 977 }, 978 else => unreachable, 979 } 980 } 981 982 /// Asserts the value is a float 983 pub fn floatHasFraction(self: Value) bool { 984 return switch (self.tag()) { 985 .ty, 986 .int_type, 987 .u8_type, 988 .i8_type, 989 .u16_type, 990 .i16_type, 991 .u32_type, 992 .i32_type, 993 .u64_type, 994 .i64_type, 995 .usize_type, 996 .isize_type, 997 .c_short_type, 998 .c_ushort_type, 999 .c_int_type, 1000 .c_uint_type, 1001 .c_long_type, 1002 .c_ulong_type, 1003 .c_longlong_type, 1004 .c_ulonglong_type, 1005 .c_longdouble_type, 1006 .f16_type, 1007 .f32_type, 1008 .f64_type, 1009 .f128_type, 1010 .c_void_type, 1011 .bool_type, 1012 .void_type, 1013 .type_type, 1014 .anyerror_type, 1015 .comptime_int_type, 1016 .comptime_float_type, 1017 .noreturn_type, 1018 .null_type, 1019 .undefined_type, 1020 .fn_noreturn_no_args_type, 1021 .fn_void_no_args_type, 1022 .fn_naked_noreturn_no_args_type, 1023 .fn_ccc_void_no_args_type, 1024 .single_const_pointer_to_comptime_int_type, 1025 .const_slice_u8_type, 1026 .enum_literal_type, 1027 .anyframe_type, 1028 .bool_true, 1029 .bool_false, 1030 .null_value, 1031 .function, 1032 .variable, 1033 .ref_val, 1034 .decl_ref, 1035 .elem_ptr, 1036 .bytes, 1037 .repeated, 1038 .undef, 1039 .int_u64, 1040 .int_i64, 1041 .int_big_positive, 1042 .int_big_negative, 1043 .empty_array, 1044 .void_value, 1045 .unreachable_value, 1046 .enum_literal, 1047 .error_set, 1048 .@"error", 1049 => unreachable, 1050 1051 .zero => false, 1052 1053 .float_16 => @rem(self.cast(Payload.Float_16).?.val, 1) != 0, 1054 .float_32 => @rem(self.cast(Payload.Float_32).?.val, 1) != 0, 1055 .float_64 => @rem(self.cast(Payload.Float_64).?.val, 1) != 0, 1056 // .float_128 => @rem(self.cast(Payload.Float_128).?.val, 1) != 0, 1057 .float_128 => @panic("TODO lld: error: undefined symbol: fmodl"), 1058 }; 1059 } 1060 1061 pub fn orderAgainstZero(lhs: Value) std.math.Order { 1062 return switch (lhs.tag()) { 1063 .ty, 1064 .int_type, 1065 .u8_type, 1066 .i8_type, 1067 .u16_type, 1068 .i16_type, 1069 .u32_type, 1070 .i32_type, 1071 .u64_type, 1072 .i64_type, 1073 .usize_type, 1074 .isize_type, 1075 .c_short_type, 1076 .c_ushort_type, 1077 .c_int_type, 1078 .c_uint_type, 1079 .c_long_type, 1080 .c_ulong_type, 1081 .c_longlong_type, 1082 .c_ulonglong_type, 1083 .c_longdouble_type, 1084 .f16_type, 1085 .f32_type, 1086 .f64_type, 1087 .f128_type, 1088 .c_void_type, 1089 .bool_type, 1090 .void_type, 1091 .type_type, 1092 .anyerror_type, 1093 .comptime_int_type, 1094 .comptime_float_type, 1095 .noreturn_type, 1096 .null_type, 1097 .undefined_type, 1098 .fn_noreturn_no_args_type, 1099 .fn_void_no_args_type, 1100 .fn_naked_noreturn_no_args_type, 1101 .fn_ccc_void_no_args_type, 1102 .single_const_pointer_to_comptime_int_type, 1103 .const_slice_u8_type, 1104 .enum_literal_type, 1105 .anyframe_type, 1106 .null_value, 1107 .function, 1108 .variable, 1109 .ref_val, 1110 .decl_ref, 1111 .elem_ptr, 1112 .bytes, 1113 .repeated, 1114 .undef, 1115 .void_value, 1116 .unreachable_value, 1117 .empty_array, 1118 .enum_literal, 1119 .error_set, 1120 .@"error", 1121 => unreachable, 1122 1123 .zero, 1124 .bool_false, 1125 => .eq, 1126 1127 .bool_true => .gt, 1128 1129 .int_u64 => std.math.order(lhs.cast(Payload.Int_u64).?.int, 0), 1130 .int_i64 => std.math.order(lhs.cast(Payload.Int_i64).?.int, 0), 1131 .int_big_positive => lhs.cast(Payload.IntBigPositive).?.asBigInt().orderAgainstScalar(0), 1132 .int_big_negative => lhs.cast(Payload.IntBigNegative).?.asBigInt().orderAgainstScalar(0), 1133 1134 .float_16 => std.math.order(lhs.cast(Payload.Float_16).?.val, 0), 1135 .float_32 => std.math.order(lhs.cast(Payload.Float_32).?.val, 0), 1136 .float_64 => std.math.order(lhs.cast(Payload.Float_64).?.val, 0), 1137 .float_128 => std.math.order(lhs.cast(Payload.Float_128).?.val, 0), 1138 }; 1139 } 1140 1141 /// Asserts the value is comparable. 1142 pub fn order(lhs: Value, rhs: Value) std.math.Order { 1143 const lhs_tag = lhs.tag(); 1144 const rhs_tag = rhs.tag(); 1145 const lhs_is_zero = lhs_tag == .zero; 1146 const rhs_is_zero = rhs_tag == .zero; 1147 if (lhs_is_zero) return rhs.orderAgainstZero().invert(); 1148 if (rhs_is_zero) return lhs.orderAgainstZero(); 1149 1150 const lhs_float = lhs.isFloat(); 1151 const rhs_float = rhs.isFloat(); 1152 if (lhs_float and rhs_float) { 1153 if (lhs_tag == rhs_tag) { 1154 return switch (lhs.tag()) { 1155 .float_16 => return std.math.order(lhs.cast(Payload.Float_16).?.val, rhs.cast(Payload.Float_16).?.val), 1156 .float_32 => return std.math.order(lhs.cast(Payload.Float_32).?.val, rhs.cast(Payload.Float_32).?.val), 1157 .float_64 => return std.math.order(lhs.cast(Payload.Float_64).?.val, rhs.cast(Payload.Float_64).?.val), 1158 .float_128 => return std.math.order(lhs.cast(Payload.Float_128).?.val, rhs.cast(Payload.Float_128).?.val), 1159 else => unreachable, 1160 }; 1161 } 1162 } 1163 if (lhs_float or rhs_float) { 1164 const lhs_f128 = lhs.toFloat(f128); 1165 const rhs_f128 = rhs.toFloat(f128); 1166 return std.math.order(lhs_f128, rhs_f128); 1167 } 1168 1169 var lhs_bigint_space: BigIntSpace = undefined; 1170 var rhs_bigint_space: BigIntSpace = undefined; 1171 const lhs_bigint = lhs.toBigInt(&lhs_bigint_space); 1172 const rhs_bigint = rhs.toBigInt(&rhs_bigint_space); 1173 return lhs_bigint.order(rhs_bigint); 1174 } 1175 1176 /// Asserts the value is comparable. 1177 pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value) bool { 1178 return order(lhs, rhs).compare(op); 1179 } 1180 1181 /// Asserts the value is comparable. 1182 pub fn compareWithZero(lhs: Value, op: std.math.CompareOperator) bool { 1183 return orderAgainstZero(lhs).compare(op); 1184 } 1185 1186 pub fn eql(a: Value, b: Value) bool { 1187 if (a.tag() == b.tag() and a.tag() == .enum_literal) { 1188 const a_name = @fieldParentPtr(Payload.Bytes, "base", a.ptr_otherwise).data; 1189 const b_name = @fieldParentPtr(Payload.Bytes, "base", b.ptr_otherwise).data; 1190 return std.mem.eql(u8, a_name, b_name); 1191 } 1192 // TODO non numerical comparisons 1193 return compare(a, .eq, b); 1194 } 1195 1196 /// Asserts the value is a pointer and dereferences it. 1197 /// Returns error.AnalysisFail if the pointer points to a Decl that failed semantic analysis. 1198 pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value { 1199 return switch (self.tag()) { 1200 .ty, 1201 .int_type, 1202 .u8_type, 1203 .i8_type, 1204 .u16_type, 1205 .i16_type, 1206 .u32_type, 1207 .i32_type, 1208 .u64_type, 1209 .i64_type, 1210 .usize_type, 1211 .isize_type, 1212 .c_short_type, 1213 .c_ushort_type, 1214 .c_int_type, 1215 .c_uint_type, 1216 .c_long_type, 1217 .c_ulong_type, 1218 .c_longlong_type, 1219 .c_ulonglong_type, 1220 .c_longdouble_type, 1221 .f16_type, 1222 .f32_type, 1223 .f64_type, 1224 .f128_type, 1225 .c_void_type, 1226 .bool_type, 1227 .void_type, 1228 .type_type, 1229 .anyerror_type, 1230 .comptime_int_type, 1231 .comptime_float_type, 1232 .noreturn_type, 1233 .null_type, 1234 .undefined_type, 1235 .fn_noreturn_no_args_type, 1236 .fn_void_no_args_type, 1237 .fn_naked_noreturn_no_args_type, 1238 .fn_ccc_void_no_args_type, 1239 .single_const_pointer_to_comptime_int_type, 1240 .const_slice_u8_type, 1241 .enum_literal_type, 1242 .anyframe_type, 1243 .zero, 1244 .bool_true, 1245 .bool_false, 1246 .null_value, 1247 .function, 1248 .variable, 1249 .int_u64, 1250 .int_i64, 1251 .int_big_positive, 1252 .int_big_negative, 1253 .bytes, 1254 .undef, 1255 .repeated, 1256 .float_16, 1257 .float_32, 1258 .float_64, 1259 .float_128, 1260 .void_value, 1261 .unreachable_value, 1262 .empty_array, 1263 .enum_literal, 1264 .error_set, 1265 .@"error", 1266 => unreachable, 1267 1268 .ref_val => self.cast(Payload.RefVal).?.val, 1269 .decl_ref => self.cast(Payload.DeclRef).?.decl.value(), 1270 .elem_ptr => { 1271 const elem_ptr = self.cast(Payload.ElemPtr).?; 1272 const array_val = try elem_ptr.array_ptr.pointerDeref(allocator); 1273 return array_val.elemValue(allocator, elem_ptr.index); 1274 }, 1275 }; 1276 } 1277 1278 /// Asserts the value is a single-item pointer to an array, or an array, 1279 /// or an unknown-length pointer, and returns the element value at the index. 1280 pub fn elemValue(self: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value { 1281 switch (self.tag()) { 1282 .ty, 1283 .int_type, 1284 .u8_type, 1285 .i8_type, 1286 .u16_type, 1287 .i16_type, 1288 .u32_type, 1289 .i32_type, 1290 .u64_type, 1291 .i64_type, 1292 .usize_type, 1293 .isize_type, 1294 .c_short_type, 1295 .c_ushort_type, 1296 .c_int_type, 1297 .c_uint_type, 1298 .c_long_type, 1299 .c_ulong_type, 1300 .c_longlong_type, 1301 .c_ulonglong_type, 1302 .c_longdouble_type, 1303 .f16_type, 1304 .f32_type, 1305 .f64_type, 1306 .f128_type, 1307 .c_void_type, 1308 .bool_type, 1309 .void_type, 1310 .type_type, 1311 .anyerror_type, 1312 .comptime_int_type, 1313 .comptime_float_type, 1314 .noreturn_type, 1315 .null_type, 1316 .undefined_type, 1317 .fn_noreturn_no_args_type, 1318 .fn_void_no_args_type, 1319 .fn_naked_noreturn_no_args_type, 1320 .fn_ccc_void_no_args_type, 1321 .single_const_pointer_to_comptime_int_type, 1322 .const_slice_u8_type, 1323 .enum_literal_type, 1324 .anyframe_type, 1325 .zero, 1326 .bool_true, 1327 .bool_false, 1328 .null_value, 1329 .function, 1330 .variable, 1331 .int_u64, 1332 .int_i64, 1333 .int_big_positive, 1334 .int_big_negative, 1335 .undef, 1336 .elem_ptr, 1337 .ref_val, 1338 .decl_ref, 1339 .float_16, 1340 .float_32, 1341 .float_64, 1342 .float_128, 1343 .void_value, 1344 .unreachable_value, 1345 .enum_literal, 1346 .error_set, 1347 .@"error", 1348 => unreachable, 1349 1350 .empty_array => unreachable, // out of bounds array index 1351 1352 .bytes => { 1353 const int_payload = try allocator.create(Payload.Int_u64); 1354 int_payload.* = .{ .int = self.cast(Payload.Bytes).?.data[index] }; 1355 return Value.initPayload(&int_payload.base); 1356 }, 1357 1358 // No matter the index; all the elements are the same! 1359 .repeated => return self.cast(Payload.Repeated).?.val, 1360 } 1361 } 1362 1363 /// Returns a pointer to the element value at the index. 1364 pub fn elemPtr(self: Value, allocator: *Allocator, index: usize) !Value { 1365 const payload = try allocator.create(Payload.ElemPtr); 1366 if (self.cast(Payload.ElemPtr)) |elem_ptr| { 1367 payload.* = .{ .array_ptr = elem_ptr.array_ptr, .index = elem_ptr.index + index }; 1368 } else { 1369 payload.* = .{ .array_ptr = self, .index = index }; 1370 } 1371 return Value.initPayload(&payload.base); 1372 } 1373 1374 pub fn isUndef(self: Value) bool { 1375 return self.tag() == .undef; 1376 } 1377 1378 /// Valid for all types. Asserts the value is not undefined and not unreachable. 1379 pub fn isNull(self: Value) bool { 1380 return switch (self.tag()) { 1381 .ty, 1382 .int_type, 1383 .u8_type, 1384 .i8_type, 1385 .u16_type, 1386 .i16_type, 1387 .u32_type, 1388 .i32_type, 1389 .u64_type, 1390 .i64_type, 1391 .usize_type, 1392 .isize_type, 1393 .c_short_type, 1394 .c_ushort_type, 1395 .c_int_type, 1396 .c_uint_type, 1397 .c_long_type, 1398 .c_ulong_type, 1399 .c_longlong_type, 1400 .c_ulonglong_type, 1401 .c_longdouble_type, 1402 .f16_type, 1403 .f32_type, 1404 .f64_type, 1405 .f128_type, 1406 .c_void_type, 1407 .bool_type, 1408 .void_type, 1409 .type_type, 1410 .anyerror_type, 1411 .comptime_int_type, 1412 .comptime_float_type, 1413 .noreturn_type, 1414 .null_type, 1415 .undefined_type, 1416 .fn_noreturn_no_args_type, 1417 .fn_void_no_args_type, 1418 .fn_naked_noreturn_no_args_type, 1419 .fn_ccc_void_no_args_type, 1420 .single_const_pointer_to_comptime_int_type, 1421 .const_slice_u8_type, 1422 .enum_literal_type, 1423 .anyframe_type, 1424 .zero, 1425 .empty_array, 1426 .bool_true, 1427 .bool_false, 1428 .function, 1429 .variable, 1430 .int_u64, 1431 .int_i64, 1432 .int_big_positive, 1433 .int_big_negative, 1434 .ref_val, 1435 .decl_ref, 1436 .elem_ptr, 1437 .bytes, 1438 .repeated, 1439 .float_16, 1440 .float_32, 1441 .float_64, 1442 .float_128, 1443 .void_value, 1444 .enum_literal, 1445 .error_set, 1446 .@"error", 1447 => false, 1448 1449 .undef => unreachable, 1450 .unreachable_value => unreachable, 1451 .null_value => true, 1452 }; 1453 } 1454 1455 /// Valid for all types. Asserts the value is not undefined. 1456 pub fn isFloat(self: Value) bool { 1457 return switch (self.tag()) { 1458 .undef => unreachable, 1459 1460 .float_16, 1461 .float_32, 1462 .float_64, 1463 .float_128, 1464 => true, 1465 else => false, 1466 }; 1467 } 1468 1469 /// This type is not copyable since it may contain pointers to its inner data. 1470 pub const Payload = struct { 1471 tag: Tag, 1472 1473 pub const Int_u64 = struct { 1474 base: Payload = Payload{ .tag = .int_u64 }, 1475 int: u64, 1476 }; 1477 1478 pub const Int_i64 = struct { 1479 base: Payload = Payload{ .tag = .int_i64 }, 1480 int: i64, 1481 }; 1482 1483 pub const IntBigPositive = struct { 1484 base: Payload = Payload{ .tag = .int_big_positive }, 1485 limbs: []const std.math.big.Limb, 1486 1487 pub fn asBigInt(self: IntBigPositive) BigIntConst { 1488 return BigIntConst{ .limbs = self.limbs, .positive = true }; 1489 } 1490 }; 1491 1492 pub const IntBigNegative = struct { 1493 base: Payload = Payload{ .tag = .int_big_negative }, 1494 limbs: []const std.math.big.Limb, 1495 1496 pub fn asBigInt(self: IntBigNegative) BigIntConst { 1497 return BigIntConst{ .limbs = self.limbs, .positive = false }; 1498 } 1499 }; 1500 1501 pub const Function = struct { 1502 base: Payload = Payload{ .tag = .function }, 1503 func: *Module.Fn, 1504 }; 1505 1506 pub const Variable = struct { 1507 base: Payload = Payload{ .tag = .variable }, 1508 variable: *Module.Var, 1509 }; 1510 1511 pub const ArraySentinel0_u8_Type = struct { 1512 base: Payload = Payload{ .tag = .array_sentinel_0_u8_type }, 1513 len: u64, 1514 }; 1515 1516 /// Represents a pointer to another immutable value. 1517 pub const RefVal = struct { 1518 base: Payload = Payload{ .tag = .ref_val }, 1519 val: Value, 1520 }; 1521 1522 /// Represents a pointer to a decl, not the value of the decl. 1523 pub const DeclRef = struct { 1524 base: Payload = Payload{ .tag = .decl_ref }, 1525 decl: *Module.Decl, 1526 }; 1527 1528 pub const ElemPtr = struct { 1529 base: Payload = Payload{ .tag = .elem_ptr }, 1530 array_ptr: Value, 1531 index: usize, 1532 }; 1533 1534 pub const Bytes = struct { 1535 base: Payload = Payload{ .tag = .bytes }, 1536 data: []const u8, 1537 }; 1538 1539 pub const Ty = struct { 1540 base: Payload = Payload{ .tag = .ty }, 1541 ty: Type, 1542 }; 1543 1544 pub const IntType = struct { 1545 base: Payload = Payload{ .tag = .int_type }, 1546 bits: u16, 1547 signed: bool, 1548 }; 1549 1550 pub const Repeated = struct { 1551 base: Payload = Payload{ .tag = .ty }, 1552 /// This value is repeated some number of times. The amount of times to repeat 1553 /// is stored externally. 1554 val: Value, 1555 }; 1556 1557 pub const Float_16 = struct { 1558 base: Payload = .{ .tag = .float_16 }, 1559 val: f16, 1560 }; 1561 1562 pub const Float_32 = struct { 1563 base: Payload = .{ .tag = .float_32 }, 1564 val: f32, 1565 }; 1566 1567 pub const Float_64 = struct { 1568 base: Payload = .{ .tag = .float_64 }, 1569 val: f64, 1570 }; 1571 1572 pub const Float_128 = struct { 1573 base: Payload = .{ .tag = .float_128 }, 1574 val: f128, 1575 }; 1576 1577 pub const ErrorSet = struct { 1578 base: Payload = .{ .tag = .error_set }, 1579 1580 // TODO revisit this when we have the concept of the error tag type 1581 fields: std.StringHashMapUnmanaged(u16), 1582 }; 1583 1584 pub const Error = struct { 1585 base: Payload = .{ .tag = .@"error" }, 1586 1587 // TODO revisit this when we have the concept of the error tag type 1588 /// `name` is owned by `Module` and will be valid for the entire 1589 /// duration of the compilation. 1590 name: []const u8, 1591 value: u16, 1592 }; 1593 }; 1594 1595 /// Big enough to fit any non-BigInt value 1596 pub const BigIntSpace = struct { 1597 /// The +1 is headroom so that operations such as incrementing once or decrementing once 1598 /// are possible without using an allocator. 1599 limbs: [(@sizeOf(u64) / @sizeOf(std.math.big.Limb)) + 1]std.math.big.Limb, 1600 }; 1601 };