5 files changed, 207 insertions(+), 33 deletions(-)
CHANGELOG.md+1| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | ## 0.1.6 |
| 2 | 2 | |
| 3 | - feat: add `--run` to execute the file in QuickJS instead of outputting source | |
| 3 | 4 | - fix: crash when printing unused struct declaration error |
| 4 | 5 | - fix: provide array result type to sema |
| 5 | 6 | - 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 { |
| 66 | 66 | const native_debug = buildWithTarget(b, b.graph.host, .Debug, .none, version, no_llvm); |
| 67 | 67 | const main = buildWithTarget(b, target, optimize, tracing, version, no_llvm); |
| 68 | 68 | |
| 69 | b.installArtifact(main.cli(b, .{})); | |
| 69 | b.installArtifact(main.cli(b, BuildConfig.all)); | |
| 70 | 70 | |
| 71 | 71 | inline for (.{ |
| 72 | 72 | .{ main.cli(b, BuildConfig.minimal), "compiler" }, |
| ... | ... | @@ -159,28 +159,25 @@ pub fn build(b: *Build) !void { |
| 159 | 159 | @tagName(cross_target.result.os.tag), |
| 160 | 160 | }, |
| 161 | 161 | ) catch @panic("OOM"); |
| 162 | _ = name; // autofix | |
| 163 | 162 | |
| 164 | 163 | 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 | } | |
| 184 | 181 | |
| 185 | 182 | package.dependOn(&b.addInstallFile(b.path("CHANGELOG.md"), "package/CHANGELOG.md").step); |
| 186 | 183 | package.dependOn(&b.addInstallFile(manual_out, "package/README.html").step); |
| ... | ... | @@ -208,8 +205,6 @@ const Artifacts = struct { |
| 208 | 205 | const use_llvm = if (a.no_llvm) false else null; |
| 209 | 206 | const use_lld = if (a.no_llvm) false else null; |
| 210 | 207 | |
| 211 | const tracer = b.dependency("tracer", dep_opts); | |
| 212 | ||
| 213 | 208 | // Options |
| 214 | 209 | const build_config = b.addOptions(); |
| 215 | 210 | build_config.addOption(BuildConfig, "config", config); |
| ... | ... | @@ -229,7 +224,12 @@ const Artifacts = struct { |
| 229 | 224 | exe.root_module.addImport("build_options", a.opts_mod); |
| 230 | 225 | exe.root_module.addImport("build_config", build_config_mod); |
| 231 | 226 | 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 | ||
| 233 | 233 | return exe; |
| 234 | 234 | } |
| 235 | 235 | }; |
src/cli.zig+71-6| ... | ... | @@ -5,6 +5,7 @@ |
| 5 | 5 | //! needing to compile the formatter. |
| 6 | 6 | |
| 7 | 7 | const have_debug_features = builtin.mode == .Debug; |
| 8 | const config = @import("build_config").config; | |
| 8 | 9 | |
| 9 | 10 | pub fn main() !u8 { |
| 10 | 11 | try tracer.init(); |
| ... | ... | @@ -37,6 +38,7 @@ pub fn main() !u8 { |
| 37 | 38 | defer if (exe_name) |path| alloc.free(path); |
| 38 | 39 | var dump_ir = false; |
| 39 | 40 | var dump_state: ?[]const u8 = null; |
| 41 | var run = false; | |
| 40 | 42 | var has_errors = false; |
| 41 | 43 | { |
| 42 | 44 | var args = try std.process.argsWithAllocator(alloc); |
| ... | ... | @@ -61,6 +63,11 @@ pub fn main() !u8 { |
| 61 | 63 | continue; |
| 62 | 64 | } |
| 63 | 65 | |
| 66 | if (config.have_embedded_quickjs and std.mem.eql(u8, arg, "--run")) { | |
| 67 | run = true; | |
| 68 | continue; | |
| 69 | } | |
| 70 | ||
| 64 | 71 | std.debug.print("error: unknown flag '{s}'\n", .{arg}); |
| 65 | 72 | has_errors = true; |
| 66 | 73 | break; |
| ... | ... | @@ -89,7 +96,13 @@ pub fn main() !u8 { |
| 89 | 96 | \\ |
| 90 | 97 | , .{}); |
| 91 | 98 | } |
| 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) { | |
| 93 | 106 | std.debug.print( |
| 94 | 107 | \\ |
| 95 | 108 | \\Debug Mode Flags: |
| ... | ... | @@ -129,6 +142,7 @@ pub fn main() !u8 { |
| 129 | 142 | error.TransformFail => { |
| 130 | 143 | std.debug.print("Transform failed:\n", .{}); |
| 131 | 144 | try fail_report.dumpToStdErr(&comp); |
| 145 | fail_report.deinit(comp.gpa); | |
| 132 | 146 | return 1; |
| 133 | 147 | }, |
| 134 | 148 | error.ParseFail => { |
| ... | ... | @@ -148,17 +162,68 @@ pub fn main() !u8 { |
| 148 | 162 | else => return err, |
| 149 | 163 | }; |
| 150 | 164 | |
| 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 | } | |
| 156 | 180 | } |
| 157 | 181 | |
| 158 | 182 | std.process.cleanExit(); |
| 159 | 183 | return 0; |
| 160 | 184 | } |
| 161 | 185 | |
| 186 | fn 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 | ||
| 162 | 227 | const core = @import("core"); |
| 163 | 228 | const Comp = core.Comp; |
| 164 | 229 | const Report = core.Report; |
src/deps/quickjs/build.zig+103-3| ... | ... | @@ -2,6 +2,9 @@ pub fn build(b: *Build) !void { |
| 2 | 2 | const target = b.standardTargetOptions(.{}); |
| 3 | 3 | const optimize = b.standardOptimizeOption(.{}); |
| 4 | 4 | |
| 5 | const pthread = WinPthreads.get(b, target, optimize); | |
| 6 | const pthread_native = WinPthreads.get(b, b.graph.host, .Debug); | |
| 7 | ||
| 5 | 8 | const src = b.dependency("quickjs", .{}); |
| 6 | 9 | |
| 7 | 10 | const version = std.mem.trim( |
| ... | ... | @@ -35,8 +38,9 @@ pub fn build(b: *Build) !void { |
| 35 | 38 | .name = "quickjs", |
| 36 | 39 | .target = target, |
| 37 | 40 | .optimize = optimize, |
| 41 | .link_libc = true, | |
| 38 | 42 | }); |
| 39 | ||
| 43 | pthread.configure(libquickjs); | |
| 40 | 44 | libquickjs.addCSourceFiles(.{ |
| 41 | 45 | .root = src.path(""), |
| 42 | 46 | .files = &.{ |
| ... | ... | @@ -52,11 +56,31 @@ pub fn build(b: *Build) !void { |
| 52 | 56 | libquickjs.root_module.addCMacro(def.name, def.value); |
| 53 | 57 | } |
| 54 | 58 | |
| 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 | ||
| 55 | 77 | const qjsc = b.addExecutable(.{ |
| 56 | 78 | .name = "qjsc", |
| 57 | 79 | .target = b.graph.host, |
| 58 | 80 | .optimize = .Debug, |
| 81 | .link_libc = true, | |
| 59 | 82 | }); |
| 83 | pthread_native.configure(qjsc); | |
| 60 | 84 | qjsc.addCSourceFiles(.{ |
| 61 | 85 | .root = src.path(""), |
| 62 | 86 | .files = &.{ |
| ... | ... | @@ -78,12 +102,13 @@ pub fn build(b: *Build) !void { |
| 78 | 102 | .name = "qjs", |
| 79 | 103 | .target = target, |
| 80 | 104 | .optimize = optimize, |
| 105 | .link_libc = true, | |
| 81 | 106 | }); |
| 107 | pthread.configure(qjs); | |
| 82 | 108 | qjs.addCSourceFiles(.{ |
| 83 | 109 | .root = src.path(""), |
| 84 | 110 | .files = &.{ |
| 85 | 111 | "qjs.c", |
| 86 | "quickjs-libc.c", | |
| 87 | 112 | }, |
| 88 | 113 | .flags = c_flags, |
| 89 | 114 | }); |
| ... | ... | @@ -99,18 +124,32 @@ pub fn build(b: *Build) !void { |
| 99 | 124 | qjs.root_module.addCMacro(def.name, def.value); |
| 100 | 125 | } |
| 101 | 126 | qjs.linkLibrary(libquickjs); |
| 127 | qjs.linkLibrary(libquickjs_libc); | |
| 102 | 128 | |
| 103 | 129 | b.installArtifact(qjs); |
| 104 | 130 | b.installArtifact(libquickjs); |
| 131 | b.installArtifact(libquickjs_libc); | |
| 105 | 132 | |
| 106 | 133 | const translate = b.addTranslateC(.{ |
| 107 | 134 | .root_source_file = src.path("quickjs.h"), |
| 108 | 135 | .target = target, |
| 109 | 136 | .optimize = optimize, |
| 110 | .link_libc = false, | |
| 137 | .link_libc = true, | |
| 111 | 138 | }); |
| 139 | if (pthread.pthreads) |pt| translate.addIncludeDir(pt.include.getPath(b)); | |
| 112 | 140 | const module = translate.addModule("quickjs"); |
| 113 | 141 | 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); | |
| 114 | 153 | } |
| 115 | 154 | |
| 116 | 155 | fn 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 |
| 124 | 163 | return out; |
| 125 | 164 | } |
| 126 | 165 | |
| 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. | |
| 169 | const 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 | ||
| 127 | 227 | const std = @import("std"); |
| 128 | 228 | const Build = std.Build; |
src/deps/quickjs/build.zig.zon+8| ... | ... | @@ -7,6 +7,14 @@ |
| 7 | 7 | .url = "https://github.com/bellard/quickjs/archive/6e2e68fd0896957f92eb6c242a2e048c1ef3cae0.tar.gz", |
| 8 | 8 | .hash = "1220d49e57fc131eebbf4b09fb100f5d802b909d2f36e15d2d849a72f354cd24489d", |
| 9 | 9 | }, |
| 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 | }, | |
| 10 | 18 | }, |
| 11 | 19 | |
| 12 | 20 | .paths = .{ |