13 files changed, 298 insertions(+), 56 deletions(-)
CHANGELOG.md+1| ... | ... | @@ -2,6 +2,7 @@ |
| 2 | 2 | |
| 3 | 3 | - feat: clarify "defined runtime representation" and "can be represented at runtime" |
| 4 | 4 | - feat: implement inferred structs + result type semantics |
| 5 | - feat: add `--dump-state=./filename.json` to dump compiler state as JSON | |
| 5 | 6 | - chore: remove group expressions, use single expression blocks instead |
| 6 | 7 | - fix(sema): fix passing structs as function params |
| 7 | 8 | - fix: diagnostic box drawing characters line up after line 9 |
build.zig+8-2| ... | ... | @@ -92,7 +92,6 @@ pub fn build(b: *std.Build) !void { |
| 92 | 92 | .root_source_file = b.path("src/manual/generate-man.zig"), |
| 93 | 93 | .target = native_target, |
| 94 | 94 | .optimize = .Debug, |
| 95 | .link_libc = true, | |
| 96 | 95 | }); |
| 97 | 96 | manual_generator.root_module.addImport("build_options", native_debug.opts_mod); |
| 98 | 97 | manual_generator.root_module.addImport("core", native_debug.core); |
| ... | ... | @@ -204,10 +203,11 @@ fn buildWithTarget( |
| 204 | 203 | const opts_mod = opts.createModule(); |
| 205 | 204 | |
| 206 | 205 | // Core |
| 207 | const core = b.addModule("compiler", .{ | |
| 206 | const core = b.addModule("core", .{ | |
| 208 | 207 | .root_source_file = b.path("src/core/mod.zig"), |
| 209 | 208 | .optimize = optimize, |
| 210 | 209 | .target = target, |
| 210 | .strip = false, | |
| 211 | 211 | }); |
| 212 | 212 | core.addImport("build_options", opts_mod); |
| 213 | 213 | core.addImport("tracer", tracer.module("tracer")); |
| ... | ... | @@ -220,6 +220,7 @@ fn buildWithTarget( |
| 220 | 220 | .optimize = optimize, |
| 221 | 221 | .use_lld = use_lld, |
| 222 | 222 | .use_llvm = use_llvm, |
| 223 | .strip = false, | |
| 223 | 224 | }); |
| 224 | 225 | core_tests.root_module.addImport("build_options", opts_mod); |
| 225 | 226 | core_tests.root_module.addImport("tracer", tracer.module("tracer")); |
| ... | ... | @@ -233,6 +234,8 @@ fn buildWithTarget( |
| 233 | 234 | .optimize = optimize, |
| 234 | 235 | .use_lld = use_lld, |
| 235 | 236 | .use_llvm = use_llvm, |
| 237 | .strip = false, | |
| 238 | .omit_frame_pointer = false, | |
| 236 | 239 | }); |
| 237 | 240 | compiler_exe.root_module.addImport("build_options", opts_mod); |
| 238 | 241 | compiler_exe.root_module.addImport("core", core); |
| ... | ... | @@ -246,6 +249,9 @@ fn buildWithTarget( |
| 246 | 249 | .optimize = optimize, |
| 247 | 250 | .use_lld = use_lld, |
| 248 | 251 | .use_llvm = use_llvm, |
| 252 | .strip = false, | |
| 253 | .omit_frame_pointer = false, | |
| 254 | .unwind_tables = false, | |
| 249 | 255 | }); |
| 250 | 256 | lsp_exe.root_module.addImport("build_options", opts_mod); |
| 251 | 257 | lsp_exe.root_module.addImport("core", core); |
src/core/Air.Dump.zig+1-1| ... | ... | @@ -143,7 +143,7 @@ pub const State = struct { |
| 143 | 143 | try tty.setColor(w, .reset); |
| 144 | 144 | try w.writeAll(")"); |
| 145 | 145 | }, |
| 146 | inline .call, .new => |t| { | |
| 146 | inline .call, .js_new => |t| { | |
| 147 | 147 | const call: Air.Call = air.instData(t, inst); |
| 148 | 148 | const call_data = call.call_data.get(air); |
| 149 | 149 | try w.writeAll("("); |
src/core/Air.zig+5-5| ... | ... | @@ -16,7 +16,7 @@ pub const Inst = struct { |
| 16 | 16 | block, |
| 17 | 17 | js_global_ref, |
| 18 | 18 | call, |
| 19 | new, | |
| 19 | js_new, | |
| 20 | 20 | @"break", |
| 21 | 21 | @"if", |
| 22 | 22 | arg, |
| ... | ... | @@ -53,7 +53,7 @@ pub const Inst = struct { |
| 53 | 53 | .js_global_ref => InternPool.String.WithLen, |
| 54 | 54 | .@"break" => Break, |
| 55 | 55 | .@"if" => If, |
| 56 | .call, .new => Call, | |
| 56 | .call, .js_new => Call, | |
| 57 | 57 | .arg => Arg, |
| 58 | 58 | .memory => Memory, |
| 59 | 59 | .store => Store, |
| ... | ... | @@ -323,7 +323,7 @@ pub fn typeOf(air: *const Air, ref: Inst.Ref, ip: *const InternPool) InternPool. |
| 323 | 323 | pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) InternPool.Type { |
| 324 | 324 | return switch (air.instTag(index)) { |
| 325 | 325 | // These values are by definition, opaque |
| 326 | .js_global_ref, .new => .@"opaque", | |
| 326 | .js_global_ref, .js_new => .@"opaque", | |
| 327 | 327 | |
| 328 | 328 | // These operations always produce known types |
| 329 | 329 | .lt, .gt, .eq, .bool_not => .bool, |
| ... | ... | @@ -375,7 +375,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In |
| 375 | 375 | .field_struct => { |
| 376 | 376 | const inst = air.instData(.field_struct, index); |
| 377 | 377 | const base_type = air.typeOfIndex(inst.base, ip) |
| 378 | .toStructType(ip) orelse unreachable; // not a struct | |
| 378 | .toStructType(ip) orelse unreachable; // field_struct demands struct type | |
| 379 | 379 | return base_type.field_types[inst.field_index]; |
| 380 | 380 | }, |
| 381 | 381 | |
| ... | ... | @@ -383,7 +383,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In |
| 383 | 383 | .index => { |
| 384 | 384 | const inst = air.instData(.index, index); |
| 385 | 385 | const base_type = air.typeOf(inst.lhs, ip) |
| 386 | .toArrayType(ip) orelse unreachable; // not an array | |
| 386 | .toArrayType(ip) orelse unreachable; // index demands array type | |
| 387 | 387 | return base_type.item_type; |
| 388 | 388 | }, |
| 389 | 389 | }; |
src/core/Comp.zig+132-20| ... | ... | @@ -8,7 +8,8 @@ gpa: Allocator, |
| 8 | 8 | /// Stores all Type and Value objects. |
| 9 | 9 | intern_pool: InternPool = .{}, |
| 10 | 10 | /// All files in the compilation |
| 11 | files: std.StringArrayHashMapUnmanaged(*File) = .{}, | |
| 11 | /// TODO: turn this into a HashMap(*File, void) as File owns it's key | |
| 12 | files: std.StringHashMapUnmanaged(*File) = .{}, | |
| 12 | 13 | |
| 13 | 14 | options: Options = .{}, |
| 14 | 15 | |
| ... | ... | @@ -20,8 +21,9 @@ pub fn init(comp: *Comp) !void { |
| 20 | 21 | |
| 21 | 22 | pub fn deinit(comp: *Comp) void { |
| 22 | 23 | comp.intern_pool.deinit(comp.gpa); |
| 23 | for (comp.files.values()) |file| { | |
| 24 | file.deinit(comp.gpa); | |
| 24 | var it = comp.files.valueIterator(); | |
| 25 | while (it.next()) |file| { | |
| 26 | file.*.deinit(comp.gpa); | |
| 25 | 27 | } |
| 26 | 28 | comp.files.deinit(comp.gpa); |
| 27 | 29 | comp.backend.deinit(comp); |
| ... | ... | @@ -96,7 +98,7 @@ pub const File = struct { |
| 96 | 98 | /// TODO: change this to a URL |
| 97 | 99 | file_path: []const u8, |
| 98 | 100 | |
| 99 | root_namespace: Decl.Index.Optional, | |
| 101 | root_namespace: Namespace.Index.Optional, | |
| 100 | 102 | status: enum { |
| 101 | 103 | never_loaded, |
| 102 | 104 | /// A failure occurred while loading the file. Retrying might succeed. |
| ... | ... | @@ -249,6 +251,36 @@ pub const File = struct { |
| 249 | 251 | file.unloadSource(gpa); |
| 250 | 252 | gpa.destroy(file); |
| 251 | 253 | } |
| 254 | ||
| 255 | pub fn fmtJson(file: *const File, comp: *const Comp) JsonFormatter { | |
| 256 | return .{ .file = file, .comp = comp }; | |
| 257 | } | |
| 258 | ||
| 259 | const JsonFormatter = struct { | |
| 260 | file: *const File, | |
| 261 | comp: *const Comp, | |
| 262 | ||
| 263 | pub fn jsonStringify(ctx: JsonFormatter, json_writer: anytype) !void { | |
| 264 | // file path is already written | |
| 265 | const jw = core.jsonWriterCast(json_writer); | |
| 266 | try jw.beginObject(); | |
| 267 | try jw.objectField("path_digest"); | |
| 268 | try if (ctx.file.path_digest) |digest| | |
| 269 | jw.write(std.fmt.bytesToHex(digest, .lower)) | |
| 270 | else | |
| 271 | jw.write(null); | |
| 272 | try jw.objectField("status"); | |
| 273 | try jw.write(ctx.file.status); | |
| 274 | try jw.objectField("root_namespace"); | |
| 275 | if (ctx.file.root_namespace.unwrap()) |ns_index| { | |
| 276 | const ns = ctx.comp.intern_pool.namespacePtrConst(ns_index); | |
| 277 | try jw.write(ns.fmtJson(ctx.comp)); | |
| 278 | } else { | |
| 279 | try jw.write(null); | |
| 280 | } | |
| 281 | try jw.endObject(); | |
| 282 | } | |
| 283 | }; | |
| 252 | 284 | }; |
| 253 | 285 | |
| 254 | 286 | /// A declaration is a named value which also represents the smallest unit of |
| ... | ... | @@ -328,12 +360,43 @@ pub const Decl = struct { |
| 328 | 360 | }; |
| 329 | 361 | } |
| 330 | 362 | |
| 331 | pub fn deinit(decl: *Decl, gpa: Allocator) void { | |
| 332 | _ = gpa; // autofix | |
| 333 | defer decl.* = undefined; | |
| 334 | // if (decl.codegen) |*cg| cg.deinit(gpa); | |
| 363 | pub fn fmtJson(decl: *const Decl, comp: *const Comp) JsonFormatter { | |
| 364 | return .{ .decl = decl, .comp = comp }; | |
| 335 | 365 | } |
| 336 | 366 | |
| 367 | const JsonFormatter = struct { | |
| 368 | decl: *const Decl, | |
| 369 | comp: *const Comp, | |
| 370 | ||
| 371 | pub fn jsonStringify(ctx: JsonFormatter, json_writer: anytype) !void { | |
| 372 | const decl = ctx.decl; | |
| 373 | const comp = ctx.comp; | |
| 374 | ||
| 375 | const jw = core.jsonWriterCast(json_writer); | |
| 376 | try jw.beginObject(); | |
| 377 | ||
| 378 | try jw.objectField("name"); | |
| 379 | try jw.write(decl.name.toSlice(&comp.intern_pool)); | |
| 380 | try jw.objectField("analysis"); | |
| 381 | try jw.write(decl.analysis); | |
| 382 | try jw.objectField("teg_decl_index"); | |
| 383 | try jw.write(decl.teg_decl_index.get(&comp.intern_pool)); | |
| 384 | try jw.objectField("value"); | |
| 385 | if (decl.raw_value) |val| { | |
| 386 | var buf: [8192]u8 = undefined; | |
| 387 | try jw.print("", .{}); | |
| 388 | try jw.stream.print("[{d}, ", .{@intFromEnum(val)}); | |
| 389 | try std.json.encodeJsonString( | |
| 390 | std.fmt.bufPrint(&buf, "{}", .{val.dump(&comp.intern_pool)}) catch &buf, | |
| 391 | .{}, | |
| 392 | jw.stream, | |
| 393 | ); | |
| 394 | try jw.stream.print("]", .{}); | |
| 395 | } | |
| 396 | try jw.endObject(); | |
| 397 | } | |
| 398 | }; | |
| 399 | ||
| 337 | 400 | pub const Index = InternPool.DeclIndex; |
| 338 | 401 | }; |
| 339 | 402 | |
| ... | ... | @@ -348,8 +411,6 @@ pub const Namespace = struct { |
| 348 | 411 | file_scope: *File, |
| 349 | 412 | /// Direct children of the namespace. |
| 350 | 413 | /// Declaration order is preserved via entry order. |
| 351 | /// These are only declarations named directly by the AST; anonymous | |
| 352 | /// declarations are not stored here. | |
| 353 | 414 | decls: std.ArrayHashMapUnmanaged(Decl.Index, void, DeclContext, true) = .{}, |
| 354 | 415 | |
| 355 | 416 | pub const DeclContext = struct { |
| ... | ... | @@ -400,6 +461,34 @@ pub const Namespace = struct { |
| 400 | 461 | return ns.decls.getKeyAdapted(name, Namespace.DeclNameAdapter{ .comp = comp }); |
| 401 | 462 | } |
| 402 | 463 | |
| 464 | pub fn fmtJson(ns: *const Namespace, comp: *const Comp) JsonFormatter { | |
| 465 | return .{ .ns = ns, .comp = comp }; | |
| 466 | } | |
| 467 | ||
| 468 | const JsonFormatter = struct { | |
| 469 | ns: *const Namespace, | |
| 470 | comp: *const Comp, | |
| 471 | ||
| 472 | pub fn jsonStringify(ctx: JsonFormatter, json_writer: anytype) !void { | |
| 473 | const ns = ctx.ns; | |
| 474 | const comp = ctx.comp; | |
| 475 | ||
| 476 | const jw = core.jsonWriterCast(json_writer); | |
| 477 | try jw.beginObject(); | |
| 478 | // try jw.objectField("parent"); | |
| 479 | // try if (ns.parent.unwrap()) |p| jw.write(@intFromEnum(p)) else jw.write(null); | |
| 480 | try jw.objectField("decls"); | |
| 481 | try jw.beginObject(); | |
| 482 | for (ns.decls.keys()) |decl_index| { | |
| 483 | const decl = comp.intern_pool.declPtrConst(decl_index); | |
| 484 | try jw.objectField(decl.name.toSlice(&comp.intern_pool)); | |
| 485 | try jw.write(decl.fmtJson(comp)); | |
| 486 | } | |
| 487 | try jw.endObject(); | |
| 488 | try jw.endObject(); | |
| 489 | } | |
| 490 | }; | |
| 491 | ||
| 403 | 492 | pub const Index = InternPool.NamespaceIndex; |
| 404 | 493 | }; |
| 405 | 494 | |
| ... | ... | @@ -408,10 +497,13 @@ pub const Namespace = struct { |
| 408 | 497 | pub fn indexTegModule(comp: *Comp, file: *File, module_index: Teg.Inst.Index) !Namespace.Index { |
| 409 | 498 | const teg = file.teg.?; |
| 410 | 499 | |
| 500 | assert(file.root_namespace == .none); | |
| 501 | ||
| 411 | 502 | const ns = try comp.intern_pool.createNamespace(comp.gpa, .{ |
| 412 | 503 | .parent = .none, |
| 413 | 504 | .file_scope = file, |
| 414 | 505 | }); |
| 506 | file.root_namespace = ns.toOptional(); | |
| 415 | 507 | const ns_ptr = comp.intern_pool.namespacePtr(ns); |
| 416 | 508 | errdefer comp.intern_pool.destroyNamespace(comp.gpa, ns); |
| 417 | 509 | |
| ... | ... | @@ -450,6 +542,8 @@ const Options = struct { |
| 450 | 542 | dump_ir: bool = false, |
| 451 | 543 | }; |
| 452 | 544 | |
| 545 | /// The compiler backend is stored separately from the compilation, and | |
| 546 | /// interaction is done via this static dispatch contract. | |
| 453 | 547 | pub const Backend = union(enum) { |
| 454 | 548 | js: *@import("js/Js.zig"), |
| 455 | 549 | |
| ... | ... | @@ -485,6 +579,23 @@ pub const Backend = union(enum) { |
| 485 | 579 | pub const Tag = std.meta.FieldEnum(Backend); |
| 486 | 580 | }; |
| 487 | 581 | |
| 582 | pub fn jsonStringify(comp: *const Comp, json_writer: anytype) !void { | |
| 583 | const jw = core.jsonWriterCast(json_writer); | |
| 584 | ||
| 585 | try jw.beginObject(); | |
| 586 | try jw.objectField("files"); | |
| 587 | try jw.beginObject(); | |
| 588 | var it = comp.files.valueIterator(); | |
| 589 | while (it.next()) |entry| { | |
| 590 | try jw.objectField(entry.*.file_path); | |
| 591 | try jw.write(entry.*.fmtJson(comp)); | |
| 592 | } | |
| 593 | try jw.endObject(); | |
| 594 | try jw.objectField("intern_pool"); | |
| 595 | try jw.write(comp.intern_pool); | |
| 596 | try jw.endObject(); | |
| 597 | } | |
| 598 | ||
| 488 | 599 | const Comp = @This(); |
| 489 | 600 | |
| 490 | 601 | const std = @import("std"); |
| ... | ... | @@ -493,15 +604,16 @@ const assert = std.debug.assert; |
| 493 | 604 | const Stat = std.Build.Cache.File.Stat; |
| 494 | 605 | const log = std.log.scoped(.comp); |
| 495 | 606 | |
| 496 | const InternPool = @import("InternPool.zig"); | |
| 497 | ||
| 498 | const Ast = @import("Ast.zig"); | |
| 499 | const Air = @import("Air.zig"); | |
| 500 | const Teg = @import("Teg.zig"); | |
| 501 | const Cache = @import("Cache.zig"); | |
| 502 | const Sema = @import("Sema.zig"); | |
| 503 | const Transform = @import("Transform.zig"); | |
| 504 | const Report = @import("Report.zig"); | |
| 505 | const Parse = @import("Parse.zig"); | |
| 607 | const core = @import("mod.zig"); | |
| 608 | const InternPool = core.InternPool; | |
| 609 | ||
| 610 | const Ast = core.Ast; | |
| 611 | const Air = core.Air; | |
| 612 | const Teg = core.Teg; | |
| 613 | const Cache = core.Cache; | |
| 614 | const Sema = core.Sema; | |
| 615 | const Transform = core.Transform; | |
| 616 | const Report = core.Report; | |
| 617 | const Parse = core.Parse; | |
| 506 | 618 | |
| 507 | 619 | const tracer = @import("tracer"); |
src/core/InternPool.zig+93-12| ... | ... | @@ -714,14 +714,21 @@ pub const TrackedInst = extern struct { |
| 714 | 714 | pub const Index = enum(u32) { |
| 715 | 715 | _, |
| 716 | 716 | pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Teg.Inst.Index { |
| 717 | return ip.tracked_insts.keys()[@intFromEnum(i)].inst; | |
| 717 | return i.get(ip).inst; | |
| 718 | 718 | } |
| 719 | ||
| 720 | pub fn get(i: TrackedInst.Index, ip: *const InternPool) TrackedInst { | |
| 721 | return ip.tracked_insts.keys()[@intFromEnum(i)]; | |
| 722 | } | |
| 723 | ||
| 719 | 724 | pub fn toOptional(i: TrackedInst.Index) Optional { |
| 720 | 725 | return @enumFromInt(@intFromEnum(i)); |
| 721 | 726 | } |
| 727 | ||
| 722 | 728 | pub const Optional = enum(u32) { |
| 723 | 729 | none = std.math.maxInt(u32), |
| 724 | 730 | _, |
| 731 | ||
| 725 | 732 | pub fn unwrap(opt: Optional) ?TrackedInst.Index { |
| 726 | 733 | return switch (opt) { |
| 727 | 734 | .none => null, |
| ... | ... | @@ -730,6 +737,16 @@ pub const TrackedInst = extern struct { |
| 730 | 737 | } |
| 731 | 738 | }; |
| 732 | 739 | }; |
| 740 | ||
| 741 | pub fn jsonStringify(i: *const TrackedInst, json_writer: anytype) !void { | |
| 742 | const jw = core.jsonWriterCast(json_writer); | |
| 743 | try jw.beginObject(); | |
| 744 | try jw.objectField("path_digest"); | |
| 745 | try jw.write(std.fmt.bytesToHex(i.path_digest, .lower)); | |
| 746 | try jw.objectField("inst"); | |
| 747 | try jw.write(@intFromEnum(i.inst)); | |
| 748 | try jw.endObject(); | |
| 749 | } | |
| 733 | 750 | }; |
| 734 | 751 | |
| 735 | 752 | pub const DeclIndex = enum(u32) { |
| ... | ... | @@ -757,7 +774,7 @@ pub const DeclIndex = enum(u32) { |
| 757 | 774 | pub const NamespaceIndex = enum(u32) { |
| 758 | 775 | _, |
| 759 | 776 | |
| 760 | pub fn toOptional(i: DeclIndex) Optional { | |
| 777 | pub fn toOptional(i: NamespaceIndex) Optional { | |
| 761 | 778 | return @enumFromInt(@intFromEnum(i)); |
| 762 | 779 | } |
| 763 | 780 | |
| ... | ... | @@ -1096,11 +1113,6 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void { |
| 1096 | 1113 | // ip.limbs.deinit(gpa); |
| 1097 | 1114 | ip.string_bytes.deinit(gpa); |
| 1098 | 1115 | |
| 1099 | var decls = ip.allocated_decls.iterator(0); | |
| 1100 | while (decls.next()) |decl| { | |
| 1101 | decl.deinit(gpa); | |
| 1102 | } | |
| 1103 | ||
| 1104 | 1116 | ip.allocated_decls.deinit(gpa); |
| 1105 | 1117 | ip.decls_free_list.deinit(gpa); |
| 1106 | 1118 | |
| ... | ... | @@ -1346,11 +1358,12 @@ fn getOrPutTrailingString( |
| 1346 | 1358 | return @enumFromInt(str_index); |
| 1347 | 1359 | }, |
| 1348 | 1360 | } |
| 1349 | const gop = try ip.string_table.getOrPutContextAdapted(gpa, key, std.hash_map.StringIndexAdapter{ | |
| 1350 | .bytes = string_bytes, | |
| 1351 | }, std.hash_map.StringIndexContext{ | |
| 1352 | .bytes = string_bytes, | |
| 1353 | }); | |
| 1361 | const gop = try ip.string_table.getOrPutContextAdapted( | |
| 1362 | gpa, | |
| 1363 | key, | |
| 1364 | std.hash_map.StringIndexAdapter{ .bytes = string_bytes }, | |
| 1365 | std.hash_map.StringIndexContext{ .bytes = string_bytes }, | |
| 1366 | ); | |
| 1354 | 1367 | if (gop.found_existing) { |
| 1355 | 1368 | string_bytes.shrinkRetainingCapacity(str_index); |
| 1356 | 1369 | return @enumFromInt(gop.key_ptr.*); |
| ... | ... | @@ -1445,6 +1458,74 @@ pub fn destroyNamespace(ip: *InternPool, gpa: Allocator, index: NamespaceIndex) |
| 1445 | 1458 | }; |
| 1446 | 1459 | } |
| 1447 | 1460 | |
| 1461 | pub fn jsonStringify(ip: *const InternPool, json_writer: anytype) !void { | |
| 1462 | const jw = core.jsonWriterCast(json_writer); | |
| 1463 | try jw.beginObject(); | |
| 1464 | { | |
| 1465 | try jw.objectField("values"); | |
| 1466 | try jw.beginArray(); | |
| 1467 | const hashes: []u32 = ip.map.entries.items(.hash); | |
| 1468 | const values = ip.items.slice(); | |
| 1469 | for ( | |
| 1470 | @as([]Tag, values.items(.tag)), | |
| 1471 | @as([]EncodedData, values.items(.data)), | |
| 1472 | hashes, | |
| 1473 | 0.., | |
| 1474 | ) |tag, encoded_data, hash, i| { | |
| 1475 | if (tag == .removed) { | |
| 1476 | try jw.write(null); | |
| 1477 | continue; | |
| 1478 | } | |
| 1479 | try jw.beginObject(); | |
| 1480 | try jw.objectField("pretty"); | |
| 1481 | { | |
| 1482 | var buf: [8192]u8 = undefined; | |
| 1483 | try jw.print("", .{}); | |
| 1484 | try jw.stream.print("[{d}, ", .{i}); | |
| 1485 | try std.json.encodeJsonString(std.fmt.bufPrint( | |
| 1486 | &buf, | |
| 1487 | "{}", | |
| 1488 | .{@as(Value, @enumFromInt(i)).dump(ip)}, | |
| 1489 | ) catch &buf, .{}, jw.stream); | |
| 1490 | try jw.stream.print("]", .{}); | |
| 1491 | } | |
| 1492 | try jw.objectField("tag"); | |
| 1493 | try jw.write(@tagName(tag)); | |
| 1494 | switch (tag) { | |
| 1495 | .removed => unreachable, | |
| 1496 | inline else => |comptime_tag| { | |
| 1497 | const data = encoded_data.decode(comptime_tag, tag); | |
| 1498 | _ = data; | |
| 1499 | // try jw.objectField("data"); | |
| 1500 | // try jw.write(data); | |
| 1501 | }, | |
| 1502 | } | |
| 1503 | try jw.objectField("hash"); | |
| 1504 | try jw.write(hash); | |
| 1505 | try jw.endObject(); | |
| 1506 | } | |
| 1507 | try jw.endArray(); | |
| 1508 | } | |
| 1509 | { | |
| 1510 | try jw.objectField("string_bytes"); | |
| 1511 | try jw.write(ip.string_bytes.items); | |
| 1512 | } | |
| 1513 | { | |
| 1514 | try jw.objectField("string_table"); | |
| 1515 | try jw.beginArray(); | |
| 1516 | var it = ip.string_table.keyIterator(); | |
| 1517 | while (it.next()) |k| { | |
| 1518 | try jw.write(k.*); | |
| 1519 | } | |
| 1520 | try jw.endArray(); | |
| 1521 | } | |
| 1522 | { | |
| 1523 | try jw.objectField("tracked_insts"); | |
| 1524 | try jw.write(ip.tracked_insts.entries.items(.key)); | |
| 1525 | } | |
| 1526 | try jw.endObject(); | |
| 1527 | } | |
| 1528 | ||
| 1448 | 1529 | const InternPool = @This(); |
| 1449 | 1530 | |
| 1450 | 1531 | const std = @import("std"); |
src/core/Sema.zig+9-10| ... | ... | @@ -622,7 +622,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { |
| 622 | 622 | const start = s.air_extra.list.items.len; |
| 623 | 623 | try s.air_extra.list.appendSlice(s.gpa, @ptrCast(scratch)); |
| 624 | 624 | |
| 625 | return s.addInstRef(.new, .{ | |
| 625 | return s.addInstRef(.js_new, .{ | |
| 626 | 626 | .base = base, |
| 627 | 627 | .call_data = try s.air_extra.append(s.gpa, Air.Call.Data, .{ .args = .{ |
| 628 | 628 | .start = @intCast(start), |
| ... | ... | @@ -774,13 +774,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { |
| 774 | 774 | |
| 775 | 775 | // Ensure we have a valid struct to operate on |
| 776 | 776 | const ty = try s.resolveType(in.op(.operand), node.base_type); |
| 777 | const struct_type = ty.toStructType(s.ip) orelse return s.fail( | |
| 778 | .struct_init_invalid_type, | |
| 779 | .{ | |
| 777 | const struct_type = ty.toStructType(s.ip) orelse { | |
| 778 | return s.fail(.struct_init_invalid_type, .{ | |
| 780 | 779 | .src = in.op(.operand).lazyNode(s.decl_index), |
| 781 | 780 | .ty = ty, |
| 782 | }, | |
| 783 | ); | |
| 781 | }); | |
| 782 | }; | |
| 784 | 783 | |
| 785 | 784 | var has_errors = false; |
| 786 | 785 | var is_constant = true; |
| ... | ... | @@ -957,7 +956,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { |
| 957 | 956 | |
| 958 | 957 | const operand = try s.resolveValue(result.type); |
| 959 | 958 | const ty = operand.toType(s.ip) orelse |
| 960 | return Value.opaque_type; | |
| 959 | return Value.opaque_type.toAir(); | |
| 961 | 960 | |
| 962 | 961 | const array_type = ty.toArrayType(s.ip) orelse |
| 963 | 962 | return Value.opaque_type.toAir(); |
| ... | ... | @@ -966,11 +965,11 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { |
| 966 | 965 | }, |
| 967 | 966 | |
| 968 | 967 | .result_type_tuple_field => { |
| 969 | const result: Teg.ResultTypeTupleField = s.code.instData(.result_type_array_value, in); | |
| 968 | const result: Teg.ResultTypeTupleField = s.code.instData(.result_type_tuple_field, in); | |
| 970 | 969 | |
| 971 | 970 | const operand = try s.resolveValue(result.type); |
| 972 | 971 | const ty = operand.toType(s.ip) orelse |
| 973 | return Value.opaque_type; | |
| 972 | return Value.opaque_type.toAir(); | |
| 974 | 973 | |
| 975 | 974 | _ = ty; |
| 976 | 975 | |
| ... | ... | @@ -982,7 +981,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { |
| 982 | 981 | |
| 983 | 982 | const operand = try s.resolveValue(result.type); |
| 984 | 983 | const ty = operand.toType(s.ip) orelse |
| 985 | return Value.opaque_type; | |
| 984 | return Value.opaque_type.toAir(); | |
| 986 | 985 | |
| 987 | 986 | const struct_type = ty.toStructType(s.ip) orelse |
| 988 | 987 | return Value.opaque_type.toAir(); |
src/core/array.zig+4| ... | ... | @@ -133,6 +133,10 @@ fn ExtraWrap(comptime kind: StoreKind) type { |
| 133 | 133 | .{ .index = @intFromEnum(index) + advance }, |
| 134 | 134 | }; |
| 135 | 135 | } |
| 136 | ||
| 137 | pub fn jsonStringify(index: @This(), jw: anytype) !void { | |
| 138 | try jw.write(@intFromEnum(index)); | |
| 139 | } | |
| 136 | 140 | }; |
| 137 | 141 | } |
| 138 | 142 | }; |
src/core/js/Link.zig+2-2| ... | ... | @@ -475,8 +475,8 @@ fn printExprLevel( |
| 475 | 475 | |
| 476 | 476 | try writer.writeAll(")"); |
| 477 | 477 | }, |
| 478 | .new => { | |
| 479 | const call: Tree.Call = tree.nodeData(.new, node); | |
| 478 | .js_new => { | |
| 479 | const call: Tree.Call = tree.nodeData(.js_new, node); | |
| 480 | 480 | const args = call.args.get(tree); |
| 481 | 481 | |
| 482 | 482 | if (Level.new.needsParens(level)) |
src/core/js/NodeGen.zig+2-2| ... | ... | @@ -273,7 +273,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void { |
| 273 | 273 | try c.markExpression(inst, node); |
| 274 | 274 | }, |
| 275 | 275 | |
| 276 | inline .call, .new => |tag| { | |
| 276 | inline .call, .js_new => |tag| { | |
| 277 | 277 | const data: Air.Call = c.air.instData(tag, inst); |
| 278 | 278 | const call_data = data.call_data.get(c.air); |
| 279 | 279 | |
| ... | ... | @@ -653,7 +653,7 @@ fn canLowerToExpression(c: *const NodeGen, inst: Air.Inst.Ref) bool { |
| 653 | 653 | .index => |index| switch (c.air.instTag(index)) { |
| 654 | 654 | .js_global_ref, |
| 655 | 655 | .call, |
| 656 | .new, | |
| 656 | .js_new, | |
| 657 | 657 | .arg, |
| 658 | 658 | .field_opaque, |
| 659 | 659 | .field_struct, |
src/core/js/Tree.zig+2-2| ... | ... | @@ -41,7 +41,7 @@ pub const Tag = enum { |
| 41 | 41 | gt, |
| 42 | 42 | // Exprs |
| 43 | 43 | call, |
| 44 | new, | |
| 44 | js_new, | |
| 45 | 45 | field, |
| 46 | 46 | ternary, |
| 47 | 47 | object_literal, |
| ... | ... | @@ -93,7 +93,7 @@ pub const Tag = enum { |
| 93 | 93 | => Un, |
| 94 | 94 | .object_literal => ObjectLiteral, |
| 95 | 95 | .array => IndexList, |
| 96 | .call, .new => Call, | |
| 96 | .call, .js_new => Call, | |
| 97 | 97 | .field => Field, |
| 98 | 98 | .stmt_if => StmtIf, |
| 99 | 99 | .stmt_break => StmtBreak, |
src/core/main.zig+26| ... | ... | @@ -40,6 +40,7 @@ pub fn main() !void { |
| 40 | 40 | |
| 41 | 41 | var exe_name: []const u8 = undefined; |
| 42 | 42 | var dump_ir = false; |
| 43 | var dump_state: ?[]const u8 = null; | |
| 43 | 44 | |
| 44 | 45 | { |
| 45 | 46 | var args = try std.process.argsWithAllocator(alloc); |
| ... | ... | @@ -58,6 +59,10 @@ pub fn main() !void { |
| 58 | 59 | dump_ir = true; |
| 59 | 60 | continue; |
| 60 | 61 | } |
| 62 | if (std.mem.startsWith(u8, arg, "--dump-state=")) { | |
| 63 | dump_state = arg["--dump-state=".len..]; | |
| 64 | continue; | |
| 65 | } | |
| 61 | 66 | std.debug.print("error: unknown flag '{s}'\n", .{arg}); |
| 62 | 67 | maybe_file_path = null; |
| 63 | 68 | break; |
| ... | ... | @@ -107,6 +112,13 @@ pub fn main() !void { |
| 107 | 112 | }; |
| 108 | 113 | try comp.init(); |
| 109 | 114 | defer comp.deinit(); |
| 115 | ||
| 116 | defer if (dump_state) |path| { | |
| 117 | dumpState(&comp, path) catch |err| { | |
| 118 | std.debug.print("Failed to dump compilation state: {}", .{err}); | |
| 119 | }; | |
| 120 | }; | |
| 121 | ||
| 110 | 122 | const main_file = try comp.getFile(file_path); |
| 111 | 123 | |
| 112 | 124 | var fail_report: Report = undefined; |
| ... | ... | @@ -141,3 +153,17 @@ pub fn main() !void { |
| 141 | 153 | |
| 142 | 154 | std.process.cleanExit(); |
| 143 | 155 | } |
| 156 | ||
| 157 | fn dumpState(comp: *const Comp, dump_path: []const u8) !void { | |
| 158 | const file = try std.fs.cwd().createFile(dump_path, .{}); | |
| 159 | defer file.close(); | |
| 160 | ||
| 161 | var bufw = std.io.bufferedWriter(file.writer()); | |
| 162 | var jw = std.json.writeStream(bufw.writer(), .{ | |
| 163 | .whitespace = .indent_2, | |
| 164 | }); | |
| 165 | ||
| 166 | try comp.jsonStringify(&jw); | |
| 167 | try bufw.writer().writeAll("\n"); | |
| 168 | try bufw.flush(); | |
| 169 | } |
src/core/mod.zig+13| ... | ... | @@ -101,6 +101,19 @@ pub fn detectTTYFromWriter(writer: std.io.AnyWriter) std.io.tty.Config { |
| 101 | 101 | return .no_color; |
| 102 | 102 | } |
| 103 | 103 | |
| 104 | /// This function is entirely because ZLS cannot infer `anytype` -> `std.json.WriteStream` | |
| 105 | /// It should be removed once ZLS or the Zig language fixes this. | |
| 106 | pub fn jsonWriterCast(json_writer: anytype) *std.json.WriteStream( | |
| 107 | @TypeOf(json_writer.*).Stream, | |
| 108 | switch (@TypeOf(json_writer.nesting_stack)) { | |
| 109 | void => .assumed_correct, | |
| 110 | std.BitStack => .checked_to_arbitrary_depth, | |
| 111 | else => .{ .checked_to_fixed_depth = 256 }, | |
| 112 | }, | |
| 113 | ) { | |
| 114 | return json_writer; | |
| 115 | } | |
| 116 | ||
| 104 | 117 | const std = @import("std"); |
| 105 | 118 | const assert = std.debug.assert; |
| 106 | 119 |