1//! For testing the core compiler with minimal feature and
2//! additional debugging parameters.
3
4const config = @import("config");
5
6const arg_config: Cli = .{
7 .options = &.{
8 .{ .short = 'i', .name = "--dump-ir", .desc = "Dump intermediate representations" },
9 .{ .name = "--dump-state", .desc = "Dump compiler state to JSON", .kind = .string },
10 .{ .short = 'r', .name = "--report-trace", .desc = "Print stack traces to errors" },
11 .{ .short = 't', .name = "--tests", .desc = "Build unit tests instead of the main function" },
12 .{ .short = 'L', .name = "--no-leak-checks", .desc = "" },
13 },
14 .positionals = .single,
15 .help = .{
16 .usage = "[options...] [entry file]",
17 },
18};
19
20pub fn main() !u8 {
21 try tracer.init();
22 defer tracer.deinit();
23 try tracer.init_thread(null);
24 defer tracer.deinit_thread();
25
26 // unicode props is asserted to be initialized before core.Tokenizer is used
27 // this will result in a static page allocation, which is never cleaned up.
28 try core.unicode_props.init();
29
30 const use_gpa = builtin.mode == .Debug;
31 var gpa = if (use_gpa)
32 std.heap.GeneralPurposeAllocator(.{
33 .stack_trace_frames = 100,
34 }){}
35 else
36 std.heap.ArenaAllocator.init(std.heap.page_allocator);
37 var no_leak_checks = false;
38 defer _ = if (use_gpa and !no_leak_checks) gpa.deinit();
39 const alloc = gpa.allocator();
40
41 // Current working directory is required for CLI resolution.
42 var cwd_buf: [std.fs.max_path_bytes]u8 = undefined;
43 const cwd = try std.posix.getcwd(&cwd_buf);
44
45 // Command line argument parsing.
46 const program_name = "zig build compiler --";
47 _, const args = try Cli.programArgsAlloc(alloc, program_name);
48 defer Cli.programArgsFree(alloc, args);
49 const opts = arg_config.parse(program_name, args);
50
51 if (opts.report_trace == true) Report.debug_show_report_trace = true;
52
53 const file_path = try std.fs.path.resolve(alloc, &.{
54 cwd,
55 opts.positionals orelse
56 arg_config.showHelpAndExit(program_name),
57 });
58 defer alloc.free(file_path);
59
60 no_leak_checks = opts.no_leak_checks orelse false;
61
62 // Execute compiler
63 {
64 var js_backend = core.Js{};
65
66 var comp = try core.Comp.init(.{
67 .gpa = tracer.tracingAllocator(&alloc),
68 .options = .{
69 .dump_ir = opts.dump_ir orelse false,
70 },
71 .backend = .{ .js = &js_backend },
72 });
73 defer comp.deinit();
74
75 defer if (opts.dump_state) |path| {
76 dumpState(&comp, path) catch |err| {
77 std.debug.print("Failed to dump compilation state: {}", .{err});
78 };
79 };
80
81 const main_file = try comp.getFile(file_path);
82
83 var fail_report: Report = undefined;
84 const hir = main_file.getHir(&comp, &fail_report) catch |err| switch (err) {
85 error.TransformFail => {
86 std.debug.print("Transform failed:\n", .{});
87 try fail_report.dump(.initComp(&comp, main_file), comp.out);
88 fail_report.deinit(comp.gpa);
89 return 1;
90 },
91 error.ParseFail => {
92 // Already printed.
93 return 1;
94 },
95 else => return err,
96 };
97
98 if (comp.options.dump_ir) {
99 const stderr = std.io.getStdErr().writer();
100 try hir.dumpToWriter(stderr, null);
101 }
102
103 const entry_point = try comp.enqueueEntryModule(main_file);
104 comp.runAllJobs() catch |err| switch (err) {
105 error.AnalysisFail => {
106 // error is already printed
107 return 1;
108 },
109 else => return err,
110 };
111
112 {
113 // Output to standard out
114 const output = std.io.getStdOut().writer();
115 var bufw = std.io.bufferedWriter(output);
116 const writer = bufw.writer();
117 try js_backend.link(&comp, entry_point, writer.any());
118 try bufw.flush();
119 }
120 }
121
122 std.process.cleanExit();
123 return 0;
124}
125
126const core = @import("core");
127const Comp = core.Comp;
128const Report = core.Report;
129
130const tracer = @import("tracer");
131pub const tracer_impl = @field(tracer, @tagName(@import("config").tracing_mode));
132
133const std = @import("std");
134const builtin = @import("builtin");
135const Cli = @import("Cli");
136
137fn dumpState(comp: *const Comp, dump_path: []const u8) !void {
138 const file = try std.fs.cwd().createFile(dump_path, .{});
139 defer file.close();
140
141 var bufw = std.io.bufferedWriter(file.writer());
142 var jw = std.json.writeStream(bufw.writer(), .{
143 .whitespace = .indent_2,
144 });
145
146 try comp.jsonStringify(&jw);
147 try bufw.writer().writeAll("\n");
148 try bufw.flush();
149}