| author | |
| committer | |
| log | ee6d161658572b76eb31d23be33043f63be4f556 |
| tree | 078a9377345cb661d277516ae79713dee297279d |
| parent | 9c9f440794d6c700dbbcf7bc410d954c694a36c1 |
| signature | Commit is signed but in an unrecognized format. |
these pointers get invalidated after appends to InternPool, so they
should store `Store.Slice(T)` instead. this introduces a memory leak
since there is a genuine use case for using real slices (when the query
is not in InternPool), but the fix for this is more convoluted and will
be done later when some other InternPool organization is done.14 files changed, 373 insertions(+), 301 deletions(-)
CHANGELOG.md+1| ... | ... | @@ -11,6 +11,7 @@ |
| 11 | 11 | - fix: coerce `break` operands and implicit breaks to result type |
| 12 | 12 | - fix: coerce results when `if` expression branches merge |
| 13 | 13 | - fix: ensure if branch results to a runtime value when the condition is not compile-time known |
| 14 | - fix: coerce return value to a runtime value | |
| 14 | 15 | - fix: inferred array type uses item type for items instead of the container type. |
| 15 | 16 | - fix(js): stop printing redundant parenthesis on ternary expressions |
| 16 | 17 |
README.md+2-2| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # Ix |
| 2 | 2 | |
| 3 | Ix (`I`nferable E`x`pression) is a high-level, general purpose programming | |
| 3 | Ix (*I*nferable E*x*pression) is a high-level, general purpose programming | |
| 4 | 4 | language. It features a mix of Rust, Zig, and JavaScript's great points. |
| 5 | 5 | |
| 6 | 6 | For a guide on how to use Ix, see the manual included in the binary |
| ... | ... | @@ -29,6 +29,6 @@ CLI to check spelling mistakes and [`dprint`][dprint] for code formatting. It is |
| 29 | 29 | recommended to setup editor integration with these two tools to prevent pushing |
| 30 | 30 | broken commits. |
| 31 | 31 | |
| 32 | [ci]: https://buildkite.com/paperdave/compiler | |
| 32 | [ci]: https://buildkite.com/paperclover/compiler | |
| 33 | 33 | [typos]: https://github.com/crate-ci/typos |
| 34 | 34 | [dprint]: https://dprint.dev |
ci+16-14| ... | ... | @@ -12,25 +12,27 @@ commit_short=$(echo "$commit" | cut -c -9) |
| 12 | 12 | typos |
| 13 | 13 | dprint check |
| 14 | 14 | |
| 15 | if [ -n "$BUILDKITE" ]; then | |
| 15 | if [ -n "$BUILDKITE" ] || [ "$1" == "all" ]; then | |
| 16 | 16 | # perform the entire build |
| 17 | 17 | ./build all --summary all |
| 18 | 18 | |
| 19 | pushd zig-out/package | |
| 20 | zip -r compiler-$commit.zip * | |
| 21 | buildkite-agent artifact upload compiler-$commit.zip | |
| 22 | popd | |
| 19 | if [ -n "$BUILDKITE" ]; then | |
| 20 | pushd zig-out/package | |
| 21 | zip -r compiler-$commit.zip * | |
| 22 | buildkite-agent artifact upload compiler-$commit.zip | |
| 23 | popd | |
| 23 | 24 | |
| 24 | rm -fr zig-out/site | |
| 25 | mkdir zig-out/site | |
| 26 | cp zig-out/package/ix.html zig-out/site/index.html | |
| 27 | branch="$BUILDKITE_BRANCH" | |
| 28 | if [ "$branch" = "dev" ]; then | |
| 29 | branch=main | |
| 25 | rm -fr zig-out/site | |
| 26 | mkdir zig-out/site | |
| 27 | cp zig-out/package/ix.html zig-out/site/index.html | |
| 28 | branch="$BUILDKITE_BRANCH" | |
| 29 | if [ "$branch" = "dev" ]; then | |
| 30 | branch=main | |
| 31 | fi | |
| 32 | CLOUDFLARE_API_TOKEN="$(buildkite-agent secret get CLOUDFLARE_API_TOKEN)" \ | |
| 33 | CLOUDFLARE_ACCOUNT_ID="$(buildkite-agent secret get CLOUDFLARE_ACCOUNT_ID)" \ | |
| 34 | wrangler pages deploy zig-out/site --branch "$branch" --commit-hash "$commit" --no-bundle --project-name language-manual | |
| 30 | 35 | fi |
| 31 | CLOUDFLARE_API_TOKEN="$(buildkite-agent secret get CLOUDFLARE_API_TOKEN)" \ | |
| 32 | CLOUDFLARE_ACCOUNT_ID="$(buildkite-agent secret get CLOUDFLARE_ACCOUNT_ID)" \ | |
| 33 | wrangler pages deploy zig-out/site --branch "$branch" --commit-hash "$commit" --no-bundle --project-name language-manual | |
| 34 | 36 | else |
| 35 | 37 | # perform only the tests, with a shorter summary |
| 36 | 38 | ./build test --summary new |
doc/language-manual.md+2-2| ... | ... | @@ -179,7 +179,7 @@ it cannot be assigned to a `var` without an explicit type annotation. Since |
| 179 | 179 | float, but a compiler warning will be emitted. |
| 180 | 180 | |
| 181 | 181 | ```lang |
| 182 | var number = 0; // `number` is a `float`, but not explicit | |
| 182 | var number = 0; // `number` is `float`, but not explicit | |
| 183 | 183 | var number: int = 0; // `number` is `int` |
| 184 | 184 | var number: float = 0; // `number` is `float` |
| 185 | 185 | ``` |
| ... | ... | @@ -203,7 +203,7 @@ fn main { |
| 203 | 203 | |
| 204 | 204 | The `return` expression can be used within functions to return early. |
| 205 | 205 | |
| 206 | ```lang:run | |
| 206 | ```lang | |
| 207 | 207 | let print = @extern("console").log; |
| 208 | 208 | |
| 209 | 209 | fn something(a: int) -> bool { |
src/core/Air.Dump.zig+15-14| ... | ... | @@ -52,7 +52,7 @@ pub const State = struct { |
| 52 | 52 | switch (tag) { |
| 53 | 53 | .block => { |
| 54 | 54 | const index_list: Air.IndexList = air.instData(.block, inst); |
| 55 | const insts = index_list.slice(air); | |
| 55 | const insts = index_list.get(air); | |
| 56 | 56 | try s.dumpInstList(w, insts, '{', '}'); |
| 57 | 57 | }, |
| 58 | 58 | .arg => { |
| ... | ... | @@ -127,7 +127,7 @@ pub const State = struct { |
| 127 | 127 | air |
| 128 | 128 | .typeOfIndex(field.base, s.ip) |
| 129 | 129 | .toStructType(s.ip).? |
| 130 | .field_keys[field.field_index] | |
| 130 | .field_keys.at(s.ip, field.field_index) | |
| 131 | 131 | .toSlice(s.ip), |
| 132 | 132 | }); |
| 133 | 133 | try tty.setColor(w, .reset); |
| ... | ... | @@ -149,7 +149,7 @@ pub const State = struct { |
| 149 | 149 | try w.writeAll("("); |
| 150 | 150 | try s.dumpRef(w, call.base); |
| 151 | 151 | try w.writeAll(", "); |
| 152 | try s.dumpRefList(w, call_data.args.slice(air), '[', ']'); | |
| 152 | try s.dumpRefList(w, call_data.args.get(air), '[', ']'); | |
| 153 | 153 | try w.writeAll(")"); |
| 154 | 154 | }, |
| 155 | 155 | .@"if" => { |
| ... | ... | @@ -177,7 +177,7 @@ pub const State = struct { |
| 177 | 177 | try s.dumpValue(w, struct_init.ty.value()); |
| 178 | 178 | try w.writeAll(", {"); |
| 179 | 179 | s.indent += 1; |
| 180 | for (struct_type.field_keys, struct_init.valuesPtr(air)) |key, ref| { | |
| 180 | for (struct_type.field_keys.get(s.ip), struct_init.valuesPtr(air)) |key, ref| { | |
| 181 | 181 | try s.newline(w); |
| 182 | 182 | try w.print("{}: ", .{key.fmt(s.ip)}); |
| 183 | 183 | try s.dumpRef(w, ref); |
| ... | ... | @@ -192,7 +192,7 @@ pub const State = struct { |
| 192 | 192 | |
| 193 | 193 | try w.writeAll("("); |
| 194 | 194 | try s.dumpValue(w, array_type.item_type.value()); |
| 195 | try s.dumpRefList(w, array_init.list.get(air).slice(air), '[', ']'); | |
| 195 | try s.dumpRefList(w, array_init.list.get(air).get(air), '[', ']'); | |
| 196 | 196 | try w.writeAll(")"); |
| 197 | 197 | }, |
| 198 | 198 | .tuple_init => { |
| ... | ... | @@ -203,6 +203,7 @@ pub const State = struct { |
| 203 | 203 | // try s.dumpValue(w, array_type.item_type.value()); |
| 204 | 204 | // try s.dumpRefList(w, array_init.list.get(air).slice(air), '[', ']'); |
| 205 | 205 | // try w.writeAll(")"); |
| 206 | @panic("TODO"); | |
| 206 | 207 | }, |
| 207 | 208 | } |
| 208 | 209 | } |
| ... | ... | @@ -244,7 +245,7 @@ pub const State = struct { |
| 244 | 245 | try tty.setColor(w, .blue); |
| 245 | 246 | try w.writeAll("fn("); |
| 246 | 247 | try tty.setColor(w, .reset); |
| 247 | for (ty.param_types, 0..) |param, i| { | |
| 248 | for (ty.param_types.get(s.ip), 0..) |param, i| { | |
| 248 | 249 | if (i != 0) { |
| 249 | 250 | try tty.setColor(w, .blue); |
| 250 | 251 | try w.writeAll(", "); |
| ... | ... | @@ -322,8 +323,8 @@ pub const State = struct { |
| 322 | 323 | try w.writeAll(" "); |
| 323 | 324 | |
| 324 | 325 | for ( |
| 325 | struct_type.field_keys, | |
| 326 | struct_type.field_types, | |
| 326 | struct_type.field_keys.get(s.ip), | |
| 327 | struct_type.field_types.get(s.ip), | |
| 327 | 328 | 0.., |
| 328 | 329 | ) |key, field_type, i| { |
| 329 | 330 | if (i != 0) |
| ... | ... | @@ -352,8 +353,8 @@ pub const State = struct { |
| 352 | 353 | try w.writeAll(" "); |
| 353 | 354 | |
| 354 | 355 | for ( |
| 355 | struct_value.ty.toStructType(s.ip).?.field_keys, | |
| 356 | struct_value.field_values, | |
| 356 | struct_value.ty.toStructType(s.ip).?.field_keys.get(s.ip), | |
| 357 | struct_value.field_values.get(s.ip), | |
| 357 | 358 | 0.., |
| 358 | 359 | ) |key, value, i| { |
| 359 | 360 | if (i != 0) |
| ... | ... | @@ -385,7 +386,7 @@ pub const State = struct { |
| 385 | 386 | try tty.setColor(w, .reset); |
| 386 | 387 | try w.writeAll("["); |
| 387 | 388 | |
| 388 | for (array_value.items, 0..) |value, i| { | |
| 389 | for (array_value.items.get(s.ip), 0..) |value, i| { | |
| 389 | 390 | if (i != 0) |
| 390 | 391 | try w.writeAll(", "); |
| 391 | 392 | try s.dumpValue(w, value); |
| ... | ... | @@ -398,7 +399,7 @@ pub const State = struct { |
| 398 | 399 | }, |
| 399 | 400 | .external_value => |external_value| { |
| 400 | 401 | try w.writeAll("external '"); |
| 401 | for (external_value.key, 0..) |part, i| { | |
| 402 | for (external_value.key.get(s.ip), 0..) |part, i| { | |
| 402 | 403 | if (i != 0) try w.writeAll("."); |
| 403 | 404 | try w.writeAll(part.toSlice(s.ip)); |
| 404 | 405 | } |
| ... | ... | @@ -406,7 +407,7 @@ pub const State = struct { |
| 406 | 407 | }, |
| 407 | 408 | .tuple_type => |tuple_type| { |
| 408 | 409 | try w.writeAll("("); |
| 409 | for (tuple_type.items, 0..) |item, i| { | |
| 410 | for (tuple_type.items.get(s.ip), 0..) |item, i| { | |
| 410 | 411 | if (i != 0) try w.writeAll(", "); |
| 411 | 412 | try s.dumpValue(w, item.value()); |
| 412 | 413 | } |
| ... | ... | @@ -414,7 +415,7 @@ pub const State = struct { |
| 414 | 415 | }, |
| 415 | 416 | .tuple_value => |tuple_value| { |
| 416 | 417 | try w.writeAll("("); |
| 417 | for (tuple_value.items, 0..) |item, i| { | |
| 418 | for (tuple_value.items.get(s.ip), 0..) |item, i| { | |
| 418 | 419 | if (i != 0) try w.writeAll(", "); |
| 419 | 420 | try s.dumpValue(w, item); |
| 420 | 421 | } |
src/core/Air.zig+6-21| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | insts: Inst.List.Slice, |
| 2 | extra: ExtraStore = .{}, | |
| 2 | extra: ExtraStore, | |
| 3 | 3 | |
| 4 | 4 | pub const ExtraStore = dod.ExtraStore(.air, .@"const"); |
| 5 | 5 | pub const EncodedData = dod.EncodedData(Inst.Tag, u64); |
| ... | ... | @@ -201,23 +201,8 @@ pub const Flags = packed struct { |
| 201 | 201 | }; |
| 202 | 202 | }; |
| 203 | 203 | |
| 204 | pub const IndexList = struct { | |
| 205 | start: u32, | |
| 206 | len: u32, | |
| 207 | ||
| 208 | pub fn slice(self: IndexList, air: *const Air) []const Inst.Index { | |
| 209 | return @ptrCast(air.extra.list.items[self.start..][0..self.len]); | |
| 210 | } | |
| 211 | }; | |
| 212 | ||
| 213 | pub const RefList = struct { | |
| 214 | start: u32, | |
| 215 | len: u32, | |
| 216 | ||
| 217 | pub fn slice(self: RefList, air: *const Air) []const Inst.Ref { | |
| 218 | return @ptrCast(air.extra.list.items[self.start..][0..self.len]); | |
| 219 | } | |
| 220 | }; | |
| 204 | pub const IndexList = ExtraStore.Slice(Air.Inst.Index); | |
| 205 | pub const RefList = ExtraStore.Slice(Air.Inst.Ref); | |
| 221 | 206 | |
| 222 | 207 | pub const Break = struct { |
| 223 | 208 | block: Inst.Index, |
| ... | ... | @@ -383,7 +368,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In |
| 383 | 368 | // TODO: taking the last instruction is likely wrong. |
| 384 | 369 | // The last instruction is going to be a .break and be of type .never |
| 385 | 370 | .block => { |
| 386 | const items = air.instData(.block, index).slice(air); | |
| 371 | const items = air.instData(.block, index).get(air); | |
| 387 | 372 | assert(items.len > 0); // empty blocks should always be `Value.void` |
| 388 | 373 | return air.typeOfIndex(items[items.len - 1], ip); |
| 389 | 374 | }, |
| ... | ... | @@ -402,7 +387,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In |
| 402 | 387 | const inst = air.instData(.field_struct, index); |
| 403 | 388 | const base_type = air.typeOfIndex(inst.base, ip) |
| 404 | 389 | .toStructType(ip) orelse unreachable; // field_struct demands struct type |
| 405 | return base_type.field_types[inst.field_index]; | |
| 390 | return base_type.field_types.at(ip, inst.field_index); | |
| 406 | 391 | }, |
| 407 | 392 | |
| 408 | 393 | // Array accesses use the array they are accessing into. |
| ... | ... | @@ -418,7 +403,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In |
| 418 | 403 | const inst = air.instData(.field_tuple, index); |
| 419 | 404 | const base_type = air.typeOfIndex(inst.base, ip) |
| 420 | 405 | .toTupleType(ip) orelse unreachable; // field_tuple demands tuple type |
| 421 | return base_type.items[inst.field_index]; | |
| 406 | return base_type.items.at(ip, inst.field_index); | |
| 422 | 407 | }, |
| 423 | 408 | }; |
| 424 | 409 | } |
src/core/Hir.zig+1-1| ... | ... | @@ -13,7 +13,7 @@ |
| 13 | 13 | |
| 14 | 14 | insts: Inst.List.Slice, |
| 15 | 15 | string_bytes: []const u8, |
| 16 | extra: ExtraStore = .{}, | |
| 16 | extra: ExtraStore, | |
| 17 | 17 | report: Report, |
| 18 | 18 | |
| 19 | 19 | pub const ExtraStore = dod.ExtraStore(.hir, .@"const"); |
src/core/InternPool.zig+91-104| ... | ... | @@ -21,9 +21,9 @@ |
| 21 | 21 | /// |
| 22 | 22 | /// The preferred way to access these this data through `.get()` and the methods |
| 23 | 23 | /// on `Value` and `Type`. |
| 24 | map: std.AutoArrayHashMapUnmanaged(void, void) = .{}, | |
| 25 | items: std.MultiArrayList(Item) = .{}, | |
| 26 | extra: ExtraStore = .{}, | |
| 24 | map: std.AutoArrayHashMapUnmanaged(void, void) = .empty, | |
| 25 | items: std.MultiArrayList(Item) = .empty, | |
| 26 | extra: Extra = .empty, | |
| 27 | 27 | |
| 28 | 28 | /// In order to store references to strings in fewer bytes, we copy all |
| 29 | 29 | /// string bytes into here. String bytes can be null. It is up to whoever |
| ... | ... | @@ -146,7 +146,7 @@ pub const Tag = enum(u8) { |
| 146 | 146 | .int32 => i32, |
| 147 | 147 | .opaque_value => Value, |
| 148 | 148 | |
| 149 | else => ExtraIndex(tag.Payload()), | |
| 149 | else => Extra.Index(tag.Payload()), | |
| 150 | 150 | }; |
| 151 | 151 | } |
| 152 | 152 | |
| ... | ... | @@ -270,18 +270,7 @@ pub const Value = enum(u32) { |
| 270 | 270 | none = std.math.maxInt(u32), |
| 271 | 271 | _, |
| 272 | 272 | |
| 273 | /// An array of `Value` existing within the `extra` array. | |
| 274 | /// This type exists to provide a struct with lifetime that is | |
| 275 | /// not invalidated when items are added to the `InternPool`. | |
| 276 | // TODO: Replace with ExtraStore.Slice(Value) | |
| 277 | pub const Slice = struct { | |
| 278 | start: u32, | |
| 279 | len: u32, | |
| 280 | ||
| 281 | pub fn get(slice: Slice, ip: *const InternPool) []const Value { | |
| 282 | return @ptrCast(ip.extra.list.items[slice.start..][0..slice.len]); | |
| 283 | } | |
| 284 | }; | |
| 273 | pub const Slice = Extra.Slice(Value); | |
| 285 | 274 | |
| 286 | 275 | /// Used for a map of `Value` values to the index within a list of `Value` values. |
| 287 | 276 | const Adapter = struct { |
| ... | ... | @@ -316,6 +305,8 @@ pub const Value = enum(u32) { |
| 316 | 305 | |
| 317 | 306 | pub fn assertValid(value: Value, ip: *const InternPool) void { |
| 318 | 307 | assert(@intFromEnum(value) < ip.items.len); |
| 308 | assert(value != .none); | |
| 309 | assert(ip.items.items(.tag)[@intFromEnum(value)] != .removed); | |
| 319 | 310 | } |
| 320 | 311 | |
| 321 | 312 | pub fn dump(value: Value, ip: *const InternPool) std.fmt.Formatter(Value.formatValue) { |
| ... | ... | @@ -459,17 +450,7 @@ pub const Type = enum(u32) { |
| 459 | 450 | tuple_type = @intFromEnum(InternPool.Tag.tuple_type), |
| 460 | 451 | }; |
| 461 | 452 | |
| 462 | /// An array of `Index` existing within the `extra` array. | |
| 463 | /// This type exists to provide a struct with lifetime that is | |
| 464 | /// not invalidated when items are added to the `InternPool`. | |
| 465 | pub const Slice = struct { | |
| 466 | start: u32, | |
| 467 | len: u32, | |
| 468 | ||
| 469 | pub fn get(slice: Slice, ip: *const InternPool) []Type { | |
| 470 | return @ptrCast(ip.extra.list.items[slice.start..][0..slice.len]); | |
| 471 | } | |
| 472 | }; | |
| 453 | pub const Slice = Extra.Slice(Type); | |
| 473 | 454 | |
| 474 | 455 | pub fn value(ty: Type) Value { |
| 475 | 456 | return @enumFromInt(@intFromEnum(ty)); |
| ... | ... | @@ -526,7 +507,7 @@ pub const Type = enum(u32) { |
| 526 | 507 | => true, |
| 527 | 508 | .tuple_type => { |
| 528 | 509 | const tuple_type = ty.toTupleType(ip).?; |
| 529 | for (tuple_type.items) |item| { | |
| 510 | for (tuple_type.items.get(ip)) |item| { | |
| 530 | 511 | if (!item.hasPossibleRepresentation(ip)) { |
| 531 | 512 | return false; |
| 532 | 513 | } |
| ... | ... | @@ -599,7 +580,7 @@ pub const Type = enum(u32) { |
| 599 | 580 | .function_type => { |
| 600 | 581 | const function_type = ty.toUnresolvedFunctionPrototype(ip).?; |
| 601 | 582 | try writer.writeAll("fn("); |
| 602 | for (function_type.param_types, 0..) |param, i| { | |
| 583 | for (function_type.param_types.get(ip), 0..) |param, i| { | |
| 603 | 584 | if (i != 0) try writer.writeAll(", "); |
| 604 | 585 | try writer.print("{}", .{param.displayName(ip)}); |
| 605 | 586 | } |
| ... | ... | @@ -619,7 +600,7 @@ pub const Type = enum(u32) { |
| 619 | 600 | }, |
| 620 | 601 | .tuple_type => { |
| 621 | 602 | try writer.writeAll("("); |
| 622 | for (ty.toTupleType(ip).?.items, 0..) |item, i| { | |
| 603 | for (ty.toTupleType(ip).?.items.get(ip), 0..) |item, i| { | |
| 623 | 604 | if (i != 0) try writer.writeAll(", "); |
| 624 | 605 | try writer.print("{}", .{item.displayName(ip)}); |
| 625 | 606 | } |
| ... | ... | @@ -651,9 +632,8 @@ pub const Item = struct { |
| 651 | 632 | } |
| 652 | 633 | }; |
| 653 | 634 | |
| 654 | pub const ExtraStore = dod.ExtraStore(.intern_pool, .@"var"); | |
| 635 | pub const Extra = dod.ExtraStore(.intern_pool, .@"var"); | |
| 655 | 636 | pub const EncodedData = dod.EncodedData(Tag, u32); |
| 656 | pub const ExtraIndex = ExtraStore.Index; | |
| 657 | 637 | |
| 658 | 638 | /// How many items in the InternPool are statically known. |
| 659 | 639 | /// This is specified with an integer literal and a corresponding comptime |
| ... | ... | @@ -674,9 +654,9 @@ pub const static_keys = [_]Key{ |
| 674 | 654 | SimpleType.never.key(), |
| 675 | 655 | SimpleType.type.key(), |
| 676 | 656 | SimpleType.numeric_literal.key(), |
| 677 | .{ .array_type = .{ .item_type = Type.numeric_literal } }, | |
| 678 | .{ .array_type = .{ .item_type = Type.never } }, | |
| 679 | .{ .tuple_type = .{ .items = &.{} } }, | |
| 657 | .{ .array_type = .{ .item_type = .numeric_literal } }, | |
| 658 | .{ .array_type = .{ .item_type = .never } }, | |
| 659 | .{ .tuple_type = .{ .items = .empty } }, | |
| 680 | 660 | |
| 681 | 661 | SimpleValue.void.key(), |
| 682 | 662 | SimpleValue.true.key(), |
| ... | ... | @@ -685,13 +665,13 @@ pub const static_keys = [_]Key{ |
| 685 | 665 | .{ .float = 0.0 }, |
| 686 | 666 | .{ .float = Float.pure_nan.decode() }, |
| 687 | 667 | .{ .array_value = .{ |
| 688 | .type = Type.never_array, | |
| 689 | .items = &.{}, | |
| 668 | .type = .never_array, | |
| 669 | .items = .empty, | |
| 690 | 670 | } }, |
| 691 | 671 | .{ .string = "" }, |
| 692 | 672 | .{ .tuple_value = .{ |
| 693 | 673 | .type = .empty_tuple, |
| 694 | .items = &.{}, | |
| 674 | .items = .empty, | |
| 695 | 675 | } }, |
| 696 | 676 | }; |
| 697 | 677 | |
| ... | ... | @@ -814,14 +794,7 @@ pub const NullTerminatedString = enum(u32) { |
| 814 | 794 | return .{ .data = .{ .string = self, .ip = ip } }; |
| 815 | 795 | } |
| 816 | 796 | |
| 817 | pub const Slice = struct { | |
| 818 | start: u32, | |
| 819 | len: u32, | |
| 820 | ||
| 821 | pub fn get(slice: Slice, ip: *const InternPool) []NullTerminatedString { | |
| 822 | return @ptrCast(ip.extra.list.items[slice.start..][0..slice.len]); | |
| 823 | } | |
| 824 | }; | |
| 797 | pub const Slice = Extra.Slice(NullTerminatedString); | |
| 825 | 798 | }; |
| 826 | 799 | |
| 827 | 800 | pub const TrackedInst = extern struct { |
| ... | ... | @@ -975,66 +948,74 @@ pub const Key = union(enum) { |
| 975 | 948 | }; |
| 976 | 949 | |
| 977 | 950 | pub const FunctionType = struct { |
| 978 | param_types: []Type, | |
| 951 | param_types: Type.Slice, | |
| 979 | 952 | /// If a return type is missing, it is inferred and not resolved yet. |
| 980 | 953 | /// When analysis figures out a return type, a new `FunctionType` with |
| 981 | 954 | /// the resolved return type. |
| 982 | 955 | return_type: ?Type, |
| 983 | 956 | |
| 984 | 957 | pub const Resolved = struct { |
| 985 | param_types: []Type, | |
| 958 | param_types: Type.Slice, | |
| 986 | 959 | return_type: Type, |
| 987 | 960 | }; |
| 988 | 961 | |
| 989 | pub fn hash(self: FunctionType, hasher: *Hash) void { | |
| 962 | pub fn hash(self: FunctionType, ip: *const InternPool, hasher: *Hash) void { | |
| 990 | 963 | const t = tracer.trace(@src()); |
| 991 | 964 | defer t.end(); |
| 992 | 965 | |
| 993 | for (self.param_types) |param_type| { | |
| 966 | for (self.param_types.get(ip)) |param_type| { | |
| 994 | 967 | std.hash.autoHash(hasher, param_type); |
| 995 | 968 | } |
| 996 | 969 | std.hash.autoHash(hasher, self.return_type); |
| 997 | 970 | } |
| 998 | 971 | |
| 999 | pub fn eql(a: FunctionType, b: FunctionType) bool { | |
| 1000 | return std.mem.eql(Type, a.param_types, b.param_types) and | |
| 972 | pub fn eql(a: FunctionType, b: FunctionType, ip: *const InternPool) bool { | |
| 973 | return std.mem.eql(Type, a.param_types.get(ip), b.param_types.get(ip)) and | |
| 1001 | 974 | a.return_type == b.return_type; |
| 1002 | 975 | } |
| 1003 | 976 | }; |
| 1004 | 977 | |
| 1005 | 978 | pub const StructType = struct { |
| 1006 | field_keys: []NullTerminatedString, | |
| 1007 | field_types: []const Type, | |
| 979 | field_keys: NullTerminatedString.Slice, | |
| 980 | field_types: Type.Slice, | |
| 1008 | 981 | |
| 1009 | pub fn hash(self: StructType, hasher: *Hash) void { | |
| 1010 | // TODO: remove this function. structural typing is not used | |
| 1011 | // this should be hashing it's location / decl, exactly like `Func` | |
| 1012 | std.hash.autoHashStrat(hasher, self, .DeepRecursive); | |
| 982 | /// TODO: store where the struct is declared to make this a nomial type | |
| 983 | pub fn hash(self: StructType, ip: *const InternPool, hasher: *Hash) void { | |
| 984 | for (self.field_keys.get(ip)) |value| { | |
| 985 | std.hash.autoHash(hasher, value); | |
| 986 | } | |
| 987 | for (self.field_types.get(ip)) |value| { | |
| 988 | std.hash.autoHash(hasher, value); | |
| 989 | } | |
| 1013 | 990 | } |
| 1014 | 991 | }; |
| 1015 | 992 | |
| 1016 | 993 | pub const StructValue = struct { |
| 1017 | 994 | ty: Type, |
| 1018 | field_values: []const Value, | |
| 995 | field_values: Value.Slice, | |
| 1019 | 996 | |
| 1020 | pub fn hash(self: StructValue, hasher: *Hash) void { | |
| 997 | pub fn hash(self: StructValue, ip: *const InternPool, hasher: *Hash) void { | |
| 1021 | 998 | std.hash.autoHash(hasher, self.ty); |
| 1022 | std.hash.autoHashStrat(hasher, self.field_values, .Deep); | |
| 999 | for (self.field_values.get(ip)) |value| { | |
| 1000 | std.hash.autoHash(hasher, value); | |
| 1001 | } | |
| 1023 | 1002 | } |
| 1024 | 1003 | }; |
| 1025 | 1004 | |
| 1026 | 1005 | pub const ArrayType = struct { |
| 1027 | 1006 | item_type: Type, |
| 1028 | 1007 | |
| 1029 | pub fn hash(self: ArrayType, hasher: *Hash) void { | |
| 1008 | pub fn hash(self: ArrayType, ip: *const InternPool, hasher: *Hash) void { | |
| 1009 | _ = ip; | |
| 1030 | 1010 | std.hash.autoHash(hasher, self.item_type); |
| 1031 | 1011 | } |
| 1032 | 1012 | }; |
| 1033 | 1013 | |
| 1034 | 1014 | pub const TupleType = struct { |
| 1035 | items: []const Type, | |
| 1015 | items: Type.Slice, | |
| 1036 | 1016 | |
| 1037 | pub fn hash(self: TupleType, hasher: *Hash) void { | |
| 1017 | pub fn hash(self: TupleType, ip: *const InternPool, hasher: *Hash) void { | |
| 1018 | _ = ip; | |
| 1038 | 1019 | std.hash.autoHashStrat(hasher, self.items, .Deep); |
| 1039 | 1020 | } |
| 1040 | 1021 | }; |
| ... | ... | @@ -1042,30 +1023,31 @@ pub const Key = union(enum) { |
| 1042 | 1023 | pub const ExternalValue = struct { |
| 1043 | 1024 | /// A list of strings to generate the property access |
| 1044 | 1025 | /// so `console.log` would be .{ "console", "log" } |
| 1045 | key: []const NullTerminatedString, | |
| 1026 | key: NullTerminatedString.Slice, | |
| 1046 | 1027 | |
| 1047 | pub fn hash(self: ExternalValue, hasher: *Hash) void { | |
| 1048 | std.hash.autoHashStrat(hasher, self.key, .Shallow); | |
| 1028 | pub fn hash(self: ExternalValue, ip: *const InternPool, hasher: *Hash) void { | |
| 1029 | std.hash.autoHashStrat(hasher, self.key.get(ip), .Shallow); | |
| 1049 | 1030 | } |
| 1050 | 1031 | }; |
| 1051 | 1032 | |
| 1052 | 1033 | pub const ArrayValue = struct { |
| 1053 | 1034 | /// This is the array type, not the item type |
| 1054 | 1035 | type: Type, |
| 1055 | items: []const Value, | |
| 1036 | items: Value.Slice, | |
| 1056 | 1037 | |
| 1057 | pub fn hash(self: ArrayValue, hasher: *Hash) void { | |
| 1038 | pub fn hash(self: ArrayValue, ip: *const InternPool, hasher: *Hash) void { | |
| 1058 | 1039 | std.hash.autoHash(hasher, self.type); |
| 1059 | std.hash.autoHashStrat(hasher, self.items, .Deep); | |
| 1040 | std.hash.autoHashStrat(hasher, self.items.get(ip), .Deep); | |
| 1060 | 1041 | } |
| 1061 | 1042 | }; |
| 1062 | 1043 | |
| 1063 | 1044 | pub const TupleValue = struct { |
| 1064 | 1045 | /// This is the tuple type, not the item type |
| 1065 | 1046 | type: Type, |
| 1066 | items: []const Value, | |
| 1047 | items: Value.Slice, | |
| 1067 | 1048 | |
| 1068 | pub fn hash(self: TupleValue, hasher: *Hash) void { | |
| 1049 | pub fn hash(self: TupleValue, ip: *const InternPool, hasher: *Hash) void { | |
| 1050 | _ = ip; | |
| 1069 | 1051 | std.hash.autoHash(hasher, self.type); |
| 1070 | 1052 | std.hash.autoHashStrat(hasher, self.items, .Deep); |
| 1071 | 1053 | } |
| ... | ... | @@ -1075,9 +1057,10 @@ pub const Key = union(enum) { |
| 1075 | 1057 | ty: Type, |
| 1076 | 1058 | owner_decl: DeclIndex, |
| 1077 | 1059 | teg_body_inst: TrackedInst.Index, |
| 1078 | analysis: ExtraIndex(AnalysisState), | |
| 1060 | analysis: Extra.Index(AnalysisState), | |
| 1079 | 1061 | |
| 1080 | pub fn hash(self: Func, hasher: *Hash) void { | |
| 1062 | pub fn hash(self: Func, ip: *const InternPool, hasher: *Hash) void { | |
| 1063 | _ = ip; | |
| 1081 | 1064 | std.hash.autoHash(hasher, self.ty); |
| 1082 | 1065 | std.hash.autoHash(hasher, self.owner_decl); |
| 1083 | 1066 | std.hash.autoHash(hasher, self.teg_body_inst); |
| ... | ... | @@ -1095,7 +1078,6 @@ pub const Key = union(enum) { |
| 1095 | 1078 | } |
| 1096 | 1079 | |
| 1097 | 1080 | pub fn hash64(key: Key, ip: *const InternPool) u64 { |
| 1098 | _ = ip; // autofix | |
| 1099 | 1081 | const t = tracer.trace(@src()); |
| 1100 | 1082 | defer t.end(); |
| 1101 | 1083 | |
| ... | ... | @@ -1114,8 +1096,8 @@ pub const Key = union(enum) { |
| 1114 | 1096 | .float, .comptime_float => |x| Hash.hash(seed, asBytes(&Float.assertPure(x))), |
| 1115 | 1097 | inline .function_type, |
| 1116 | 1098 | .func, |
| 1117 | .struct_type, | |
| 1118 | 1099 | .struct_value, |
| 1100 | .struct_type, | |
| 1119 | 1101 | .array_value, |
| 1120 | 1102 | .array_type, |
| 1121 | 1103 | .external_value, |
| ... | ... | @@ -1123,14 +1105,13 @@ pub const Key = union(enum) { |
| 1123 | 1105 | .tuple_value, |
| 1124 | 1106 | => |x| { |
| 1125 | 1107 | var hasher = Hash.init(seed); |
| 1126 | x.hash(&hasher); | |
| 1108 | x.hash(ip, &hasher); | |
| 1127 | 1109 | return hasher.final(); |
| 1128 | 1110 | }, |
| 1129 | 1111 | }; |
| 1130 | 1112 | } |
| 1131 | 1113 | |
| 1132 | 1114 | pub fn eql(a: Key, b: Key, ip: *const InternPool) bool { |
| 1133 | _ = ip; // autofix | |
| 1134 | 1115 | const t = tracer.trace(@src()); |
| 1135 | 1116 | defer t.end(); |
| 1136 | 1117 | |
| ... | ... | @@ -1148,7 +1129,7 @@ pub const Key = union(enum) { |
| 1148 | 1129 | => |x| std.mem.eql(u8, x, b.string), |
| 1149 | 1130 | .float => |x| Float.assertPure(x) == Float.assertPure(b.float), |
| 1150 | 1131 | .comptime_float => |x| Float.assertPure(x) == Float.assertPure(b.comptime_float), |
| 1151 | .function_type => |x| x.eql(b.function_type), | |
| 1132 | .function_type => |x| x.eql(b.function_type, ip), | |
| 1152 | 1133 | .func => |a_info| { |
| 1153 | 1134 | const b_info = b.func; |
| 1154 | 1135 | if (a_info.owner_decl != b_info.owner_decl) |
| ... | ... | @@ -1165,7 +1146,7 @@ pub const Key = union(enum) { |
| 1165 | 1146 | .struct_value => |a_info| { |
| 1166 | 1147 | const b_info = b.struct_value; |
| 1167 | 1148 | return a_info.ty == b_info.ty and |
| 1168 | std.mem.eql(Value, a_info.field_values, b_info.field_values); | |
| 1149 | std.mem.eql(Value, a_info.field_values.get(ip), b_info.field_values.get(ip)); | |
| 1169 | 1150 | }, |
| 1170 | 1151 | .array_type => |a_info| { |
| 1171 | 1152 | return a_info.item_type == b.array_type.item_type; |
| ... | ... | @@ -1173,20 +1154,21 @@ pub const Key = union(enum) { |
| 1173 | 1154 | .array_value => |a_info| { |
| 1174 | 1155 | const b_info = b.array_value; |
| 1175 | 1156 | return a_info.type == b_info.type and |
| 1176 | std.mem.eql(Value, a_info.items, b_info.items); | |
| 1157 | std.mem.eql(Value, a_info.items.get(ip), b_info.items.get(ip)); | |
| 1177 | 1158 | }, |
| 1178 | 1159 | .external_value => |a_info| { |
| 1179 | 1160 | const b_info = b.external_value; |
| 1180 | return std.mem.eql(NullTerminatedString, a_info.key, b_info.key); | |
| 1161 | return std.mem.eql(NullTerminatedString, a_info.key.get(ip), b_info.key.get(ip)); | |
| 1181 | 1162 | }, |
| 1182 | 1163 | .tuple_type => |a_info| { |
| 1183 | 1164 | const b_info = b.tuple_type; |
| 1184 | return a_info.items.len == b_info.items.len and std.mem.eql(Type, a_info.items, b_info.items); | |
| 1165 | return a_info.items.len == b_info.items.len and | |
| 1166 | std.mem.eql(Type, a_info.items.get(ip), b_info.items.get(ip)); | |
| 1185 | 1167 | }, |
| 1186 | 1168 | .tuple_value => |a_info| { |
| 1187 | 1169 | const b_info = b.tuple_value; |
| 1188 | 1170 | return a_info.type == b_info.type and |
| 1189 | std.mem.eql(Value, a_info.items, b_info.items); | |
| 1171 | std.mem.eql(Value, a_info.items.get(ip), b_info.items.get(ip)); | |
| 1190 | 1172 | }, |
| 1191 | 1173 | }; |
| 1192 | 1174 | } |
| ... | ... | @@ -1438,8 +1420,8 @@ pub fn valueToKey(ip: *const InternPool, index: Value) Key { |
| 1438 | 1420 | data.decode(.struct_type, item.tag).getTrail(ip); |
| 1439 | 1421 | |
| 1440 | 1422 | return .{ .struct_type = .{ |
| 1441 | .field_keys = trail.readNullTerminatedStringSlice(payload.fields_len).get(ip), | |
| 1442 | .field_types = trail.readTypeSlice(payload.fields_len).get(ip), | |
| 1423 | .field_keys = trail.readNullTerminatedStringSlice(payload.fields_len), | |
| 1424 | .field_types = trail.readTypeSlice(payload.fields_len), | |
| 1443 | 1425 | } }; |
| 1444 | 1426 | }, |
| 1445 | 1427 | .struct_value => { |
| ... | ... | @@ -1449,8 +1431,10 @@ pub fn valueToKey(ip: *const InternPool, index: Value) Key { |
| 1449 | 1431 | return .{ .struct_value = .{ |
| 1450 | 1432 | .ty = payload.ty, |
| 1451 | 1433 | .field_values = trail.readValueSlice( |
| 1452 | payload.ty.value().valueData(ip, .struct_type).get(ip).fields_len, | |
| 1453 | ).get(ip), | |
| 1434 | payload.ty.value() | |
| 1435 | .valueData(ip, .struct_type) | |
| 1436 | .get(ip).fields_len, | |
| 1437 | ), | |
| 1454 | 1438 | } }; |
| 1455 | 1439 | }, |
| 1456 | 1440 | .array_type => { |
| ... | ... | @@ -1463,31 +1447,34 @@ pub fn valueToKey(ip: *const InternPool, index: Value) Key { |
| 1463 | 1447 | const payload: Tag.ArrayValue, var trail = data.decode(.array_value, item.tag).getTrail(ip); |
| 1464 | 1448 | return .{ .array_value = .{ |
| 1465 | 1449 | .type = payload.type, |
| 1466 | .items = trail.readValueSlice(payload.items_len).get(ip), | |
| 1450 | .items = trail.readValueSlice(payload.items_len), | |
| 1467 | 1451 | } }; |
| 1468 | 1452 | }, |
| 1469 | 1453 | .external_value => { |
| 1470 | 1454 | const payload: Tag.ExternalValue, var trail = data.decode(.external_value, item.tag).getTrail(ip); |
| 1471 | 1455 | return .{ .external_value = .{ |
| 1472 | .key = trail.readNullTerminatedStringSlice(payload.key_count).get(ip), | |
| 1456 | .key = trail.readNullTerminatedStringSlice(payload.key_count), | |
| 1473 | 1457 | } }; |
| 1474 | 1458 | }, |
| 1475 | 1459 | .tuple_type => { |
| 1476 | 1460 | const payload: Tag.TupleType, var trail = data.decode(.tuple_type, item.tag).getTrail(ip); |
| 1477 | 1461 | return .{ .tuple_type = .{ |
| 1478 | .items = trail.readTypeSlice(payload.items_len).get(ip), | |
| 1462 | .items = trail.readTypeSlice(payload.items_len), | |
| 1479 | 1463 | } }; |
| 1480 | 1464 | }, |
| 1481 | 1465 | .tuple_value => { |
| 1482 | 1466 | const payload: Tag.TupleValue, var trail = data.decode(.tuple_value, item.tag).getTrail(ip); |
| 1483 | 1467 | return .{ .tuple_value = .{ |
| 1484 | 1468 | .type = payload.type, |
| 1485 | .items = trail.readValueSlice(payload.items_len).get(ip), | |
| 1469 | .items = trail.readValueSlice(payload.items_len), | |
| 1486 | 1470 | } }; |
| 1487 | 1471 | }, |
| 1488 | 1472 | }; |
| 1489 | 1473 | } |
| 1490 | 1474 | |
| 1475 | // TODO: this function currently has a soft leak as `Key` requires slices into | |
| 1476 | // InternPool, so querying for a something with a slice (function_type) will | |
| 1477 | // always append it to `.extra` even if it becomes unused. | |
| 1491 | 1478 | pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value { |
| 1492 | 1479 | const t = tracer.traceFmt(@src(), "{s}", .{@tagName(key)}); |
| 1493 | 1480 | defer t.end(); |
| ... | ... | @@ -1536,25 +1523,25 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value { |
| 1536 | 1523 | break :brk Item.encode(.func, extra); |
| 1537 | 1524 | }, |
| 1538 | 1525 | .function_type => |f| brk: { |
| 1539 | for (f.param_types) |ty| ty.assertValid(ip); | |
| 1526 | for (f.param_types.get(ip)) |ty| ty.assertValid(ip); | |
| 1540 | 1527 | |
| 1541 | 1528 | const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.FunctionType, .{ |
| 1542 | 1529 | .params_len = @intCast(f.param_types.len), |
| 1543 | 1530 | .return_type = .init(f.return_type), |
| 1544 | 1531 | }, f.param_types.len); |
| 1545 | 1532 | defer trail.end(); |
| 1546 | trail.writeSlice(f.param_types); | |
| 1533 | trail.writeSlice(f.param_types.get(ip)); | |
| 1547 | 1534 | break :brk Item.encode(.function_type, extra); |
| 1548 | 1535 | }, |
| 1549 | 1536 | .struct_type => |s| brk: { |
| 1550 | for (s.field_types) |ty| ty.assertValid(ip); | |
| 1537 | for (s.field_types.get(ip)) |ty| ty.assertValid(ip); | |
| 1551 | 1538 | |
| 1552 | 1539 | assert(s.field_keys.len == s.field_types.len); |
| 1553 | 1540 | const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.StructType, .{ |
| 1554 | 1541 | .fields_len = @intCast(s.field_keys.len), |
| 1555 | 1542 | }, s.field_keys.len * 2); |
| 1556 | trail.writeSlice(s.field_keys); | |
| 1557 | trail.writeSlice(s.field_types); | |
| 1543 | trail.writeSlice(s.field_keys.get(ip)); | |
| 1544 | trail.writeSlice(s.field_types.get(ip)); | |
| 1558 | 1545 | |
| 1559 | 1546 | break :brk Item.encode(.struct_type, extra); |
| 1560 | 1547 | }, |
| ... | ... | @@ -1563,7 +1550,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value { |
| 1563 | 1550 | const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.StructValue, .{ |
| 1564 | 1551 | .ty = s.ty, |
| 1565 | 1552 | }, s.field_values.len); |
| 1566 | trail.writeSlice(s.field_values); | |
| 1553 | trail.writeSlice(s.field_values.get(ip)); | |
| 1567 | 1554 | break :brk Item.encode(.struct_value, extra); |
| 1568 | 1555 | }, |
| 1569 | 1556 | .array_type => |s| brk: { |
| ... | ... | @@ -1576,21 +1563,21 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value { |
| 1576 | 1563 | .type = s.type, |
| 1577 | 1564 | .items_len = @intCast(s.items.len), |
| 1578 | 1565 | }, s.items.len); |
| 1579 | trail.writeSlice(s.items); | |
| 1566 | trail.writeSlice(s.items.get(ip)); | |
| 1580 | 1567 | break :brk Item.encode(.array_value, extra); |
| 1581 | 1568 | }, |
| 1582 | 1569 | .external_value => |s| brk: { |
| 1583 | 1570 | const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.ExternalValue, .{ |
| 1584 | 1571 | .key_count = @intCast(s.key.len), |
| 1585 | 1572 | }, s.key.len); |
| 1586 | trail.writeSlice(s.key); | |
| 1573 | trail.writeSlice(s.key.get(ip)); | |
| 1587 | 1574 | break :brk Item.encode(.external_value, extra); |
| 1588 | 1575 | }, |
| 1589 | 1576 | .tuple_type => |s| brk: { |
| 1590 | 1577 | const extra, var trail = try ip.extra.appendTrailing(gpa, Tag.TupleType, .{ |
| 1591 | 1578 | .items_len = @intCast(s.items.len), |
| 1592 | 1579 | }, s.items.len); |
| 1593 | trail.writeSlice(s.items); | |
| 1580 | trail.writeSlice(s.items.get(ip)); | |
| 1594 | 1581 | break :brk Item.encode(.tuple_type, extra); |
| 1595 | 1582 | }, |
| 1596 | 1583 | .tuple_value => |s| brk: { |
| ... | ... | @@ -1598,7 +1585,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value { |
| 1598 | 1585 | .type = s.type, |
| 1599 | 1586 | .items_len = @intCast(s.items.len), |
| 1600 | 1587 | }, s.items.len); |
| 1601 | trail.writeSlice(s.items); | |
| 1588 | trail.writeSlice(s.items.get(ip)); | |
| 1602 | 1589 | break :brk Item.encode(.tuple_value, extra); |
| 1603 | 1590 | }, |
| 1604 | 1591 | }; |
| ... | ... | @@ -1613,13 +1600,13 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) !Value { |
| 1613 | 1600 | |
| 1614 | 1601 | fn extraTypeFunction( |
| 1615 | 1602 | ip: *const InternPool, |
| 1616 | extra_index: ExtraIndex(Tag.FunctionType), | |
| 1603 | extra_index: Extra.Index(Tag.FunctionType), | |
| 1617 | 1604 | ) Key.FunctionType { |
| 1618 | 1605 | const function_type, var trail = extra_index.getTrail(ip); |
| 1619 | 1606 | const param_types = trail.readTypeSlice(function_type.params_len); |
| 1620 | 1607 | const result: Key.FunctionType = .{ |
| 1621 | 1608 | .return_type = function_type.return_type.unwrap(), |
| 1622 | .param_types = param_types.get(ip), | |
| 1609 | .param_types = param_types, | |
| 1623 | 1610 | }; |
| 1624 | 1611 | return result; |
| 1625 | 1612 | } |
src/core/Report.zig+6-7| ... | ... | @@ -111,8 +111,7 @@ pub const Err = union(enum) { |
| 111 | 111 | }, |
| 112 | 112 | no_main_func: struct { |
| 113 | 113 | fn build(_: @This(), ctx: *MsgContext) !void { |
| 114 | // TODO: variant that includes file, but no location | |
| 115 | try ctx.msgToken(0, "missing top-level function \"main\"", .{}); | |
| 114 | try ctx.msg(.{ .codepoint_eol = 0 }, "missing top-level function \"main\"", .{}); | |
| 116 | 115 | } |
| 117 | 116 | }, |
| 118 | 117 | unknown_identifier: struct { |
| ... | ... | @@ -455,7 +454,8 @@ pub const Err = union(enum) { |
| 455 | 454 | data.ty.displayName(ctx.ip()), |
| 456 | 455 | formatId( |
| 457 | 456 | data.ty.toStructType(ctx.ip()).? |
| 458 | .field_keys[data.field].toSlice(ctx.ip()), | |
| 457 | .field_keys.at(ctx.ip(), data.field) | |
| 458 | .toSlice(ctx.ip()), | |
| 459 | 459 | ), |
| 460 | 460 | }, |
| 461 | 461 | ); |
| ... | ... | @@ -872,7 +872,7 @@ fn formatItem( |
| 872 | 872 | try tty.setColor(writer, .reset); |
| 873 | 873 | try tty.setColor(writer, prefix.color()); |
| 874 | 874 | try tty.setColor(writer, .bold); |
| 875 | try writer.writeBytesNTimes("━", at.slice.len); | |
| 875 | try writer.writeBytesNTimes("━", @max(at.slice.len, 1)); | |
| 876 | 876 | try tty.setColor(writer, .reset); |
| 877 | 877 | try writer.writeAll("\n"); |
| 878 | 878 | } |
| ... | ... | @@ -1074,11 +1074,10 @@ pub const Highlight = union(enum) { |
| 1074 | 1074 | .byte = b, |
| 1075 | 1075 | .slice = ast.utf8_source[b..][0..len], |
| 1076 | 1076 | .loc = .{ |
| 1077 | // TODO: | |
| 1078 | 1077 | .column = .start, |
| 1079 | 1078 | .line = .start, |
| 1080 | .line_start = 0, | |
| 1081 | .line_end = @intCast(ast.utf8_source.len), | |
| 1079 | .line_start = b, | |
| 1080 | .line_end = @intCast(b + len), | |
| 1082 | 1081 | }, |
| 1083 | 1082 | }; |
| 1084 | 1083 | }, |
src/core/Sema.zig+64-39| ... | ... | @@ -547,7 +547,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 547 | 547 | return return_type.value().toAir(); |
| 548 | 548 | }, |
| 549 | 549 | else => return s.addRef(.arg, .{ |
| 550 | .type = proto.param_types[param.data], | |
| 550 | .type = proto.param_types.at(s.ip, param.data), | |
| 551 | 551 | .arg_number = param.data, |
| 552 | 552 | }), |
| 553 | 553 | } |
| ... | ... | @@ -664,8 +664,8 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 664 | 664 | } |
| 665 | 665 | |
| 666 | 666 | return try s.makeValueAir(.{ .struct_type = .{ |
| 667 | .field_keys = scratch.items(.keys), | |
| 668 | .field_types = scratch.items(.types), | |
| 667 | .field_keys = try s.ip.extra.appendSlice(s.gpa, scratch.items(.keys)), | |
| 668 | .field_types = try s.ip.extra.appendSlice(s.gpa, scratch.items(.types)), | |
| 669 | 669 | } }); |
| 670 | 670 | }, |
| 671 | 671 | .discard => { |
| ... | ... | @@ -689,7 +689,10 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 689 | 689 | @panic("TODO: support strings with null here"); |
| 690 | 690 | }; |
| 691 | 691 | return try s.makeValueAir(.{ .external_value = .{ |
| 692 | .key = &.{str}, | |
| 692 | .key = try s.ip.extra.appendSlice( | |
| 693 | s.gpa, | |
| 694 | @as([]const NullTerminatedString, &.{str}), | |
| 695 | ), | |
| 693 | 696 | } }); |
| 694 | 697 | }, |
| 695 | 698 | .field => { |
| ... | ... | @@ -708,13 +711,13 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 708 | 711 | const previous_key = value.toKey(s.ip).external_value.key; |
| 709 | 712 | |
| 710 | 713 | const new_key = try std.mem.concat(s.arena(), NullTerminatedString, &.{ |
| 711 | previous_key, | |
| 714 | previous_key.get(s.ip), | |
| 712 | 715 | &.{field_key}, |
| 713 | 716 | }); |
| 714 | 717 | defer s.arena().free(new_key); |
| 715 | 718 | |
| 716 | 719 | return s.makeValueAir(.{ .external_value = .{ |
| 717 | .key = new_key, | |
| 720 | .key = try s.ip.extra.appendSlice(s.gpa, new_key), | |
| 718 | 721 | } }); |
| 719 | 722 | } |
| 720 | 723 | } |
| ... | ... | @@ -764,7 +767,11 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 764 | 767 | } |
| 765 | 768 | |
| 766 | 769 | // validate function args |
| 767 | for (proto.param_types, call.args.slice(&s.hir), 0..) |param, arg, i| { | |
| 770 | for ( | |
| 771 | proto.param_types.get(s.ip), | |
| 772 | call.args.slice(&s.hir), | |
| 773 | 0.., | |
| 774 | ) |param, arg, i| { | |
| 768 | 775 | const ref = s.getRef(arg, .marked); |
| 769 | 776 | const coerced = try s.coerceRef( |
| 770 | 777 | s.lazyNode(.argument(@intCast(i))), |
| ... | ... | @@ -838,19 +845,23 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 838 | 845 | for (scratch.slice(), scratch.sliceReinterpret(Value)) |ref, *value| { |
| 839 | 846 | value.* = ref.decode().value; |
| 840 | 847 | } |
| 841 | return try s.makeValueAir(.{ .array_value = .{ | |
| 842 | .type = ty, | |
| 843 | .items = result_storage, | |
| 844 | } }); | |
| 848 | return try s.makeValueAir(.{ | |
| 849 | .array_value = .{ | |
| 850 | .type = ty, | |
| 851 | // TODO: do not clone memory here | |
| 852 | .items = try s.ip.extra.appendSlice(s.gpa, result_storage), | |
| 853 | }, | |
| 854 | }); | |
| 845 | 855 | } else { |
| 846 | 856 | // Create a runtime array instantiation |
| 847 | 857 | try s.ensureAtRuntime(s.lazyNode(.main_node)); |
| 848 | 858 | return try s.addRef(.array_init, .{ |
| 849 | 859 | .ty = ty, |
| 850 | .list = try s.func.?.extra.append(s.gpa, Air.RefList, .{ | |
| 851 | .start = try s.func.?.extra.appendSlice(s.gpa, scratch.slice()), | |
| 852 | .len = node.list.len, | |
| 853 | }), | |
| 860 | .list = try s.func.?.extra.append( | |
| 861 | s.gpa, | |
| 862 | Air.RefList, | |
| 863 | try s.func.?.extra.appendSlice(s.gpa, scratch.slice()), | |
| 864 | ), | |
| 854 | 865 | }); |
| 855 | 866 | } |
| 856 | 867 | }, |
| ... | ... | @@ -1017,7 +1028,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 1017 | 1028 | const brk: Hir.Break = s.frame.currentPayload(.@"break"); |
| 1018 | 1029 | const operand = s.getRef(brk.operand, .marked); |
| 1019 | 1030 | |
| 1020 | assert(s.frame.block_index == brk.block); | |
| 1031 | if (s.frame.block_index != brk.block) @panic("TODO"); | |
| 1021 | 1032 | |
| 1022 | 1033 | const mark = core.U32Stack.Mark{ .stack = &s.scratch, .index = s.frame.mark_index }; |
| 1023 | 1034 | |
| ... | ... | @@ -1028,7 +1039,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 1028 | 1039 | const coerced = if (proto.return_type) |return_coercion| |
| 1029 | 1040 | try s.coerceRef(s.lazyNode(.operand), operand, return_coercion) |
| 1030 | 1041 | else |
| 1031 | operand; | |
| 1042 | try s.ensureRefRuntime(s.lazyNode(.operand), operand); | |
| 1032 | 1043 | s.inst_map.add(s.frame.block_index, coerced); |
| 1033 | 1044 | |
| 1034 | 1045 | const indexes = mark.slice(u32); |
| ... | ... | @@ -1388,7 +1399,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 1388 | 1399 | // may be different than the instantiation. The fields are visited in |
| 1389 | 1400 | // order of the instantiation. |
| 1390 | 1401 | for (node.keys(&s.hir), node.inits(&s.hir), 0..) |init_key, init_value, i| { |
| 1391 | const found_index = index: for (struct_type.field_keys, 0..) |decl_key, j| { | |
| 1402 | const found_index = index: for (struct_type.field_keys.get(s.ip), 0..) |decl_key, j| { | |
| 1392 | 1403 | if (decl_key.eqlSlice(init_key.slice(s.hir.string_bytes), s.ip)) |
| 1393 | 1404 | break :index j; |
| 1394 | 1405 | } else { |
| ... | ... | @@ -1410,7 +1421,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 1410 | 1421 | const coerced = s.getCoercedRef( |
| 1411 | 1422 | s.lazyNode(.argument(@intCast(i))), |
| 1412 | 1423 | init_value, |
| 1413 | struct_type.field_types[found_index], | |
| 1424 | struct_type.field_types.at(s.ip, found_index), | |
| 1414 | 1425 | .marked, |
| 1415 | 1426 | ) catch |e| switch (e) { |
| 1416 | 1427 | error.AnalysisFail => { |
| ... | ... | @@ -1452,7 +1463,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 1452 | 1463 | } |
| 1453 | 1464 | return try s.makeValueAir(.{ .struct_value = .{ |
| 1454 | 1465 | .ty = ty, |
| 1455 | .field_values = result_storage, | |
| 1466 | .field_values = try s.ip.extra.appendSlice(s.gpa, result_storage), | |
| 1456 | 1467 | } }); |
| 1457 | 1468 | } else { |
| 1458 | 1469 | try s.ensureAtRuntime(s.lazyNode(.main_node)); |
| ... | ... | @@ -1460,7 +1471,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 1460 | 1471 | const value_index = try s.func.?.extra.appendSlice(s.gpa, scratch.slice()); |
| 1461 | 1472 | return try s.addRef(.struct_init, .{ |
| 1462 | 1473 | .ty = ty, |
| 1463 | .field_values = value_index, | |
| 1474 | .field_values = value_index.start, | |
| 1464 | 1475 | }); |
| 1465 | 1476 | } |
| 1466 | 1477 | }, |
| ... | ... | @@ -1481,7 +1492,9 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 1481 | 1492 | dst.* = try s.getType(s.lazyNode(.argument(@intCast(i))), src); |
| 1482 | 1493 | } |
| 1483 | 1494 | |
| 1484 | return s.makeValueAir(.{ .tuple_type = .{ .items = scratch.slice() } }); | |
| 1495 | return s.makeValueAir(.{ .tuple_type = .{ | |
| 1496 | .items = try s.ip.extra.appendSlice(s.gpa, scratch.slice()), | |
| 1497 | } }); | |
| 1485 | 1498 | }, |
| 1486 | 1499 | |
| 1487 | 1500 | .tuple_init => { |
| ... | ... | @@ -1515,7 +1528,12 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 1515 | 1528 | ty.* = s.typeOfRef(val); |
| 1516 | 1529 | } |
| 1517 | 1530 | |
| 1518 | break :ty try s.makeType(.{ .tuple_type = .{ .items = type_scratch.slice() } }); | |
| 1531 | break :ty try s.makeType(.{ | |
| 1532 | .tuple_type = .{ | |
| 1533 | // TODO: memory leak | |
| 1534 | .items = try s.ip.extra.appendSlice(s.gpa, type_scratch.slice()), | |
| 1535 | }, | |
| 1536 | }); | |
| 1519 | 1537 | }; |
| 1520 | 1538 | |
| 1521 | 1539 | if (is_const) { |
| ... | ... | @@ -1525,14 +1543,17 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 1525 | 1543 | value.* = ref.decode().value; |
| 1526 | 1544 | } |
| 1527 | 1545 | |
| 1528 | return try s.makeValueAir(.{ .tuple_value = .{ | |
| 1529 | .items = result_storage, | |
| 1530 | .type = ty, | |
| 1531 | } }); | |
| 1546 | return try s.makeValueAir(.{ | |
| 1547 | .tuple_value = .{ | |
| 1548 | // TODO: memory leak | |
| 1549 | .items = try s.ip.extra.appendSlice(s.gpa, result_storage), | |
| 1550 | .type = ty, | |
| 1551 | }, | |
| 1552 | }); | |
| 1532 | 1553 | } else { |
| 1533 | 1554 | const value_index = try s.func.?.extra.appendSlice(s.gpa, scratch.slice()); |
| 1534 | 1555 | return try s.addRef(.struct_init, .{ |
| 1535 | .field_values = value_index, | |
| 1556 | .field_values = value_index.start, | |
| 1536 | 1557 | .ty = ty, |
| 1537 | 1558 | }); |
| 1538 | 1559 | } |
| ... | ... | @@ -1550,7 +1571,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 1550 | 1571 | if (result.argument >= func.param_types.len) |
| 1551 | 1572 | return Value.opaque_type.toAir(); |
| 1552 | 1573 | |
| 1553 | return func.param_types[result.argument].value().toAir(); | |
| 1574 | return func.param_types.at(s.ip, result.argument).value().toAir(); | |
| 1554 | 1575 | }, |
| 1555 | 1576 | |
| 1556 | 1577 | .result_type_array_value => { |
| ... | ... | @@ -1575,7 +1596,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 1575 | 1596 | |
| 1576 | 1597 | _ = ty; |
| 1577 | 1598 | |
| 1578 | @panic("TODO: tuple result type resolution"); // tuples are not implemented | |
| 1599 | @panic("TODO: tuple result type resolution"); | |
| 1579 | 1600 | }, |
| 1580 | 1601 | |
| 1581 | 1602 | .result_type_struct_field => { |
| ... | ... | @@ -1589,7 +1610,7 @@ fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag) |
| 1589 | 1610 | return Value.opaque_type.toAir(); |
| 1590 | 1611 | |
| 1591 | 1612 | const to_match = result.field.slice(s.hir.string_bytes); |
| 1592 | for (struct_type.field_keys, struct_type.field_types) |k, v| { | |
| 1613 | for (struct_type.field_keys.get(s.ip), struct_type.field_types.get(s.ip)) |k, v| { | |
| 1593 | 1614 | if (k.eqlSlice(to_match, s.ip)) { |
| 1594 | 1615 | return v.value().toAir(); |
| 1595 | 1616 | } |
| ... | ... | @@ -1857,9 +1878,14 @@ fn coerceRef(s: *Sema, src: LazyNode, ref: Air.Inst.Ref, to: Type) !Air.Inst.Ref |
| 1857 | 1878 | /// Same as `coerceRef` but on a compile-time known value |
| 1858 | 1879 | fn coerceValue(s: *Sema, src: LazyNode, value: Value, to: Type) Error!Value { |
| 1859 | 1880 | const from = value.typeOf(s.ip); |
| 1881 | ||
| 1882 | from.assertValid(s.ip); | |
| 1883 | to.assertValid(s.ip); | |
| 1884 | ||
| 1860 | 1885 | if (from == to) { |
| 1861 | 1886 | return value; |
| 1862 | 1887 | } |
| 1888 | ||
| 1863 | 1889 | switch (to) { |
| 1864 | 1890 | .@"opaque" => { |
| 1865 | 1891 | return try s.makeValue(.{ .opaque_value = value }); |
| ... | ... | @@ -2069,7 +2095,7 @@ fn coerceArrayValue(s: *Sema, src: LazyNode, value: Value, item_type: Type) !Val |
| 2069 | 2095 | |
| 2070 | 2096 | return try s.makeValue(.{ .array_value = .{ |
| 2071 | 2097 | .type = try s.makeType(.{ .array_type = .{ .item_type = item_type } }), |
| 2072 | .items = scratch.slice(), | |
| 2098 | .items = try s.ip.extra.appendSlice(s.gpa, scratch.slice()), | |
| 2073 | 2099 | } }); |
| 2074 | 2100 | } |
| 2075 | 2101 | |
| ... | ... | @@ -2096,8 +2122,8 @@ fn coerceTupleValue( |
| 2096 | 2122 | |
| 2097 | 2123 | // This function will append new items to the intern pool, invalidating |
| 2098 | 2124 | // existing ones. Copy all data into a stable slice first. |
| 2099 | @memcpy(scratch.items(.values), tuple_value.items); | |
| 2100 | @memcpy(scratch.items(.types), target_key.items); | |
| 2125 | @memcpy(scratch.items(.values), tuple_value.items.get(s.ip)); | |
| 2126 | @memcpy(scratch.items(.types), target_key.items.get(s.ip)); | |
| 2101 | 2127 | |
| 2102 | 2128 | for (0..len) |i| { |
| 2103 | 2129 | // `s.scratch` can be invalidated by having a tuple of tuples and coercing it. |
| ... | ... | @@ -2107,7 +2133,7 @@ fn coerceTupleValue( |
| 2107 | 2133 | |
| 2108 | 2134 | return try s.makeValue(.{ .tuple_value = .{ |
| 2109 | 2135 | .type = target_type, |
| 2110 | .items = scratch.items(.values), | |
| 2136 | .items = try s.ip.extra.appendSlice(s.gpa, scratch.items(.values)), | |
| 2111 | 2137 | } }); |
| 2112 | 2138 | } |
| 2113 | 2139 | |
| ... | ... | @@ -2205,7 +2231,7 @@ fn fieldAccessStruct( |
| 2205 | 2231 | else => |e| return e, |
| 2206 | 2232 | }; |
| 2207 | 2233 | |
| 2208 | break :found_index for (struct_type.field_keys, 0..) |key, i| { | |
| 2234 | break :found_index for (struct_type.field_keys.get(s.ip), 0..) |key, i| { | |
| 2209 | 2235 | if (key == lookup) |
| 2210 | 2236 | break @as(u32, @intCast(i)); |
| 2211 | 2237 | } else null; |
| ... | ... | @@ -2341,7 +2367,7 @@ fn fieldAccessTuple( |
| 2341 | 2367 | |
| 2342 | 2368 | switch (lhs.decode()) { |
| 2343 | 2369 | .value => |value| { |
| 2344 | return value.toKey(s.ip).tuple_value.items[index].toAir(); | |
| 2370 | return value.toKey(s.ip).tuple_value.items.at(s.ip, index).toAir(); | |
| 2345 | 2371 | }, |
| 2346 | 2372 | .index => |lhs_index| { |
| 2347 | 2373 | try s.ensureAtRuntime(s.lazyNode(.lhs)); |
| ... | ... | @@ -2359,11 +2385,10 @@ fn postVisitFunctionPrototype(s: *Sema, reserve: FunctionReserve, return_type: ? |
| 2359 | 2385 | const tracked_inst = try s.ip.trackInst(s.gpa, s.file, s.frame.currentIndex()); |
| 2360 | 2386 | const func_type = try s.makeType(.{ |
| 2361 | 2387 | .function_type = .{ |
| 2362 | .param_types = reserve.items(.params), | |
| 2388 | .param_types = try s.ip.extra.appendSlice(s.gpa, reserve.items(.params)), | |
| 2363 | 2389 | .return_type = return_type, |
| 2364 | 2390 | }, |
| 2365 | 2391 | }); |
| 2366 | // TODO: make a dedicated function to insert a new function | |
| 2367 | 2392 | const func_value = try s.makeValue(.{ |
| 2368 | 2393 | .func = .{ |
| 2369 | 2394 | .ty = func_type, |
src/core/array.zig+122-72| ... | ... | @@ -81,24 +81,14 @@ pub const StoreKind = enum { |
| 81 | 81 | air, |
| 82 | 82 | js_tree, |
| 83 | 83 | |
| 84 | pub fn resolveStoreConst( | |
| 84 | pub fn resolveStore( | |
| 85 | 85 | comptime kind: StoreKind, |
| 86 | 86 | owner: anytype, |
| 87 | ) *const kind.ResolvedStore(@TypeOf(owner)) { | |
| 87 | ) kind.ResolvedStorePtr(@TypeOf(owner)) { | |
| 88 | 88 | return &owner.extra; |
| 89 | 89 | } |
| 90 | 90 | |
| 91 | pub fn resolveStoreMut( | |
| 92 | comptime kind: StoreKind, | |
| 93 | owner: anytype, | |
| 94 | ) *kind.ResolvedStore(@TypeOf(owner)) { | |
| 95 | return &owner.extra; | |
| 96 | } | |
| 97 | ||
| 98 | pub fn ResolvedStore( | |
| 99 | comptime kind: StoreKind, | |
| 100 | comptime Owner: type, | |
| 101 | ) type { | |
| 91 | pub fn ResolvedStore(kind: StoreKind, Owner: type) type { | |
| 102 | 92 | const ptr = @typeInfo(Owner).pointer; |
| 103 | 93 | assert(ptr.size == .One); |
| 104 | 94 | const mutability = brk: for (@typeInfo(ptr.child).@"struct".fields) |field| { |
| ... | ... | @@ -108,42 +98,32 @@ pub const StoreKind = enum { |
| 108 | 98 | } else unreachable; |
| 109 | 99 | return ExtraStore(kind, mutability); |
| 110 | 100 | } |
| 111 | }; | |
| 112 | ||
| 113 | fn ExtraWrap(comptime kind: StoreKind) type { | |
| 114 | return struct { | |
| 115 | pub fn Index(comptime T: type) type { | |
| 116 | return enum(u32) { | |
| 117 | _, | |
| 118 | 101 | |
| 119 | pub fn get(index: @This(), owner: anytype) T { | |
| 120 | return kind.resolveStoreConst(owner).get(T, @intFromEnum(index)); | |
| 121 | } | |
| 122 | ||
| 123 | pub fn set(index: @This(), owner: anytype, payload: T) void { | |
| 124 | return kind.resolveStoreMut(owner).set(T, @intFromEnum(index), payload); | |
| 125 | } | |
| 126 | ||
| 127 | /// Returns data with a trailing reader to read data stored immediately after | |
| 128 | /// the main data structure. What is stored should be documented on `T` | |
| 129 | pub fn getTrail(index: @This(), owner: anytype) struct { | |
| 130 | T, | |
| 131 | kind.ResolvedStore(@TypeOf(owner)).TrailReader, | |
| 132 | } { | |
| 133 | const advance = comptime extraSizeOf(T); | |
| 134 | return .{ | |
| 135 | index.get(owner), | |
| 136 | .{ .index = @intFromEnum(index) + advance }, | |
| 137 | }; | |
| 138 | } | |
| 102 | pub fn ResolvedStorePtr(kind: StoreKind, Owner: type) type { | |
| 103 | return kind.ItemPointer(Owner, .One, kind.ResolvedStore(Owner)); | |
| 104 | } | |
| 139 | 105 | |
| 140 | pub fn jsonStringify(index: @This(), jw: anytype) !void { | |
| 141 | try jw.write(@intFromEnum(index)); | |
| 142 | } | |
| 143 | }; | |
| 144 | } | |
| 145 | }; | |
| 146 | } | |
| 106 | pub fn ItemPointer( | |
| 107 | kind: StoreKind, | |
| 108 | Owner: type, | |
| 109 | size: std.builtin.Type.Pointer.Size, | |
| 110 | child: type, | |
| 111 | ) type { | |
| 112 | const ptr = @typeInfo(Owner).pointer; | |
| 113 | return @Type(.{ | |
| 114 | .pointer = .{ | |
| 115 | .size = size, | |
| 116 | .is_const = ptr.is_const or ResolvedStore(kind, Owner).mutability == .@"const", | |
| 117 | .is_volatile = false, | |
| 118 | .is_allowzero = false, | |
| 119 | .alignment = @alignOf(child), | |
| 120 | .address_space = .generic, | |
| 121 | .child = child, | |
| 122 | .sentinel = null, | |
| 123 | }, | |
| 124 | }); | |
| 125 | } | |
| 126 | }; | |
| 147 | 127 | |
| 148 | 128 | pub fn EncodedData(comptime Tag: type, backing_type: type) type { |
| 149 | 129 | return enum(backing_type) { |
| ... | ... | @@ -230,23 +210,89 @@ pub inline fn extraSizeOf(comptime T: type) usize { |
| 230 | 210 | }; |
| 231 | 211 | } |
| 232 | 212 | |
| 233 | // TODO: rename to Store | |
| 234 | pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutability) type { | |
| 213 | pub const ExtraStore = Store; | |
| 214 | ||
| 215 | /// A data structure to manage a `[]u32` with mixed data types. Provides | |
| 216 | /// `.Index` and `.Slice` to keep strongly typed indices to items within the | |
| 217 | /// store. | |
| 218 | pub fn Store(set_kind: StoreKind, set_mutability: Mutability) type { | |
| 219 | // Separate struct to avoid capturing set_mutability | |
| 220 | const wrappers = struct { | |
| 221 | pub const kind = set_kind; | |
| 222 | ||
| 223 | pub fn Index(T: type) type { | |
| 224 | return enum(u32) { | |
| 225 | _, | |
| 226 | ||
| 227 | pub fn get(index: @This(), owner: anytype) T { | |
| 228 | return kind.resolveStore(owner).get(T, @intFromEnum(index)); | |
| 229 | } | |
| 230 | ||
| 231 | pub fn set(index: @This(), owner: anytype, payload: T) void { | |
| 232 | return kind.resolveStore(owner).set(T, @intFromEnum(index), payload); | |
| 233 | } | |
| 234 | ||
| 235 | /// Returns data with a trailing reader to read data stored immediately after | |
| 236 | /// the main data structure. What is stored should be documented on `T` | |
| 237 | pub fn getTrail(index: @This(), owner: anytype) struct { | |
| 238 | T, | |
| 239 | kind.ResolvedStore(@TypeOf(owner)).TrailReader, | |
| 240 | } { | |
| 241 | const advance = comptime extraSizeOf(T); | |
| 242 | return .{ | |
| 243 | index.get(owner), | |
| 244 | .{ .index = @intFromEnum(index) + advance }, | |
| 245 | }; | |
| 246 | } | |
| 247 | ||
| 248 | pub fn jsonStringify(index: @This(), jw: anytype) !void { | |
| 249 | try jw.write(@intFromEnum(index)); | |
| 250 | } | |
| 251 | }; | |
| 252 | } | |
| 253 | ||
| 254 | /// An array of `T` existing within the `extra` array. | |
| 255 | /// This type exists to provide a struct with lifetime that is | |
| 256 | /// not invalidated when items are added to the `InternPool`. | |
| 257 | pub fn Slice(T: type) type { | |
| 258 | return struct { | |
| 259 | start: u32, | |
| 260 | len: u32, | |
| 261 | ||
| 262 | pub const empty: @This() = .{ | |
| 263 | .start = 0, | |
| 264 | .len = 0, | |
| 265 | }; | |
| 266 | ||
| 267 | pub fn get(slice: @This(), owner: anytype) kind.ItemPointer(@TypeOf(owner), .Slice, T) { | |
| 268 | return @ptrCast(kind.resolveStore(owner).list.items[slice.start..][0..slice.len]); | |
| 269 | } | |
| 270 | ||
| 271 | pub fn at(slice: @This(), owner: anytype, index: usize) T { | |
| 272 | return slice.get(owner)[index]; | |
| 273 | } | |
| 274 | }; | |
| 275 | } | |
| 276 | }; | |
| 277 | ||
| 235 | 278 | return struct { |
| 236 | list: List = .{}, | |
| 279 | const Self = @This(); | |
| 280 | ||
| 281 | list: Inner, | |
| 237 | 282 | |
| 238 | pub const empty: @This() = .{}; | |
| 283 | pub const empty: @This() = .{ .list = .empty }; | |
| 239 | 284 | |
| 240 | 285 | pub const kind = set_kind; |
| 241 | 286 | pub const mutability = set_mutability; |
| 242 | 287 | |
| 243 | const Store = @This(); | |
| 244 | ||
| 245 | pub const Index = ExtraWrap(kind).Index; | |
| 288 | pub const Index = wrappers.Index; | |
| 289 | pub const Slice = wrappers.Slice; | |
| 246 | 290 | |
| 247 | pub const List = switch (mutability) { | |
| 291 | pub const Inner = switch (mutability) { | |
| 248 | 292 | .@"const" => struct { |
| 249 | items: []const u32 = &.{}, | |
| 293 | items: []const u32, | |
| 294 | ||
| 295 | pub const empty = .{ .items = &.{} }; | |
| 250 | 296 | |
| 251 | 297 | pub fn deinit(slice: *@This(), gpa: Allocator) void { |
| 252 | 298 | gpa.free(slice.items); |
| ... | ... | @@ -255,7 +301,7 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil |
| 255 | 301 | .@"var" => std.ArrayListUnmanaged(u32), |
| 256 | 302 | }; |
| 257 | 303 | |
| 258 | pub fn deinit(store: *Store, gpa: Allocator) void { | |
| 304 | pub fn deinit(store: *Self, gpa: Allocator) void { | |
| 259 | 305 | store.list.deinit(gpa); |
| 260 | 306 | store.* = undefined; |
| 261 | 307 | } |
| ... | ... | @@ -263,12 +309,12 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil |
| 263 | 309 | pub const TrailReader = struct { |
| 264 | 310 | index: usize, |
| 265 | 311 | |
| 266 | pub fn read(trail: *TrailReader, ip: *const Store, comptime T: type) T { | |
| 312 | pub fn read(trail: *TrailReader, ip: *const Self, comptime T: type) T { | |
| 267 | 313 | defer trail.index += comptime extraSizeOf(T); |
| 268 | 314 | return ip.get(T, trail.index); |
| 269 | 315 | } |
| 270 | 316 | |
| 271 | pub fn at(trail: *const TrailReader, ip: *const Store, comptime T: type, index: u32) T { | |
| 317 | pub fn at(trail: *const TrailReader, ip: *const Self, comptime T: type, index: u32) T { | |
| 272 | 318 | return ip.get(T, trail.index + index); |
| 273 | 319 | } |
| 274 | 320 | |
| ... | ... | @@ -301,10 +347,10 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil |
| 301 | 347 | }; |
| 302 | 348 | |
| 303 | 349 | pub const TrailWriter = struct { |
| 304 | store: *Store, | |
| 350 | store: *Self, | |
| 305 | 351 | leftover: usize, |
| 306 | 352 | |
| 307 | pub fn init(store: *Store, len: usize) TrailWriter { | |
| 353 | pub fn init(store: *Self, len: usize) TrailWriter { | |
| 308 | 354 | return .{ .store = store, .leftover = len }; |
| 309 | 355 | } |
| 310 | 356 | |
| ... | ... | @@ -332,13 +378,13 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil |
| 332 | 378 | } |
| 333 | 379 | }; |
| 334 | 380 | |
| 335 | pub fn append(store: *Store, gpa: Allocator, comptime T: type, payload: T) Allocator.Error!Index(T) { | |
| 381 | pub fn append(store: *Self, gpa: Allocator, comptime T: type, payload: T) Allocator.Error!Index(T) { | |
| 336 | 382 | comptime assert(mutability == .@"var"); |
| 337 | 383 | try store.list.ensureUnusedCapacity(gpa, extraSizeOf(@TypeOf(payload))); |
| 338 | 384 | return store.appendAssumeCapacity(T, payload); |
| 339 | 385 | } |
| 340 | 386 | |
| 341 | pub fn appendAssumeCapacity(ip: *Store, comptime T: type, payload: T) Index(T) { | |
| 387 | pub fn appendAssumeCapacity(ip: *Self, comptime T: type, payload: T) Index(T) { | |
| 342 | 388 | comptime assert(mutability == .@"var"); |
| 343 | 389 | const extra_index: u32 = @intCast(ip.list.items.len); |
| 344 | 390 | ip.list.items.len += extraSizeOf(@TypeOf(payload)); |
| ... | ... | @@ -347,7 +393,7 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil |
| 347 | 393 | } |
| 348 | 394 | |
| 349 | 395 | pub fn appendTrailing( |
| 350 | store: *Store, | |
| 396 | store: *Self, | |
| 351 | 397 | gpa: Allocator, |
| 352 | 398 | comptime T: type, |
| 353 | 399 | payload: T, |
| ... | ... | @@ -365,32 +411,34 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil |
| 365 | 411 | } |
| 366 | 412 | |
| 367 | 413 | // TODO: make setAsU32 allow any type |
| 368 | pub fn setU32(store: *Store, index: usize, payload: u32) void { | |
| 414 | pub fn setU32(store: *Self, index: usize, payload: u32) void { | |
| 369 | 415 | comptime assert(mutability == .@"var"); |
| 370 | 416 | store.list.items[index] = payload; |
| 371 | 417 | } |
| 372 | 418 | |
| 373 | pub fn set(store: *Store, comptime T: type, index: usize, payload: T) void { | |
| 419 | pub fn set(store: *Self, comptime T: type, index: usize, payload: T) void { | |
| 374 | 420 | comptime assert(mutability == .@"var"); |
| 375 | 421 | setAsU32(store.list.items, T, index, payload); |
| 376 | 422 | } |
| 377 | 423 | |
| 378 | pub fn get(store: *const Store, comptime T: type, index: usize) T { | |
| 424 | pub fn get(store: *const Self, comptime T: type, index: usize) T { | |
| 379 | 425 | return getAsU32(store.list.items, T, index); |
| 380 | 426 | } |
| 381 | 427 | |
| 382 | pub fn toOwnedStore(store: *Store, gpa: Allocator) !ExtraStore(set_kind, .@"const") { | |
| 428 | pub fn toOwnedStore(store: *Self, gpa: Allocator) !ExtraStore(set_kind, .@"const") { | |
| 383 | 429 | comptime assert(mutability == .@"var"); |
| 384 | 430 | return .{ .list = .{ .items = try store.list.toOwnedSlice(gpa) } }; |
| 385 | 431 | } |
| 386 | 432 | |
| 387 | pub fn constant(store: *const Store) ExtraStore(set_kind, .@"const") { | |
| 433 | /// Returns a `const` store pointing at the mutable's data. | |
| 434 | /// Invalidated when the mutable store is mutated. | |
| 435 | pub fn constant(store: *const Self) ExtraStore(set_kind, .@"const") { | |
| 388 | 436 | return .{ .list = .{ .items = store.list.items } }; |
| 389 | 437 | } |
| 390 | 438 | |
| 391 | 439 | // TODO: Add some safety to the Index returned from this |
| 392 | 440 | /// Allocate a number of u32s into this store, but they are left uninitialized. |
| 393 | pub fn alloc(store: *Store, gpa: Allocator, len: usize) !u32 { | |
| 441 | pub fn alloc(store: *Self, gpa: Allocator, len: usize) !u32 { | |
| 394 | 442 | comptime assert(mutability == .@"var"); |
| 395 | 443 | const idx = store.list.items.len; |
| 396 | 444 | try store.list.ensureUnusedCapacity(gpa, len); |
| ... | ... | @@ -398,13 +446,15 @@ pub fn ExtraStore(comptime set_kind: StoreKind, comptime set_mutability: Mutabil |
| 398 | 446 | return @intCast(idx); |
| 399 | 447 | } |
| 400 | 448 | |
| 401 | pub fn appendSlice(store: *Store, gpa: Allocator, data: anytype) !u32 { | |
| 449 | pub fn appendSlice(store: *Self, gpa: Allocator, data: anytype) !Slice(std.meta.Child(@TypeOf(data))) { | |
| 402 | 450 | const idx = store.list.items.len; |
| 451 | comptime assert(@typeInfo(@TypeOf(data)).pointer.size == .Slice); | |
| 452 | comptime assert(@typeInfo(@TypeOf(data)).pointer.alignment == @alignOf(u32)); | |
| 403 | 453 | comptime assert(@sizeOf(@TypeOf(data[0])) == @sizeOf(u32)); |
| 404 | 454 | comptime assert(@alignOf(@TypeOf(data[0])) == @alignOf(u32)); |
| 405 | 455 | try store.list.appendSlice(gpa, @ptrCast(data)); |
| 406 | 456 | store.list.items.len += data.len; |
| 407 | return @intCast(idx); | |
| 457 | return .{ .start = @intCast(idx), .len = @intCast(data.len) }; | |
| 408 | 458 | } |
| 409 | 459 | }; |
| 410 | 460 | } |
src/core/js/Link.zig+17-8| ... | ... | @@ -284,8 +284,9 @@ fn printValue(link: *Link, value: InternPool.Value, level: Level, writer: anytyp |
| 284 | 284 | try writer.writeAll("{"); |
| 285 | 285 | |
| 286 | 286 | for ( |
| 287 | struct_value.ty.toStructType(&link.comp.intern_pool).?.field_keys, | |
| 288 | struct_value.field_values, | |
| 287 | struct_value.ty.toStructType(&link.comp.intern_pool).? | |
| 288 | .field_keys.get(&link.comp.intern_pool), | |
| 289 | struct_value.field_values.get(&link.comp.intern_pool), | |
| 289 | 290 | 0.., |
| 290 | 291 | ) |key, inner_value, i| { |
| 291 | 292 | if (i != 0) |
| ... | ... | @@ -305,7 +306,7 @@ fn printValue(link: *Link, value: InternPool.Value, level: Level, writer: anytyp |
| 305 | 306 | .array_value => |array_value| { |
| 306 | 307 | try writer.writeAll("["); |
| 307 | 308 | |
| 308 | for (array_value.items, 0..) |inner_value, i| { | |
| 309 | for (array_value.items.get(&link.comp.intern_pool), 0..) |inner_value, i| { | |
| 309 | 310 | if (i != 0) |
| 310 | 311 | try writer.writeAll(","); |
| 311 | 312 | |
| ... | ... | @@ -317,7 +318,7 @@ fn printValue(link: *Link, value: InternPool.Value, level: Level, writer: anytyp |
| 317 | 318 | .tuple_value => |tuple_value| { |
| 318 | 319 | try writer.writeAll("["); |
| 319 | 320 | |
| 320 | for (tuple_value.items, 0..) |inner_value, i| { | |
| 321 | for (tuple_value.items.get(&link.comp.intern_pool), 0..) |inner_value, i| { | |
| 321 | 322 | if (i != 0) |
| 322 | 323 | try writer.writeAll(","); |
| 323 | 324 | |
| ... | ... | @@ -327,7 +328,7 @@ fn printValue(link: *Link, value: InternPool.Value, level: Level, writer: anytyp |
| 327 | 328 | }, |
| 328 | 329 | |
| 329 | 330 | .external_value => |external_value| { |
| 330 | for (external_value.key, 0..) |part, i| { | |
| 331 | for (external_value.key.get(&link.comp.intern_pool), 0..) |part, i| { | |
| 331 | 332 | if (i != 0) try writer.writeAll("."); |
| 332 | 333 | try writer.writeAll(part.toSlice(&link.comp.intern_pool)); |
| 333 | 334 | } |
| ... | ... | @@ -477,11 +478,15 @@ fn printExprLevel( |
| 477 | 478 | }, |
| 478 | 479 | |
| 479 | 480 | .comma_chain => { |
| 481 | if (Level.comma.needsParens(level)) | |
| 482 | try writer.writeAll("("); | |
| 480 | 483 | const bin: Tree.IndexList = tree.nodeData(.comma_chain, node); |
| 481 | 484 | for (bin.slice(tree), 0..) |expr, i| { |
| 482 | 485 | if (i != 0) try writer.writeAll(", "); |
| 483 | 486 | try link.printExprLevel(tree, expr, .assignment, writer); |
| 484 | 487 | } |
| 488 | if (Level.comma.needsParens(level)) | |
| 489 | try writer.writeAll(")"); | |
| 485 | 490 | }, |
| 486 | 491 | |
| 487 | 492 | inline .negate, |
| ... | ... | @@ -503,9 +508,9 @@ fn printExprLevel( |
| 503 | 508 | try writer.writeAll("("); |
| 504 | 509 | try link.printExprLevel(tree, ternary.cond, .logical_or, writer); |
| 505 | 510 | try writer.writeAll(" ? "); |
| 506 | try link.printExpr(tree, data.yes, writer); | |
| 511 | try link.printExprLevel(tree, data.yes, .assignment, writer); | |
| 507 | 512 | try writer.writeAll(" : "); |
| 508 | try link.printExpr(tree, data.no, writer); | |
| 513 | try link.printExprLevel(tree, data.no, .assignment, writer); | |
| 509 | 514 | if (wrap) |
| 510 | 515 | try writer.writeAll(")"); |
| 511 | 516 | }, |
| ... | ... | @@ -518,7 +523,11 @@ fn printExprLevel( |
| 518 | 523 | const k = tree.nodeData(.plain_value, call.base).value.toKey(&link.comp.intern_pool); |
| 519 | 524 | break :brk k == .external_value and |
| 520 | 525 | k.external_value.key.len == 1 and |
| 521 | std.mem.eql(u8, k.external_value.key[0].toSlice(&link.comp.intern_pool), "eval"); | |
| 526 | std.mem.eql( | |
| 527 | u8, | |
| 528 | k.external_value.key.at(&link.comp.intern_pool, 0).toSlice(&link.comp.intern_pool), | |
| 529 | "eval", | |
| 530 | ); | |
| 522 | 531 | }) { |
| 523 | 532 | @branchHint(.unlikely); |
| 524 | 533 | try writer.writeAll("(0, eval)"); |
src/core/js/NodeGen.zig+19-14| ... | ... | @@ -47,8 +47,8 @@ pub fn init(gpa: Allocator, arena: Allocator, ip: *InternPool, air: Air) !NodeGe |
| 47 | 47 | .extern_symbols = .{}, |
| 48 | 48 | .top_level_value_deps = .{}, |
| 49 | 49 | .air_node_map = air_node_map, |
| 50 | .extra = .{}, | |
| 51 | .scratch = .{}, | |
| 50 | .extra = .empty, | |
| 51 | .scratch = .empty, | |
| 52 | 52 | .next_id = param_count, |
| 53 | 53 | .next_label = 0, |
| 54 | 54 | }; |
| ... | ... | @@ -100,7 +100,7 @@ pub fn build(c: *NodeGen) !void { |
| 100 | 100 | defer t.end(); |
| 101 | 101 | |
| 102 | 102 | assert(c.air.instTag(.main_block) == .block); // expected Air to start with block |
| 103 | const statements = c.air.instData(.block, .main_block).slice(&c.air); | |
| 103 | const statements = c.air.instData(.block, .main_block).get(&c.air); | |
| 104 | 104 | |
| 105 | 105 | const scratch_top = c.scratch.items.len; |
| 106 | 106 | defer c.scratch.shrinkRetainingCapacity(scratch_top); |
| ... | ... | @@ -301,7 +301,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void { |
| 301 | 301 | .field = field_name: { |
| 302 | 302 | break :field_name c.air.typeOfIndex(data.base, c.ip) |
| 303 | 303 | .toStructType(c.ip).? |
| 304 | .field_keys[data.field_index]; | |
| 304 | .field_keys.at(c.ip, data.field_index); | |
| 305 | 305 | }, |
| 306 | 306 | }); |
| 307 | 307 | try c.markExpression(inst, node); |
| ... | ... | @@ -338,7 +338,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void { |
| 338 | 338 | |
| 339 | 339 | const items = c.extra.list.items[start..][0..call_data.args.len]; |
| 340 | 340 | |
| 341 | for (call_data.args.slice(&c.air), items) |arg, *dest| { | |
| 341 | for (call_data.args.get(&c.air), items) |arg, *dest| { | |
| 342 | 342 | dest.* = @intFromEnum(try c.fetchExpression(arg)); |
| 343 | 343 | } |
| 344 | 344 | |
| ... | ... | @@ -457,7 +457,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void { |
| 457 | 457 | // |
| 458 | 458 | // This is also required for the main function, which cannot return |
| 459 | 459 | // anything. We don't want to emit return instructions here. |
| 460 | const main_insts = c.air.instData(.block, .main_block).slice(&c.air); | |
| 460 | const main_insts = c.air.instData(.block, .main_block).get(&c.air); | |
| 461 | 461 | if (main_insts[main_insts.len - 1] == inst) { |
| 462 | 462 | return; |
| 463 | 463 | } |
| ... | ... | @@ -472,7 +472,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void { |
| 472 | 472 | const operand = try c.fetchExpression(brk.value); |
| 473 | 473 | const block = &c.air_node_map[@intFromEnum(brk.block)].block; |
| 474 | 474 | |
| 475 | const block_insts = c.air.instData(.block, brk.block).slice(&c.air); | |
| 475 | const block_insts = c.air.instData(.block, brk.block).get(&c.air); | |
| 476 | 476 | if (block_insts[block_insts.len - 1] != inst) { |
| 477 | 477 | block.used = true; |
| 478 | 478 | } |
| ... | ... | @@ -499,7 +499,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void { |
| 499 | 499 | const store_offset = try c.extra.alloc(c.gpa, property_count * 2); |
| 500 | 500 | |
| 501 | 501 | for ( |
| 502 | struct_type.field_keys, | |
| 502 | struct_type.field_keys.get(c.ip), | |
| 503 | 503 | struct_init.valuesPtr(&c.air), |
| 504 | 504 | store_offset.., |
| 505 | 505 | store_offset + property_count.., |
| ... | ... | @@ -520,7 +520,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void { |
| 520 | 520 | .array_init => { |
| 521 | 521 | const array_init: Air.ArrayInit = c.air.instData(.array_init, inst); |
| 522 | 522 | |
| 523 | const items = array_init.list.get(&c.air).slice(&c.air); | |
| 523 | const items = array_init.list.get(&c.air).get(&c.air); | |
| 524 | 524 | const store_offset = try c.extra.alloc(c.gpa, items.len); |
| 525 | 525 | |
| 526 | 526 | for ( |
| ... | ... | @@ -653,7 +653,12 @@ fn valueToExpression(c: *NodeGen, v: Value) !Node.Index { |
| 653 | 653 | |
| 654 | 654 | .external_value => { |
| 655 | 655 | const external = v.toKey(c.ip).external_value; |
| 656 | try c.extern_symbols.put(c.gpa, external.key[0].toString().withLen(external.key[0].length(c.ip)), {}); | |
| 656 | const first_key = external.key.at(c.ip, 0); | |
| 657 | try c.extern_symbols.put( | |
| 658 | c.gpa, | |
| 659 | first_key.toString().withLen(first_key.length(c.ip)), | |
| 660 | {}, | |
| 661 | ); | |
| 657 | 662 | return try c.add(.plain_value, .{ .value = v }); |
| 658 | 663 | }, |
| 659 | 664 | |
| ... | ... | @@ -730,7 +735,7 @@ fn codeGenBranch(c: *NodeGen, inst: Air.Inst.Ref, temporary: ?Node.Index) !?Bran |
| 730 | 735 | }); |
| 731 | 736 | |
| 732 | 737 | const block: Air.IndexList = c.air.instData(.block, i); |
| 733 | for (block.slice(&c.air)) |item| { | |
| 738 | for (block.get(&c.air)) |item| { | |
| 734 | 739 | try c.codeGenInst(item); |
| 735 | 740 | } |
| 736 | 741 | |
| ... | ... | @@ -781,7 +786,7 @@ fn codeGenBlock(c: *NodeGen, inst: Air.Inst.Index) !void { |
| 781 | 786 | }; |
| 782 | 787 | const block: Air.IndexList = c.air.instData(.block, inst); |
| 783 | 788 | |
| 784 | for (block.slice(&c.air)) |item| { | |
| 789 | for (block.get(&c.air)) |item| { | |
| 785 | 790 | try c.codeGenInst(item); |
| 786 | 791 | } |
| 787 | 792 | |
| ... | ... | @@ -814,7 +819,7 @@ fn codeGenBlockAsExpression(c: *NodeGen, inst: Air.Inst.Index) !Node.Index { |
| 814 | 819 | .block = .{ .index = @intCast(scratch_top) }, |
| 815 | 820 | }; |
| 816 | 821 | const block: Air.IndexList = c.air.instData(.block, inst); |
| 817 | const instructions = block.slice(&c.air); | |
| 822 | const instructions = block.get(&c.air); | |
| 818 | 823 | for (instructions[0 .. instructions.len - 1]) |item| { |
| 819 | 824 | try c.codeGenInst(item); |
| 820 | 825 | } |
| ... | ... | @@ -885,7 +890,7 @@ fn canLowerToExpression(c: *const NodeGen, inst: Air.Inst.Ref) bool { |
| 885 | 890 | // are lowerable. The break at the end just becomes the result. |
| 886 | 891 | .block => { |
| 887 | 892 | const block: Air.IndexList = c.air.instData(.block, index); |
| 888 | const items = block.slice(&c.air); | |
| 893 | const items = block.get(&c.air); | |
| 889 | 894 | for (items[0 .. items.len - 1]) |item| { |
| 890 | 895 | if (c.air.instFlags(item).uses == .multi) |
| 891 | 896 | return false; |
src/manual/generate_manual.zig+11-3| ... | ... | @@ -70,7 +70,7 @@ pub fn main() !void { |
| 70 | 70 | .contents = contents.items, |
| 71 | 71 | .navigation = header.data.items, |
| 72 | 72 | .nav_h1 = "Ix Language", |
| 73 | .repository = "https://github.com/paperdave/wl", | |
| 73 | .repository = "https://github.com/paperdave/ix", | |
| 74 | 74 | .style = minified_style, |
| 75 | 75 | }); |
| 76 | 76 | |
| ... | ... | @@ -83,7 +83,7 @@ pub fn main() !void { |
| 83 | 83 | std.debug.lockStdErr(); |
| 84 | 84 | std.debug.unlockStdErr(); |
| 85 | 85 | |
| 86 | std.process.exit(0); | |
| 86 | std.process.exit(if (header.had_signaled) 1 else 0); | |
| 87 | 87 | } |
| 88 | 88 | |
| 89 | 89 | const BlockType = enum { |
| ... | ... | @@ -190,6 +190,8 @@ const HeaderWriter = struct { |
| 190 | 190 | |
| 191 | 191 | has_closed_li: bool = true, |
| 192 | 192 | |
| 193 | had_signaled: bool = false, | |
| 194 | ||
| 193 | 195 | fn add(header: *HeaderWriter, alloc: Allocator, name: []const u8, id: []const u8, level: u8) !void { |
| 194 | 196 | const w = header.data.writer(alloc); |
| 195 | 197 | |
| ... | ... | @@ -440,6 +442,10 @@ fn processMarkdown( |
| 440 | 442 | |
| 441 | 443 | try build.collectOutput(&out, &err, std.math.maxInt(usize)); |
| 442 | 444 | const result = try build.wait(); |
| 445 | if (result == .Signal) { | |
| 446 | std.debug.print("{s}\n", .{err.items}); | |
| 447 | header.had_signaled = true; | |
| 448 | } | |
| 443 | 449 | if (result != .Exited or result.Exited != 0) { |
| 444 | 450 | try err.writer().print("[Process {s} with {d}]", .{ |
| 445 | 451 | switch (result) { |
| ... | ... | @@ -530,7 +536,9 @@ fn processMarkdown( |
| 530 | 536 | } |
| 531 | 537 | return e; |
| 532 | 538 | }; |
| 533 | ||
| 539 | if (run_result == .Signal) { | |
| 540 | header.had_signaled = true; | |
| 541 | } | |
| 534 | 542 | if (run_result != .Exited or run_result.Exited != 0) { |
| 535 | 543 | try run_err.writer().print("[Process {s} with {d}]", .{ |
| 536 | 544 | switch (run_result) { |