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 @@
22
33- feat: clarify "defined runtime representation" and "can be represented at runtime"
44- feat: implement inferred structs + result type semantics
5- feat: add `--dump-state=./filename.json` to dump compiler state as JSON
56- chore: remove group expressions, use single expression blocks instead
67- fix(sema): fix passing structs as function params
78- 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 {
9292 .root_source_file = b.path("src/manual/generate-man.zig"),
9393 .target = native_target,
9494 .optimize = .Debug,
95 .link_libc = true,
9695 });
9796 manual_generator.root_module.addImport("build_options", native_debug.opts_mod);
9897 manual_generator.root_module.addImport("core", native_debug.core);
......@@ -204,10 +203,11 @@ fn buildWithTarget(
204203 const opts_mod = opts.createModule();
205204
206205 // Core
207 const core = b.addModule("compiler", .{
206 const core = b.addModule("core", .{
208207 .root_source_file = b.path("src/core/mod.zig"),
209208 .optimize = optimize,
210209 .target = target,
210 .strip = false,
211211 });
212212 core.addImport("build_options", opts_mod);
213213 core.addImport("tracer", tracer.module("tracer"));
......@@ -220,6 +220,7 @@ fn buildWithTarget(
220220 .optimize = optimize,
221221 .use_lld = use_lld,
222222 .use_llvm = use_llvm,
223 .strip = false,
223224 });
224225 core_tests.root_module.addImport("build_options", opts_mod);
225226 core_tests.root_module.addImport("tracer", tracer.module("tracer"));
......@@ -233,6 +234,8 @@ fn buildWithTarget(
233234 .optimize = optimize,
234235 .use_lld = use_lld,
235236 .use_llvm = use_llvm,
237 .strip = false,
238 .omit_frame_pointer = false,
236239 });
237240 compiler_exe.root_module.addImport("build_options", opts_mod);
238241 compiler_exe.root_module.addImport("core", core);
......@@ -246,6 +249,9 @@ fn buildWithTarget(
246249 .optimize = optimize,
247250 .use_lld = use_lld,
248251 .use_llvm = use_llvm,
252 .strip = false,
253 .omit_frame_pointer = false,
254 .unwind_tables = false,
249255 });
250256 lsp_exe.root_module.addImport("build_options", opts_mod);
251257 lsp_exe.root_module.addImport("core", core);
src/core/Air.Dump.zig+1-1
......@@ -143,7 +143,7 @@ pub const State = struct {
143143 try tty.setColor(w, .reset);
144144 try w.writeAll(")");
145145 },
146 inline .call, .new => |t| {
146 inline .call, .js_new => |t| {
147147 const call: Air.Call = air.instData(t, inst);
148148 const call_data = call.call_data.get(air);
149149 try w.writeAll("(");
src/core/Air.zig+5-5
......@@ -16,7 +16,7 @@ pub const Inst = struct {
1616 block,
1717 js_global_ref,
1818 call,
19 new,
19 js_new,
2020 @"break",
2121 @"if",
2222 arg,
......@@ -53,7 +53,7 @@ pub const Inst = struct {
5353 .js_global_ref => InternPool.String.WithLen,
5454 .@"break" => Break,
5555 .@"if" => If,
56 .call, .new => Call,
56 .call, .js_new => Call,
5757 .arg => Arg,
5858 .memory => Memory,
5959 .store => Store,
......@@ -323,7 +323,7 @@ pub fn typeOf(air: *const Air, ref: Inst.Ref, ip: *const InternPool) InternPool.
323323pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) InternPool.Type {
324324 return switch (air.instTag(index)) {
325325 // These values are by definition, opaque
326 .js_global_ref, .new => .@"opaque",
326 .js_global_ref, .js_new => .@"opaque",
327327
328328 // These operations always produce known types
329329 .lt, .gt, .eq, .bool_not => .bool,
......@@ -375,7 +375,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In
375375 .field_struct => {
376376 const inst = air.instData(.field_struct, index);
377377 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
379379 return base_type.field_types[inst.field_index];
380380 },
381381
......@@ -383,7 +383,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In
383383 .index => {
384384 const inst = air.instData(.index, index);
385385 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
387387 return base_type.item_type;
388388 },
389389 };
src/core/Comp.zig+132-20
......@@ -8,7 +8,8 @@ gpa: Allocator,
88/// Stores all Type and Value objects.
99intern_pool: InternPool = .{},
1010/// 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
1314options: Options = .{},
1415
......@@ -20,8 +21,9 @@ pub fn init(comp: *Comp) !void {
2021
2122pub fn deinit(comp: *Comp) void {
2223 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);
2527 }
2628 comp.files.deinit(comp.gpa);
2729 comp.backend.deinit(comp);
......@@ -96,7 +98,7 @@ pub const File = struct {
9698 /// TODO: change this to a URL
9799 file_path: []const u8,
98100
99 root_namespace: Decl.Index.Optional,
101 root_namespace: Namespace.Index.Optional,
100102 status: enum {
101103 never_loaded,
102104 /// A failure occurred while loading the file. Retrying might succeed.
......@@ -249,6 +251,36 @@ pub const File = struct {
249251 file.unloadSource(gpa);
250252 gpa.destroy(file);
251253 }
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 };
252284};
253285
254286/// A declaration is a named value which also represents the smallest unit of
......@@ -328,12 +360,43 @@ pub const Decl = struct {
328360 };
329361 }
330362
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 };
335365 }
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
337400 pub const Index = InternPool.DeclIndex;
338401};
339402
......@@ -348,8 +411,6 @@ pub const Namespace = struct {
348411 file_scope: *File,
349412 /// Direct children of the namespace.
350413 /// Declaration order is preserved via entry order.
351 /// These are only declarations named directly by the AST; anonymous
352 /// declarations are not stored here.
353414 decls: std.ArrayHashMapUnmanaged(Decl.Index, void, DeclContext, true) = .{},
354415
355416 pub const DeclContext = struct {
......@@ -400,6 +461,34 @@ pub const Namespace = struct {
400461 return ns.decls.getKeyAdapted(name, Namespace.DeclNameAdapter{ .comp = comp });
401462 }
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
403492 pub const Index = InternPool.NamespaceIndex;
404493};
405494
......@@ -408,10 +497,13 @@ pub const Namespace = struct {
408497pub fn indexTegModule(comp: *Comp, file: *File, module_index: Teg.Inst.Index) !Namespace.Index {
409498 const teg = file.teg.?;
410499
500 assert(file.root_namespace == .none);
501
411502 const ns = try comp.intern_pool.createNamespace(comp.gpa, .{
412503 .parent = .none,
413504 .file_scope = file,
414505 });
506 file.root_namespace = ns.toOptional();
415507 const ns_ptr = comp.intern_pool.namespacePtr(ns);
416508 errdefer comp.intern_pool.destroyNamespace(comp.gpa, ns);
417509
......@@ -450,6 +542,8 @@ const Options = struct {
450542 dump_ir: bool = false,
451543};
452544
545/// The compiler backend is stored separately from the compilation, and
546/// interaction is done via this static dispatch contract.
453547pub const Backend = union(enum) {
454548 js: *@import("js/Js.zig"),
455549
......@@ -485,6 +579,23 @@ pub const Backend = union(enum) {
485579 pub const Tag = std.meta.FieldEnum(Backend);
486580};
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
488599const Comp = @This();
489600
490601const std = @import("std");
......@@ -493,15 +604,16 @@ const assert = std.debug.assert;
493604const Stat = std.Build.Cache.File.Stat;
494605const log = std.log.scoped(.comp);
495606
496const InternPool = @import("InternPool.zig");
497
498const Ast = @import("Ast.zig");
499const Air = @import("Air.zig");
500const Teg = @import("Teg.zig");
501const Cache = @import("Cache.zig");
502const Sema = @import("Sema.zig");
503const Transform = @import("Transform.zig");
504const Report = @import("Report.zig");
505const Parse = @import("Parse.zig");
607const core = @import("mod.zig");
608const InternPool = core.InternPool;
609
610const Ast = core.Ast;
611const Air = core.Air;
612const Teg = core.Teg;
613const Cache = core.Cache;
614const Sema = core.Sema;
615const Transform = core.Transform;
616const Report = core.Report;
617const Parse = core.Parse;
506618
507619const tracer = @import("tracer");
src/core/InternPool.zig+93-12
......@@ -714,14 +714,21 @@ pub const TrackedInst = extern struct {
714714 pub const Index = enum(u32) {
715715 _,
716716 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;
718718 }
719
720 pub fn get(i: TrackedInst.Index, ip: *const InternPool) TrackedInst {
721 return ip.tracked_insts.keys()[@intFromEnum(i)];
722 }
723
719724 pub fn toOptional(i: TrackedInst.Index) Optional {
720725 return @enumFromInt(@intFromEnum(i));
721726 }
727
722728 pub const Optional = enum(u32) {
723729 none = std.math.maxInt(u32),
724730 _,
731
725732 pub fn unwrap(opt: Optional) ?TrackedInst.Index {
726733 return switch (opt) {
727734 .none => null,
......@@ -730,6 +737,16 @@ pub const TrackedInst = extern struct {
730737 }
731738 };
732739 };
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 }
733750};
734751
735752pub const DeclIndex = enum(u32) {
......@@ -757,7 +774,7 @@ pub const DeclIndex = enum(u32) {
757774pub const NamespaceIndex = enum(u32) {
758775 _,
759776
760 pub fn toOptional(i: DeclIndex) Optional {
777 pub fn toOptional(i: NamespaceIndex) Optional {
761778 return @enumFromInt(@intFromEnum(i));
762779 }
763780
......@@ -1096,11 +1113,6 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
10961113 // ip.limbs.deinit(gpa);
10971114 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
11041116 ip.allocated_decls.deinit(gpa);
11051117 ip.decls_free_list.deinit(gpa);
11061118
......@@ -1346,11 +1358,12 @@ fn getOrPutTrailingString(
13461358 return @enumFromInt(str_index);
13471359 },
13481360 }
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 );
13541367 if (gop.found_existing) {
13551368 string_bytes.shrinkRetainingCapacity(str_index);
13561369 return @enumFromInt(gop.key_ptr.*);
......@@ -1445,6 +1458,74 @@ pub fn destroyNamespace(ip: *InternPool, gpa: Allocator, index: NamespaceIndex)
14451458 };
14461459}
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
14481529const InternPool = @This();
14491530
14501531const 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 {
622622 const start = s.air_extra.list.items.len;
623623 try s.air_extra.list.appendSlice(s.gpa, @ptrCast(scratch));
624624
625 return s.addInstRef(.new, .{
625 return s.addInstRef(.js_new, .{
626626 .base = base,
627627 .call_data = try s.air_extra.append(s.gpa, Air.Call.Data, .{ .args = .{
628628 .start = @intCast(start),
......@@ -774,13 +774,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {
774774
775775 // Ensure we have a valid struct to operate on
776776 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, .{
780779 .src = in.op(.operand).lazyNode(s.decl_index),
781780 .ty = ty,
782 },
783 );
781 });
782 };
784783
785784 var has_errors = false;
786785 var is_constant = true;
......@@ -957,7 +956,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {
957956
958957 const operand = try s.resolveValue(result.type);
959958 const ty = operand.toType(s.ip) orelse
960 return Value.opaque_type;
959 return Value.opaque_type.toAir();
961960
962961 const array_type = ty.toArrayType(s.ip) orelse
963962 return Value.opaque_type.toAir();
......@@ -966,11 +965,11 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {
966965 },
967966
968967 .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
971970 const operand = try s.resolveValue(result.type);
972971 const ty = operand.toType(s.ip) orelse
973 return Value.opaque_type;
972 return Value.opaque_type.toAir();
974973
975974 _ = ty;
976975
......@@ -982,7 +981,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref {
982981
983982 const operand = try s.resolveValue(result.type);
984983 const ty = operand.toType(s.ip) orelse
985 return Value.opaque_type;
984 return Value.opaque_type.toAir();
986985
987986 const struct_type = ty.toStructType(s.ip) orelse
988987 return Value.opaque_type.toAir();
src/core/array.zig+4
......@@ -133,6 +133,10 @@ fn ExtraWrap(comptime kind: StoreKind) type {
133133 .{ .index = @intFromEnum(index) + advance },
134134 };
135135 }
136
137 pub fn jsonStringify(index: @This(), jw: anytype) !void {
138 try jw.write(@intFromEnum(index));
139 }
136140 };
137141 }
138142 };
src/core/js/Link.zig+2-2
......@@ -475,8 +475,8 @@ fn printExprLevel(
475475
476476 try writer.writeAll(")");
477477 },
478 .new => {
479 const call: Tree.Call = tree.nodeData(.new, node);
478 .js_new => {
479 const call: Tree.Call = tree.nodeData(.js_new, node);
480480 const args = call.args.get(tree);
481481
482482 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 {
273273 try c.markExpression(inst, node);
274274 },
275275
276 inline .call, .new => |tag| {
276 inline .call, .js_new => |tag| {
277277 const data: Air.Call = c.air.instData(tag, inst);
278278 const call_data = data.call_data.get(c.air);
279279
......@@ -653,7 +653,7 @@ fn canLowerToExpression(c: *const NodeGen, inst: Air.Inst.Ref) bool {
653653 .index => |index| switch (c.air.instTag(index)) {
654654 .js_global_ref,
655655 .call,
656 .new,
656 .js_new,
657657 .arg,
658658 .field_opaque,
659659 .field_struct,
src/core/js/Tree.zig+2-2
......@@ -41,7 +41,7 @@ pub const Tag = enum {
4141 gt,
4242 // Exprs
4343 call,
44 new,
44 js_new,
4545 field,
4646 ternary,
4747 object_literal,
......@@ -93,7 +93,7 @@ pub const Tag = enum {
9393 => Un,
9494 .object_literal => ObjectLiteral,
9595 .array => IndexList,
96 .call, .new => Call,
96 .call, .js_new => Call,
9797 .field => Field,
9898 .stmt_if => StmtIf,
9999 .stmt_break => StmtBreak,
src/core/main.zig+26
......@@ -40,6 +40,7 @@ pub fn main() !void {
4040
4141 var exe_name: []const u8 = undefined;
4242 var dump_ir = false;
43 var dump_state: ?[]const u8 = null;
4344
4445 {
4546 var args = try std.process.argsWithAllocator(alloc);
......@@ -58,6 +59,10 @@ pub fn main() !void {
5859 dump_ir = true;
5960 continue;
6061 }
62 if (std.mem.startsWith(u8, arg, "--dump-state=")) {
63 dump_state = arg["--dump-state=".len..];
64 continue;
65 }
6166 std.debug.print("error: unknown flag '{s}'\n", .{arg});
6267 maybe_file_path = null;
6368 break;
......@@ -107,6 +112,13 @@ pub fn main() !void {
107112 };
108113 try comp.init();
109114 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
110122 const main_file = try comp.getFile(file_path);
111123
112124 var fail_report: Report = undefined;
......@@ -141,3 +153,17 @@ pub fn main() !void {
141153
142154 std.process.cleanExit();
143155}
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 {
101101 return .no_color;
102102}
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
104117const std = @import("std");
105118const assert = std.debug.assert;
106119