authorgravatar for me@paperdave.netdave caruso <me@paperdave.net> 2024-07-27 23:32:02-07:00
committergravatar for me@paperdave.netdave caruso <me@paperdave.net> 2024-07-27 23:32:02-07:00
logc7cb405f654a9aae882cc17746d73301b896f87b
tree3a15f57d55e437f2b908dd75d9dfc031560097a5
parent84d69ae4e43f53b2b0b243cff4f1f67303825b4b
signature Commit is signed but in an unrecognized format.

feat: add --run flag


5 files changed, 207 insertions(+), 33 deletions(-)

CHANGELOG.md+1
......@@ -1,5 +1,6 @@
11## 0.1.6
22
3- feat: add `--run` to execute the file in QuickJS instead of outputting source
34- fix: crash when printing unused struct declaration error
45- fix: provide array result type to sema
56- fix: crash when analyzing an empty array without a result type
build.zig+24-24
......@@ -66,7 +66,7 @@ pub fn build(b: *Build) !void {
6666 const native_debug = buildWithTarget(b, b.graph.host, .Debug, .none, version, no_llvm);
6767 const main = buildWithTarget(b, target, optimize, tracing, version, no_llvm);
6868
69 b.installArtifact(main.cli(b, .{}));
69 b.installArtifact(main.cli(b, BuildConfig.all));
7070
7171 inline for (.{
7272 .{ main.cli(b, BuildConfig.minimal), "compiler" },
......@@ -159,28 +159,25 @@ pub fn build(b: *Build) !void {
159159 @tagName(cross_target.result.os.tag),
160160 },
161161 ) catch @panic("OOM");
162 _ = name; // autofix
163162
164163 const artifacts = buildWithTarget(b, cross_target, .ReleaseSafe, .none, version, no_llvm);
165 _ = artifacts; // autofix
166
167 // inline for (.{
168 // .{ artifacts.compiler, "compiler" },
169 // // .{ artifacts.lsp, "lsp" },
170 // }) |entry| {
171 // const artifact, const bin_name = entry;
172 // package.dependOn(&b.addInstallFile(
173 // artifact.getEmittedBin(),
174 // b.pathJoin(&.{
175 // "package",
176 // name,
177 // std.mem.concat(b.graph.arena, u8, &.{
178 // bin_name,
179 // cross_target.result.exeFileExt(),
180 // }) catch @panic("OOM"),
181 // }),
182 // ).step);
183 // }
164
165 inline for (.{
166 .{ artifacts.cli(b, BuildConfig.all), "compiler" },
167 }) |entry| {
168 const artifact, const bin_name = entry;
169 package.dependOn(&b.addInstallFile(
170 artifact.getEmittedBin(),
171 b.pathJoin(&.{
172 "package",
173 name,
174 std.mem.concat(b.graph.arena, u8, &.{
175 bin_name,
176 cross_target.result.exeFileExt(),
177 }) catch @panic("OOM"),
178 }),
179 ).step);
180 }
184181
185182 package.dependOn(&b.addInstallFile(b.path("CHANGELOG.md"), "package/CHANGELOG.md").step);
186183 package.dependOn(&b.addInstallFile(manual_out, "package/README.html").step);
......@@ -208,8 +205,6 @@ const Artifacts = struct {
208205 const use_llvm = if (a.no_llvm) false else null;
209206 const use_lld = if (a.no_llvm) false else null;
210207
211 const tracer = b.dependency("tracer", dep_opts);
212
213208 // Options
214209 const build_config = b.addOptions();
215210 build_config.addOption(BuildConfig, "config", config);
......@@ -229,7 +224,12 @@ const Artifacts = struct {
229224 exe.root_module.addImport("build_options", a.opts_mod);
230225 exe.root_module.addImport("build_config", build_config_mod);
231226 exe.root_module.addImport("core", a.core);
232 exe.root_module.addImport("tracer", tracer.module("tracer"));
227 exe.root_module.addImport("tracer", b.dependency("tracer", dep_opts).module("tracer"));
228
229 if (config.have_embedded_quickjs) {
230 exe.root_module.addImport("quickjs", b.dependency("quickjs", dep_opts).module("quickjs_libc"));
231 }
232
233233 return exe;
234234 }
235235};
src/cli.zig+71-6
......@@ -5,6 +5,7 @@
55//! needing to compile the formatter.
66
77const have_debug_features = builtin.mode == .Debug;
8const config = @import("build_config").config;
89
910pub fn main() !u8 {
1011 try tracer.init();
......@@ -37,6 +38,7 @@ pub fn main() !u8 {
3738 defer if (exe_name) |path| alloc.free(path);
3839 var dump_ir = false;
3940 var dump_state: ?[]const u8 = null;
41 var run = false;
4042 var has_errors = false;
4143 {
4244 var args = try std.process.argsWithAllocator(alloc);
......@@ -61,6 +63,11 @@ pub fn main() !u8 {
6163 continue;
6264 }
6365
66 if (config.have_embedded_quickjs and std.mem.eql(u8, arg, "--run")) {
67 run = true;
68 continue;
69 }
70
6471 std.debug.print("error: unknown flag '{s}'\n", .{arg});
6572 has_errors = true;
6673 break;
......@@ -89,7 +96,13 @@ pub fn main() !u8 {
8996 \\
9097 , .{});
9198 }
92 if (builtin.mode == .Debug) {
99 if (config.have_embedded_quickjs) {
100 std.debug.print(
101 \\ --run Run program using QuickJS
102 \\
103 , .{});
104 }
105 if (have_debug_features) {
93106 std.debug.print(
94107 \\
95108 \\Debug Mode Flags:
......@@ -129,6 +142,7 @@ pub fn main() !u8 {
129142 error.TransformFail => {
130143 std.debug.print("Transform failed:\n", .{});
131144 try fail_report.dumpToStdErr(&comp);
145 fail_report.deinit(comp.gpa);
132146 return 1;
133147 },
134148 error.ParseFail => {
......@@ -148,17 +162,68 @@ pub fn main() !u8 {
148162 else => return err,
149163 };
150164
151 const output = std.io.getStdOut().writer();
152 var bufw = std.io.bufferedWriter(output);
153 const writer = bufw.writer();
154 try js_backend.link(&comp, entry_point, writer.any());
155 try bufw.flush();
165 if (config.have_embedded_quickjs and run) {
166 // Execute with QuickJS
167 var out: std.ArrayListUnmanaged(u8) = .{};
168 defer out.deinit(alloc);
169 try js_backend.link(&comp, entry_point, out.writer(alloc).any());
170 try out.append(alloc, 0);
171 try runWithQuickJs(out.items[0 .. out.items.len - 1 :0]);
172 } else {
173 // Output to standard out
174 const output = std.io.getStdOut().writer();
175 var bufw = std.io.bufferedWriter(output);
176 const writer = bufw.writer();
177 try js_backend.link(&comp, entry_point, writer.any());
178 try bufw.flush();
179 }
156180 }
157181
158182 std.process.cleanExit();
159183 return 0;
160184}
161185
186fn runWithQuickJs(js: [:0]const u8) !void {
187 const qjs = @import("quickjs");
188
189 const runtime = qjs.JS_NewRuntime() orelse
190 return error.UnexpectedError;
191 defer qjs.JS_FreeRuntime(runtime);
192 const js_ctx = qjs.JS_NewContext(runtime) orelse
193 return error.UnexpectedError;
194 defer qjs.JS_FreeContext(js_ctx);
195
196 // QuickJS provides a completely blank global context. It is a non-goal to
197 // be a full runtime, but adding simple globals to align with expectations
198 // is OK.
199
200 // 0 and null is zero process args
201 qjs.js_std_add_helpers(js_ctx, 0, null);
202
203 const result = qjs.JS_Eval(
204 js_ctx,
205 js.ptr,
206 js.len,
207 "test.js",
208 qjs.JS_EVAL_TYPE_GLOBAL,
209 );
210 defer qjs.JS_FreeValue(js_ctx, result);
211
212 if (qjs.JS_IsException(result) != 0) {
213 const exception = qjs.JS_GetException(js_ctx);
214 defer qjs.JS_FreeValue(js_ctx, exception);
215
216 const exception_str = qjs.JS_ToCString(js_ctx, exception);
217 defer qjs.JS_FreeCString(js_ctx, exception_str);
218
219 const slice = std.mem.span(exception_str);
220
221 std.debug.print("Exception: {s}\n", .{slice});
222
223 std.process.exit(1);
224 }
225}
226
162227const core = @import("core");
163228const Comp = core.Comp;
164229const Report = core.Report;
src/deps/quickjs/build.zig+103-3
......@@ -2,6 +2,9 @@ pub fn build(b: *Build) !void {
22 const target = b.standardTargetOptions(.{});
33 const optimize = b.standardOptimizeOption(.{});
44
5 const pthread = WinPthreads.get(b, target, optimize);
6 const pthread_native = WinPthreads.get(b, b.graph.host, .Debug);
7
58 const src = b.dependency("quickjs", .{});
69
710 const version = std.mem.trim(
......@@ -35,8 +38,9 @@ pub fn build(b: *Build) !void {
3538 .name = "quickjs",
3639 .target = target,
3740 .optimize = optimize,
41 .link_libc = true,
3842 });
39
43 pthread.configure(libquickjs);
4044 libquickjs.addCSourceFiles(.{
4145 .root = src.path(""),
4246 .files = &.{
......@@ -52,11 +56,31 @@ pub fn build(b: *Build) !void {
5256 libquickjs.root_module.addCMacro(def.name, def.value);
5357 }
5458
59 const libquickjs_libc = b.addStaticLibrary(.{
60 .name = "quickjs_libc",
61 .target = target,
62 .optimize = optimize,
63 .link_libc = true,
64 });
65 pthread.configure(libquickjs_libc);
66 libquickjs_libc.addCSourceFiles(.{
67 .root = src.path(""),
68 .files = &.{
69 "quickjs-libc.c",
70 },
71 .flags = c_flags,
72 });
73 for (defines) |def| {
74 libquickjs_libc.root_module.addCMacro(def.name, def.value);
75 }
76
5577 const qjsc = b.addExecutable(.{
5678 .name = "qjsc",
5779 .target = b.graph.host,
5880 .optimize = .Debug,
81 .link_libc = true,
5982 });
83 pthread_native.configure(qjsc);
6084 qjsc.addCSourceFiles(.{
6185 .root = src.path(""),
6286 .files = &.{
......@@ -78,12 +102,13 @@ pub fn build(b: *Build) !void {
78102 .name = "qjs",
79103 .target = target,
80104 .optimize = optimize,
105 .link_libc = true,
81106 });
107 pthread.configure(qjs);
82108 qjs.addCSourceFiles(.{
83109 .root = src.path(""),
84110 .files = &.{
85111 "qjs.c",
86 "quickjs-libc.c",
87112 },
88113 .flags = c_flags,
89114 });
......@@ -99,18 +124,32 @@ pub fn build(b: *Build) !void {
99124 qjs.root_module.addCMacro(def.name, def.value);
100125 }
101126 qjs.linkLibrary(libquickjs);
127 qjs.linkLibrary(libquickjs_libc);
102128
103129 b.installArtifact(qjs);
104130 b.installArtifact(libquickjs);
131 b.installArtifact(libquickjs_libc);
105132
106133 const translate = b.addTranslateC(.{
107134 .root_source_file = src.path("quickjs.h"),
108135 .target = target,
109136 .optimize = optimize,
110 .link_libc = false,
137 .link_libc = true,
111138 });
139 if (pthread.pthreads) |pt| translate.addIncludeDir(pt.include.getPath(b));
112140 const module = translate.addModule("quickjs");
113141 module.linkLibrary(libquickjs);
142
143 const translate_libc = b.addTranslateC(.{
144 .root_source_file = src.path("quickjs-libc.h"),
145 .target = target,
146 .optimize = optimize,
147 .link_libc = true,
148 });
149 const module2 = translate_libc.addModule("quickjs_libc");
150 if (pthread.pthreads) |pt| translate_libc.addIncludeDir(pt.include.getPath(b));
151 module2.linkLibrary(libquickjs);
152 module2.linkLibrary(libquickjs_libc);
114153}
115154
116155fn runQjsc(b: *Build, qjsc: *Build.Step.Compile, in: Build.LazyPath) Build.LazyPath {
......@@ -124,5 +163,66 @@ fn runQjsc(b: *Build, qjsc: *Build.Step.Compile, in: Build.LazyPath) Build.LazyP
124163 return out;
125164}
126165
166/// Zig doesnt include winpthreads, so we build it from source. This helper
167/// decides if it is needed, and provides a no-op `configure` function if it is
168/// not actually needed. Call .configure on any object files you need.
169const WinPthreads = struct {
170 pthreads: ?struct {
171 library: *Build.Step.Compile,
172 include: Build.LazyPath,
173 } = null,
174
175 pub fn get(
176 b: *Build,
177 target: Build.ResolvedTarget,
178 optimize: std.builtin.OptimizeMode,
179 ) WinPthreads {
180 if (target.result.os.tag == .windows) {
181 const dep = b.lazyDependency("mingw-w64", .{}) orelse
182 return .{};
183
184 const libpthread = b.addStaticLibrary(.{
185 .name = "winpthreads",
186 .target = target,
187 .optimize = optimize,
188 .link_libc = true,
189 });
190
191 libpthread.addCSourceFiles(.{
192 .root = dep.path("mingw-w64-libraries/winpthreads/src"),
193 .files = &.{
194 "barrier.c",
195 "clock.c",
196 "cond.c",
197 "misc.c",
198 "mutex.c",
199 "nanosleep.c",
200 "ref.c",
201 "rwlock.c",
202 "sched.c",
203 "sem.c",
204 "spinlock.c",
205 "thread.c",
206 },
207 });
208
209 libpthread.addIncludePath(dep.path("mingw-w64-libraries/winpthreads/include"));
210
211 return .{ .pthreads = .{
212 .library = libpthread,
213 .include = dep.path("mingw-w64-libraries/winpthreads/include"),
214 } };
215 }
216 return .{};
217 }
218
219 pub fn configure(this: WinPthreads, compile: *Build.Step.Compile) void {
220 if (this.pthreads) |pthreads| {
221 compile.linkLibrary(pthreads.library);
222 compile.addIncludePath(pthreads.include);
223 }
224 }
225};
226
127227const std = @import("std");
128228const Build = std.Build;
src/deps/quickjs/build.zig.zon+8
......@@ -7,6 +7,14 @@
77 .url = "https://github.com/bellard/quickjs/archive/6e2e68fd0896957f92eb6c242a2e048c1ef3cae0.tar.gz",
88 .hash = "1220d49e57fc131eebbf4b09fb100f5d802b909d2f36e15d2d849a72f354cd24489d",
99 },
10
11 // Required for building "pthread.h" on Windows
12 // https://github.com/ziglang/zig/issues/10989
13 .@"mingw-w64" = .{
14 .url = "https://github.com/mirror/mingw-w64/archive/eff726c461e09f35eeaed125a3570fa5f807f02b.tar.gz",
15 .hash = "1220cb412e58a63679fd29943e90331c4cc4d301382d792b1fba570eabfb0b032c81",
16 .lazy = true,
17 },
1018 },
1119
1220 .paths = .{