authorgravatar for me@paperdave.netdave caruso <me@paperdave.net> 2024-07-27 05:08:05-07:00
committergravatar for me@paperdave.netdave caruso <me@paperdave.net> 2024-07-27 05:08:05-07:00
logbc6e21dae00fe292462a68138fc26ee7a6753bfb
tree69e80ba6e1a8fbd4d888e62f68776dc4452d4ace
parent04faedd592fa4b470cf574b0c14c87cdea2d95a4
signature Commit is signed but in an unrecognized format.

feat: allow dumping compiler state


13 files changed, 298 insertions(+), 56 deletions(-)

CHANGELOG.md+1
...@@ -2,6 +2,7 @@...@@ -2,6 +2,7 @@
22
3- feat: clarify "defined runtime representation" and "can be represented at runtime"3- feat: clarify "defined runtime representation" and "can be represented at runtime"
4- feat: implement inferred structs + result type semantics4- feat: implement inferred structs + result type semantics
5- feat: add `--dump-state=./filename.json` to dump compiler state as JSON
5- chore: remove group expressions, use single expression blocks instead6- chore: remove group expressions, use single expression blocks instead
6- fix(sema): fix passing structs as function params7- fix(sema): fix passing structs as function params
7- fix: diagnostic box drawing characters line up after line 98- 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,7 +92,6 @@ pub fn build(b: *std.Build) !void {
92 .root_source_file = b.path("src/manual/generate-man.zig"),92 .root_source_file = b.path("src/manual/generate-man.zig"),
93 .target = native_target,93 .target = native_target,
94 .optimize = .Debug,94 .optimize = .Debug,
95 .link_libc = true,
96 });95 });
97 manual_generator.root_module.addImport("build_options", native_debug.opts_mod);96 manual_generator.root_module.addImport("build_options", native_debug.opts_mod);
98 manual_generator.root_module.addImport("core", native_debug.core);97 manual_generator.root_module.addImport("core", native_debug.core);
...@@ -204,10 +203,11 @@ fn buildWithTarget(...@@ -204,10 +203,11 @@ fn buildWithTarget(
204 const opts_mod = opts.createModule();203 const opts_mod = opts.createModule();
205204
206 // Core205 // Core
207 const core = b.addModule("compiler", .{206 const core = b.addModule("core", .{
208 .root_source_file = b.path("src/core/mod.zig"),207 .root_source_file = b.path("src/core/mod.zig"),
209 .optimize = optimize,208 .optimize = optimize,
210 .target = target,209 .target = target,
210 .strip = false,
211 });211 });
212 core.addImport("build_options", opts_mod);212 core.addImport("build_options", opts_mod);
213 core.addImport("tracer", tracer.module("tracer"));213 core.addImport("tracer", tracer.module("tracer"));
...@@ -220,6 +220,7 @@ fn buildWithTarget(...@@ -220,6 +220,7 @@ fn buildWithTarget(
220 .optimize = optimize,220 .optimize = optimize,
221 .use_lld = use_lld,221 .use_lld = use_lld,
222 .use_llvm = use_llvm,222 .use_llvm = use_llvm,
223 .strip = false,
223 });224 });
224 core_tests.root_module.addImport("build_options", opts_mod);225 core_tests.root_module.addImport("build_options", opts_mod);
225 core_tests.root_module.addImport("tracer", tracer.module("tracer"));226 core_tests.root_module.addImport("tracer", tracer.module("tracer"));
...@@ -233,6 +234,8 @@ fn buildWithTarget(...@@ -233,6 +234,8 @@ fn buildWithTarget(
233 .optimize = optimize,234 .optimize = optimize,
234 .use_lld = use_lld,235 .use_lld = use_lld,
235 .use_llvm = use_llvm,236 .use_llvm = use_llvm,
237 .strip = false,
238 .omit_frame_pointer = false,
236 });239 });
237 compiler_exe.root_module.addImport("build_options", opts_mod);240 compiler_exe.root_module.addImport("build_options", opts_mod);
238 compiler_exe.root_module.addImport("core", core);241 compiler_exe.root_module.addImport("core", core);
...@@ -246,6 +249,9 @@ fn buildWithTarget(...@@ -246,6 +249,9 @@ fn buildWithTarget(
246 .optimize = optimize,249 .optimize = optimize,
247 .use_lld = use_lld,250 .use_lld = use_lld,
248 .use_llvm = use_llvm,251 .use_llvm = use_llvm,
252 .strip = false,
253 .omit_frame_pointer = false,
254 .unwind_tables = false,
249 });255 });
250 lsp_exe.root_module.addImport("build_options", opts_mod);256 lsp_exe.root_module.addImport("build_options", opts_mod);
251 lsp_exe.root_module.addImport("core", core);257 lsp_exe.root_module.addImport("core", core);
src/core/Air.Dump.zig+1-1
...@@ -143,7 +143,7 @@ pub const State = struct {...@@ -143,7 +143,7 @@ pub const State = struct {
143 try tty.setColor(w, .reset);143 try tty.setColor(w, .reset);
144 try w.writeAll(")");144 try w.writeAll(")");
145 },145 },
146 inline .call, .new => |t| {146 inline .call, .js_new => |t| {
147 const call: Air.Call = air.instData(t, inst);147 const call: Air.Call = air.instData(t, inst);
148 const call_data = call.call_data.get(air);148 const call_data = call.call_data.get(air);
149 try w.writeAll("(");149 try w.writeAll("(");
src/core/Air.zig+5-5
...@@ -16,7 +16,7 @@ pub const Inst = struct {...@@ -16,7 +16,7 @@ pub const Inst = struct {
16 block,16 block,
17 js_global_ref,17 js_global_ref,
18 call,18 call,
19 new,19 js_new,
20 @"break",20 @"break",
21 @"if",21 @"if",
22 arg,22 arg,
...@@ -53,7 +53,7 @@ pub const Inst = struct {...@@ -53,7 +53,7 @@ pub const Inst = struct {
53 .js_global_ref => InternPool.String.WithLen,53 .js_global_ref => InternPool.String.WithLen,
54 .@"break" => Break,54 .@"break" => Break,
55 .@"if" => If,55 .@"if" => If,
56 .call, .new => Call,56 .call, .js_new => Call,
57 .arg => Arg,57 .arg => Arg,
58 .memory => Memory,58 .memory => Memory,
59 .store => Store,59 .store => Store,
...@@ -323,7 +323,7 @@ pub fn typeOf(air: *const Air, ref: Inst.Ref, ip: *const InternPool) InternPool....@@ -323,7 +323,7 @@ pub fn typeOf(air: *const Air, ref: Inst.Ref, ip: *const InternPool) InternPool.
323pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) InternPool.Type {323pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) InternPool.Type {
324 return switch (air.instTag(index)) {324 return switch (air.instTag(index)) {
325 // These values are by definition, opaque325 // These values are by definition, opaque
326 .js_global_ref, .new => .@"opaque",326 .js_global_ref, .js_new => .@"opaque",
327327
328 // These operations always produce known types328 // These operations always produce known types
329 .lt, .gt, .eq, .bool_not => .bool,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,7 +375,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In
375 .field_struct => {375 .field_struct => {
376 const inst = air.instData(.field_struct, index);376 const inst = air.instData(.field_struct, index);
377 const base_type = air.typeOfIndex(inst.base, ip)377 const base_type = air.typeOfIndex(inst.base, ip)
378 .toStructType(ip) orelse unreachable; // not a struct378 .toStructType(ip) orelse unreachable; // field_struct demands struct type
379 return base_type.field_types[inst.field_index];379 return base_type.field_types[inst.field_index];
380 },380 },
381381
...@@ -383,7 +383,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In...@@ -383,7 +383,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In
383 .index => {383 .index => {
384 const inst = air.instData(.index, index);384 const inst = air.instData(.index, index);
385 const base_type = air.typeOf(inst.lhs, ip)385 const base_type = air.typeOf(inst.lhs, ip)
386 .toArrayType(ip) orelse unreachable; // not an array386 .toArrayType(ip) orelse unreachable; // index demands array type
387 return base_type.item_type;387 return base_type.item_type;
388 },388 },
389 };389 };
src/core/Comp.zig+132-20
...@@ -8,7 +8,8 @@ gpa: Allocator,...@@ -8,7 +8,8 @@ gpa: Allocator,
8/// Stores all Type and Value objects.8/// Stores all Type and Value objects.
9intern_pool: InternPool = .{},9intern_pool: InternPool = .{},
10/// All files in the compilation10/// All files in the compilation
11files: std.StringArrayHashMapUnmanaged(*File) = .{},11/// TODO: turn this into a HashMap(*File, void) as File owns it's key
12files: std.StringHashMapUnmanaged(*File) = .{},
1213
13options: Options = .{},14options: Options = .{},
1415
...@@ -20,8 +21,9 @@ pub fn init(comp: *Comp) !void {...@@ -20,8 +21,9 @@ pub fn init(comp: *Comp) !void {
2021
21pub fn deinit(comp: *Comp) void {22pub fn deinit(comp: *Comp) void {
22 comp.intern_pool.deinit(comp.gpa);23 comp.intern_pool.deinit(comp.gpa);
23 for (comp.files.values()) |file| {24 var it = comp.files.valueIterator();
24 file.deinit(comp.gpa);25 while (it.next()) |file| {
26 file.*.deinit(comp.gpa);
25 }27 }
26 comp.files.deinit(comp.gpa);28 comp.files.deinit(comp.gpa);
27 comp.backend.deinit(comp);29 comp.backend.deinit(comp);
...@@ -96,7 +98,7 @@ pub const File = struct {...@@ -96,7 +98,7 @@ pub const File = struct {
96 /// TODO: change this to a URL98 /// TODO: change this to a URL
97 file_path: []const u8,99 file_path: []const u8,
98100
99 root_namespace: Decl.Index.Optional,101 root_namespace: Namespace.Index.Optional,
100 status: enum {102 status: enum {
101 never_loaded,103 never_loaded,
102 /// A failure occurred while loading the file. Retrying might succeed.104 /// A failure occurred while loading the file. Retrying might succeed.
...@@ -249,6 +251,36 @@ pub const File = struct {...@@ -249,6 +251,36 @@ pub const File = struct {
249 file.unloadSource(gpa);251 file.unloadSource(gpa);
250 gpa.destroy(file);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};
253285
254/// A declaration is a named value which also represents the smallest unit of286/// A declaration is a named value which also represents the smallest unit of
...@@ -328,12 +360,43 @@ pub const Decl = struct {...@@ -328,12 +360,43 @@ pub const Decl = struct {
328 };360 };
329 }361 }
330362
331 pub fn deinit(decl: *Decl, gpa: Allocator) void {363 pub fn fmtJson(decl: *const Decl, comp: *const Comp) JsonFormatter {
332 _ = gpa; // autofix364 return .{ .decl = decl, .comp = comp };
333 defer decl.* = undefined;
334 // if (decl.codegen) |*cg| cg.deinit(gpa);
335 }365 }
336366
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 pub const Index = InternPool.DeclIndex;400 pub const Index = InternPool.DeclIndex;
338};401};
339402
...@@ -348,8 +411,6 @@ pub const Namespace = struct {...@@ -348,8 +411,6 @@ pub const Namespace = struct {
348 file_scope: *File,411 file_scope: *File,
349 /// Direct children of the namespace.412 /// Direct children of the namespace.
350 /// Declaration order is preserved via entry order.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 decls: std.ArrayHashMapUnmanaged(Decl.Index, void, DeclContext, true) = .{},414 decls: std.ArrayHashMapUnmanaged(Decl.Index, void, DeclContext, true) = .{},
354415
355 pub const DeclContext = struct {416 pub const DeclContext = struct {
...@@ -400,6 +461,34 @@ pub const Namespace = struct {...@@ -400,6 +461,34 @@ pub const Namespace = struct {
400 return ns.decls.getKeyAdapted(name, Namespace.DeclNameAdapter{ .comp = comp });461 return ns.decls.getKeyAdapted(name, Namespace.DeclNameAdapter{ .comp = comp });
401 }462 }
402463
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 pub const Index = InternPool.NamespaceIndex;492 pub const Index = InternPool.NamespaceIndex;
404};493};
405494
...@@ -408,10 +497,13 @@ pub const Namespace = struct {...@@ -408,10 +497,13 @@ pub const Namespace = struct {
408pub fn indexTegModule(comp: *Comp, file: *File, module_index: Teg.Inst.Index) !Namespace.Index {497pub fn indexTegModule(comp: *Comp, file: *File, module_index: Teg.Inst.Index) !Namespace.Index {
409 const teg = file.teg.?;498 const teg = file.teg.?;
410499
500 assert(file.root_namespace == .none);
501
411 const ns = try comp.intern_pool.createNamespace(comp.gpa, .{502 const ns = try comp.intern_pool.createNamespace(comp.gpa, .{
412 .parent = .none,503 .parent = .none,
413 .file_scope = file,504 .file_scope = file,
414 });505 });
506 file.root_namespace = ns.toOptional();
415 const ns_ptr = comp.intern_pool.namespacePtr(ns);507 const ns_ptr = comp.intern_pool.namespacePtr(ns);
416 errdefer comp.intern_pool.destroyNamespace(comp.gpa, ns);508 errdefer comp.intern_pool.destroyNamespace(comp.gpa, ns);
417509
...@@ -450,6 +542,8 @@ const Options = struct {...@@ -450,6 +542,8 @@ const Options = struct {
450 dump_ir: bool = false,542 dump_ir: bool = false,
451};543};
452544
545/// The compiler backend is stored separately from the compilation, and
546/// interaction is done via this static dispatch contract.
453pub const Backend = union(enum) {547pub const Backend = union(enum) {
454 js: *@import("js/Js.zig"),548 js: *@import("js/Js.zig"),
455549
...@@ -485,6 +579,23 @@ pub const Backend = union(enum) {...@@ -485,6 +579,23 @@ pub const Backend = union(enum) {
485 pub const Tag = std.meta.FieldEnum(Backend);579 pub const Tag = std.meta.FieldEnum(Backend);
486};580};
487581
582pub 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
488const Comp = @This();599const Comp = @This();
489600
490const std = @import("std");601const std = @import("std");
...@@ -493,15 +604,16 @@ const assert = std.debug.assert;...@@ -493,15 +604,16 @@ const assert = std.debug.assert;
493const Stat = std.Build.Cache.File.Stat;604const Stat = std.Build.Cache.File.Stat;
494const log = std.log.scoped(.comp);605const log = std.log.scoped(.comp);
495606
496const InternPool = @import("InternPool.zig");607const core = @import("mod.zig");
497608const InternPool = core.InternPool;
498const Ast = @import("Ast.zig");609
499const Air = @import("Air.zig");610const Ast = core.Ast;
500const Teg = @import("Teg.zig");611const Air = core.Air;
501const Cache = @import("Cache.zig");612const Teg = core.Teg;
502const Sema = @import("Sema.zig");613const Cache = core.Cache;
503const Transform = @import("Transform.zig");614const Sema = core.Sema;
504const Report = @import("Report.zig");615const Transform = core.Transform;
505const Parse = @import("Parse.zig");616const Report = core.Report;
617const Parse = core.Parse;
506618
507const tracer = @import("tracer");619const tracer = @import("tracer");
src/core/InternPool.zig+93-12
...@@ -714,14 +714,21 @@ pub const TrackedInst = extern struct {...@@ -714,14 +714,21 @@ pub const TrackedInst = extern struct {
714 pub const Index = enum(u32) {714 pub const Index = enum(u32) {
715 _,715 _,
716 pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Teg.Inst.Index {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 pub fn toOptional(i: TrackedInst.Index) Optional {724 pub fn toOptional(i: TrackedInst.Index) Optional {
720 return @enumFromInt(@intFromEnum(i));725 return @enumFromInt(@intFromEnum(i));
721 }726 }
727
722 pub const Optional = enum(u32) {728 pub const Optional = enum(u32) {
723 none = std.math.maxInt(u32),729 none = std.math.maxInt(u32),
724 _,730 _,
731
725 pub fn unwrap(opt: Optional) ?TrackedInst.Index {732 pub fn unwrap(opt: Optional) ?TrackedInst.Index {
726 return switch (opt) {733 return switch (opt) {
727 .none => null,734 .none => null,
...@@ -730,6 +737,16 @@ pub const TrackedInst = extern struct {...@@ -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};
734751
735pub const DeclIndex = enum(u32) {752pub const DeclIndex = enum(u32) {
...@@ -757,7 +774,7 @@ pub const DeclIndex = enum(u32) {...@@ -757,7 +774,7 @@ pub const DeclIndex = enum(u32) {
757pub const NamespaceIndex = enum(u32) {774pub const NamespaceIndex = enum(u32) {
758 _,775 _,
759776
760 pub fn toOptional(i: DeclIndex) Optional {777 pub fn toOptional(i: NamespaceIndex) Optional {
761 return @enumFromInt(@intFromEnum(i));778 return @enumFromInt(@intFromEnum(i));
762 }779 }
763780
...@@ -1096,11 +1113,6 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {...@@ -1096,11 +1113,6 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
1096 // ip.limbs.deinit(gpa);1113 // ip.limbs.deinit(gpa);
1097 ip.string_bytes.deinit(gpa);1114 ip.string_bytes.deinit(gpa);
10981115
1099 var decls = ip.allocated_decls.iterator(0);
1100 while (decls.next()) |decl| {
1101 decl.deinit(gpa);
1102 }
1103
1104 ip.allocated_decls.deinit(gpa);1116 ip.allocated_decls.deinit(gpa);
1105 ip.decls_free_list.deinit(gpa);1117 ip.decls_free_list.deinit(gpa);
11061118
...@@ -1346,11 +1358,12 @@ fn getOrPutTrailingString(...@@ -1346,11 +1358,12 @@ fn getOrPutTrailingString(
1346 return @enumFromInt(str_index);1358 return @enumFromInt(str_index);
1347 },1359 },
1348 }1360 }
1349 const gop = try ip.string_table.getOrPutContextAdapted(gpa, key, std.hash_map.StringIndexAdapter{1361 const gop = try ip.string_table.getOrPutContextAdapted(
1350 .bytes = string_bytes,1362 gpa,
1351 }, std.hash_map.StringIndexContext{1363 key,
1352 .bytes = string_bytes,1364 std.hash_map.StringIndexAdapter{ .bytes = string_bytes },
1353 });1365 std.hash_map.StringIndexContext{ .bytes = string_bytes },
1366 );
1354 if (gop.found_existing) {1367 if (gop.found_existing) {
1355 string_bytes.shrinkRetainingCapacity(str_index);1368 string_bytes.shrinkRetainingCapacity(str_index);
1356 return @enumFromInt(gop.key_ptr.*);1369 return @enumFromInt(gop.key_ptr.*);
...@@ -1445,6 +1458,74 @@ pub fn destroyNamespace(ip: *InternPool, gpa: Allocator, index: NamespaceIndex)...@@ -1445,6 +1458,74 @@ pub fn destroyNamespace(ip: *InternPool, gpa: Allocator, index: NamespaceIndex)
1445 };1458 };
1446}1459}
14471460
1461pub 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
1448const InternPool = @This();1529const InternPool = @This();
14491530
1450const std = @import("std");1531const 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,7 +622,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {
622 const start = s.air_extra.list.items.len;622 const start = s.air_extra.list.items.len;
623 try s.air_extra.list.appendSlice(s.gpa, @ptrCast(scratch));623 try s.air_extra.list.appendSlice(s.gpa, @ptrCast(scratch));
624624
625 return s.addInstRef(.new, .{625 return s.addInstRef(.js_new, .{
626 .base = base,626 .base = base,
627 .call_data = try s.air_extra.append(s.gpa, Air.Call.Data, .{ .args = .{627 .call_data = try s.air_extra.append(s.gpa, Air.Call.Data, .{ .args = .{
628 .start = @intCast(start),628 .start = @intCast(start),
...@@ -774,13 +774,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {...@@ -774,13 +774,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {
774774
775 // Ensure we have a valid struct to operate on775 // Ensure we have a valid struct to operate on
776 const ty = try s.resolveType(in.op(.operand), node.base_type);776 const ty = try s.resolveType(in.op(.operand), node.base_type);
777 const struct_type = ty.toStructType(s.ip) orelse return s.fail(777 const struct_type = ty.toStructType(s.ip) orelse {
778 .struct_init_invalid_type,778 return s.fail(.struct_init_invalid_type, .{
779 .{
780 .src = in.op(.operand).lazyNode(s.decl_index),779 .src = in.op(.operand).lazyNode(s.decl_index),
781 .ty = ty,780 .ty = ty,
782 },781 });
783 );782 };
784783
785 var has_errors = false;784 var has_errors = false;
786 var is_constant = true;785 var is_constant = true;
...@@ -957,7 +956,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {...@@ -957,7 +956,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {
957956
958 const operand = try s.resolveValue(result.type);957 const operand = try s.resolveValue(result.type);
959 const ty = operand.toType(s.ip) orelse958 const ty = operand.toType(s.ip) orelse
960 return Value.opaque_type;959 return Value.opaque_type.toAir();
961960
962 const array_type = ty.toArrayType(s.ip) orelse961 const array_type = ty.toArrayType(s.ip) orelse
963 return Value.opaque_type.toAir();962 return Value.opaque_type.toAir();
...@@ -966,11 +965,11 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {...@@ -966,11 +965,11 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {
966 },965 },
967966
968 .result_type_tuple_field => {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);
970969
971 const operand = try s.resolveValue(result.type);970 const operand = try s.resolveValue(result.type);
972 const ty = operand.toType(s.ip) orelse971 const ty = operand.toType(s.ip) orelse
973 return Value.opaque_type;972 return Value.opaque_type.toAir();
974973
975 _ = ty;974 _ = ty;
976975
...@@ -982,7 +981,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {...@@ -982,7 +981,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {
982981
983 const operand = try s.resolveValue(result.type);982 const operand = try s.resolveValue(result.type);
984 const ty = operand.toType(s.ip) orelse983 const ty = operand.toType(s.ip) orelse
985 return Value.opaque_type;984 return Value.opaque_type.toAir();
986985
987 const struct_type = ty.toStructType(s.ip) orelse986 const struct_type = ty.toStructType(s.ip) orelse
988 return Value.opaque_type.toAir();987 return Value.opaque_type.toAir();
src/core/array.zig+4
...@@ -133,6 +133,10 @@ fn ExtraWrap(comptime kind: StoreKind) type {...@@ -133,6 +133,10 @@ fn ExtraWrap(comptime kind: StoreKind) type {
133 .{ .index = @intFromEnum(index) + advance },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,8 +475,8 @@ fn printExprLevel(
475475
476 try writer.writeAll(")");476 try writer.writeAll(")");
477 },477 },
478 .new => {478 .js_new => {
479 const call: Tree.Call = tree.nodeData(.new, node);479 const call: Tree.Call = tree.nodeData(.js_new, node);
480 const args = call.args.get(tree);480 const args = call.args.get(tree);
481481
482 if (Level.new.needsParens(level))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,7 +273,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void {
273 try c.markExpression(inst, node);273 try c.markExpression(inst, node);
274 },274 },
275275
276 inline .call, .new => |tag| {276 inline .call, .js_new => |tag| {
277 const data: Air.Call = c.air.instData(tag, inst);277 const data: Air.Call = c.air.instData(tag, inst);
278 const call_data = data.call_data.get(c.air);278 const call_data = data.call_data.get(c.air);
279279
...@@ -653,7 +653,7 @@ fn canLowerToExpression(c: *const NodeGen, inst: Air.Inst.Ref) bool {...@@ -653,7 +653,7 @@ fn canLowerToExpression(c: *const NodeGen, inst: Air.Inst.Ref) bool {
653 .index => |index| switch (c.air.instTag(index)) {653 .index => |index| switch (c.air.instTag(index)) {
654 .js_global_ref,654 .js_global_ref,
655 .call,655 .call,
656 .new,656 .js_new,
657 .arg,657 .arg,
658 .field_opaque,658 .field_opaque,
659 .field_struct,659 .field_struct,
src/core/js/Tree.zig+2-2
...@@ -41,7 +41,7 @@ pub const Tag = enum {...@@ -41,7 +41,7 @@ pub const Tag = enum {
41 gt,41 gt,
42 // Exprs42 // Exprs
43 call,43 call,
44 new,44 js_new,
45 field,45 field,
46 ternary,46 ternary,
47 object_literal,47 object_literal,
...@@ -93,7 +93,7 @@ pub const Tag = enum {...@@ -93,7 +93,7 @@ pub const Tag = enum {
93 => Un,93 => Un,
94 .object_literal => ObjectLiteral,94 .object_literal => ObjectLiteral,
95 .array => IndexList,95 .array => IndexList,
96 .call, .new => Call,96 .call, .js_new => Call,
97 .field => Field,97 .field => Field,
98 .stmt_if => StmtIf,98 .stmt_if => StmtIf,
99 .stmt_break => StmtBreak,99 .stmt_break => StmtBreak,
src/core/main.zig+26
...@@ -40,6 +40,7 @@ pub fn main() !void {...@@ -40,6 +40,7 @@ pub fn main() !void {
4040
41 var exe_name: []const u8 = undefined;41 var exe_name: []const u8 = undefined;
42 var dump_ir = false;42 var dump_ir = false;
43 var dump_state: ?[]const u8 = null;
4344
44 {45 {
45 var args = try std.process.argsWithAllocator(alloc);46 var args = try std.process.argsWithAllocator(alloc);
...@@ -58,6 +59,10 @@ pub fn main() !void {...@@ -58,6 +59,10 @@ pub fn main() !void {
58 dump_ir = true;59 dump_ir = true;
59 continue;60 continue;
60 }61 }
62 if (std.mem.startsWith(u8, arg, "--dump-state=")) {
63 dump_state = arg["--dump-state=".len..];
64 continue;
65 }
61 std.debug.print("error: unknown flag '{s}'\n", .{arg});66 std.debug.print("error: unknown flag '{s}'\n", .{arg});
62 maybe_file_path = null;67 maybe_file_path = null;
63 break;68 break;
...@@ -107,6 +112,13 @@ pub fn main() !void {...@@ -107,6 +112,13 @@ pub fn main() !void {
107 };112 };
108 try comp.init();113 try comp.init();
109 defer comp.deinit();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 const main_file = try comp.getFile(file_path);122 const main_file = try comp.getFile(file_path);
111123
112 var fail_report: Report = undefined;124 var fail_report: Report = undefined;
...@@ -141,3 +153,17 @@ pub fn main() !void {...@@ -141,3 +153,17 @@ pub fn main() !void {
141153
142 std.process.cleanExit();154 std.process.cleanExit();
143}155}
156
157fn 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,6 +101,19 @@ pub fn detectTTYFromWriter(writer: std.io.AnyWriter) std.io.tty.Config {
101 return .no_color;101 return .no_color;
102}102}
103103
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.
106pub 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
104const std = @import("std");117const std = @import("std");
105const assert = std.debug.assert;118const assert = std.debug.assert;
106119