aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.vscode/launch.json14
-rw-r--r--build.zig3
-rw-r--r--src/bundler.zig16
-rw-r--r--src/css_scanner.zig8
-rw-r--r--src/global.zig21
-rw-r--r--src/javascript/jsc/JavascriptCore.zig7
m---------src/javascript/jsc/WebKit0
-rw-r--r--src/javascript/jsc/base.zig143
-rw-r--r--src/javascript/jsc/bindings/ZigGlobalObject.cpp12
-rw-r--r--src/javascript/jsc/bindings/bindings.cpp399
-rw-r--r--src/javascript/jsc/bindings/bindings.zig34
-rw-r--r--src/javascript/jsc/bindings/exports.zig319
-rw-r--r--src/javascript/jsc/bindings/header-gen.zig17
-rw-r--r--src/javascript/jsc/bindings/headers-cpp.h8
-rw-r--r--src/javascript/jsc/bindings/headers-handwritten.h95
-rw-r--r--src/javascript/jsc/bindings/headers.zig6
-rw-r--r--src/javascript/jsc/bindings/helpers.h10
-rw-r--r--src/javascript/jsc/bindings/static_export.zig1
-rw-r--r--src/javascript/jsc/javascript.zig516
-rw-r--r--src/javascript/jsc/webcore/response.zig22
-rw-r--r--src/js_parser/js_parser.zig14
-rw-r--r--src/js_printer.zig54
-rw-r--r--src/linker.zig11
-rw-r--r--src/logger.zig70
-rw-r--r--src/runtime/errors.ts82
-rw-r--r--src/runtime/index.ts1
-rw-r--r--src/tagged_pointer.zig186
27 files changed, 1744 insertions, 325 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 590185982..41b9d64af 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -53,6 +53,20 @@
{
"type": "lldb",
"request": "launch",
+ "name": "Eval Error",
+ "program": "${workspaceFolder}/build/debug/macos-x86_64/spjs",
+ "args": [
+ "error.js",
+ "--resolve=dev",
+ "--outdir=outcss"
+ // "--public-url=https://localhost:9000/"
+ ],
+ "cwd": "${workspaceFolder}",
+ "console": "internalConsole"
+ },
+ {
+ "type": "lldb",
+ "request": "launch",
"name": "Eval",
"program": "${workspaceFolder}/build/debug/macos-x86_64/spjs",
"args": [
diff --git a/build.zig b/build.zig
index d2df9f78e..4417e7af6 100644
--- a/build.zig
+++ b/build.zig
@@ -223,14 +223,13 @@ pub fn build(b: *std.build.Builder) void {
translate_c.out_basename = "headers";
translate_c.output_dir = b.pathFromRoot("src/javascript/jsc/bindings/");
headers_step.dependOn(&translate_c.step);
-
headers_zig_file = b.pathFromRoot("src/javascript/jsc/bindings/headers.zig");
original_make_fn = headers_step.makeFn;
headers_step.makeFn = HeadersMaker.make;
b.default_step.dependOn(&exe.step);
- var steps = [_]*std.build.LibExeObjStep{ exe, javascript, typings_exe };
+ var steps = [_]*std.build.LibExeObjStep{ exe, javascript, typings_exe, headers_exec };
for (steps) |step| {
step.linkLibC();
diff --git a/src/bundler.zig b/src/bundler.zig
index b31fb8308..d2488be89 100644
--- a/src/bundler.zig
+++ b/src/bundler.zig
@@ -539,8 +539,20 @@ pub fn NewBundler(cache_files: bool) type {
// Since we trim the prefixes, we must also compare the package name
pub fn sortJavascriptModuleByPath(ctx: *GenerateNodeModuleBundle, a: Api.JavascriptBundledModule, b: Api.JavascriptBundledModule) bool {
- return switch (std.mem.order(u8, ctx.metadataStringPointer(ctx.package_list.items[a.package_id].name), ctx.metadataStringPointer(ctx.package_list.items[b.package_id].name))) {
- .eq => std.mem.order(u8, ctx.metadataStringPointer(a.path), ctx.metadataStringPointer(b.path)) == .lt,
+ return switch (std.mem.order(
+ u8,
+ ctx.metadataStringPointer(
+ ctx.package_list.items[a.package_id].name,
+ ),
+ ctx.metadataStringPointer(
+ ctx.package_list.items[b.package_id].name,
+ ),
+ )) {
+ .eq => std.mem.order(
+ u8,
+ ctx.metadataStringPointer(a.path),
+ ctx.metadataStringPointer(b.path),
+ ) == .lt,
.lt => true,
else => false,
};
diff --git a/src/css_scanner.zig b/src/css_scanner.zig
index d26fbf1a1..e39515292 100644
--- a/src/css_scanner.zig
+++ b/src/css_scanner.zig
@@ -316,7 +316,13 @@ pub const Scanner = struct {
return text;
}
- pub fn next(scanner: *Scanner, comptime import_behavior: ImportBehavior, comptime WriterType: type, writer: WriterType, writeChunk: (fn (ctx: WriterType, Chunk) anyerror!void)) !void {
+ pub fn next(
+ scanner: *Scanner,
+ comptime import_behavior: ImportBehavior,
+ comptime WriterType: type,
+ writer: WriterType,
+ writeChunk: (fn (ctx: WriterType, Chunk) anyerror!void),
+ ) !void {
scanner.has_newline_before = scanner.end == 0;
scanner.has_delimiter_before = false;
scanner.step();
diff --git a/src/global.zig b/src/global.zig
index daa30e676..496136a29 100644
--- a/src/global.zig
+++ b/src/global.zig
@@ -62,6 +62,10 @@ pub const Output = struct {
return source.error_stream.writer();
}
+ pub fn errorStream() Source.StreamType {
+ return source.error_stream;
+ }
+
pub fn writer() WriterType {
return source.stream.writer();
}
@@ -134,7 +138,7 @@ pub const Output = struct {
// <d> - dim
// </r> - reset
// <r> - reset
- fn _pretty(comptime fmt: string, args: anytype, comptime printer: anytype, comptime is_enabled: bool) void {
+ pub fn prettyFmt(comptime fmt: string, comptime is_enabled: bool) string {
comptime var new_fmt: [fmt.len * 4]u8 = undefined;
comptime var new_fmt_i: usize = 0;
const ED = comptime "\x1b[";
@@ -205,7 +209,7 @@ pub const Output = struct {
is_reset = true;
break :color_picker "";
} else {
- @compileError("Invalid color name passed:" ++ color_name);
+ @compileError("Invalid color name passed: " ++ color_name);
}
};
var orig = new_fmt_i;
@@ -233,18 +237,19 @@ pub const Output = struct {
},
}
};
- printer(new_fmt[0..new_fmt_i], args);
+
+ return comptime new_fmt[0..new_fmt_i];
}
- pub fn prettyWithPrinter(comptime fmt: string, args: anytype, printer: anytype, comptime l: Level) void {
+ pub fn prettyWithPrinter(comptime fmt: string, args: anytype, comptime printer: anytype, comptime l: Level) void {
if (comptime l == .Warn) {
if (level == .Error) return;
}
if (enable_ansi_colors) {
- _pretty(fmt, args, printer, true);
+ printer(comptime prettyFmt(fmt, true), args);
} else {
- _pretty(fmt, args, printer, false);
+ printer(comptime prettyFmt(fmt, false), args);
}
}
@@ -254,9 +259,9 @@ pub const Output = struct {
pub fn prettyln(comptime fmt: string, args: anytype) void {
if (enable_ansi_colors) {
- _pretty(fmt, args, println, true);
+ println(comptime prettyFmt(fmt, true), args);
} else {
- _pretty(fmt, args, println, false);
+ println(comptime prettyFmt(fmt, false), args);
}
}
diff --git a/src/javascript/jsc/JavascriptCore.zig b/src/javascript/jsc/JavascriptCore.zig
index f5299cd08..25bb40c5a 100644
--- a/src/javascript/jsc/JavascriptCore.zig
+++ b/src/javascript/jsc/JavascriptCore.zig
@@ -18,9 +18,9 @@ pub const JSPropertyNameArrayRef = ?*struct_OpaqueJSPropertyNameArray;
pub const struct_OpaqueJSPropertyNameAccumulator = generic;
pub const JSPropertyNameAccumulatorRef = ?*struct_OpaqueJSPropertyNameAccumulator;
pub const JSTypedArrayBytesDeallocator = ?fn (?*c_void, ?*c_void) callconv(.C) void;
-pub const struct_OpaqueJSValue = generic;
-pub const JSValueRef = ?*struct_OpaqueJSValue;
-pub const JSObjectRef = ?*struct_OpaqueJSValue;
+pub const OpaqueJSValue = opaque {};
+pub const JSValueRef = ?*OpaqueJSValue;
+pub const JSObjectRef = ?*OpaqueJSValue;
pub extern fn JSEvaluateScript(ctx: JSContextRef, script: JSStringRef, thisObject: JSObjectRef, sourceURL: JSStringRef, startingLineNumber: c_int, exception: ExceptionRef) JSValueRef;
pub extern fn JSCheckScriptSyntax(ctx: JSContextRef, script: JSStringRef, sourceURL: JSStringRef, startingLineNumber: c_int, exception: ExceptionRef) bool;
pub extern fn JSGarbageCollect(ctx: JSContextRef) void;
@@ -242,7 +242,6 @@ pub const OpaqueJSString = struct_OpaqueJSString;
pub const OpaqueJSClass = struct_OpaqueJSClass;
pub const OpaqueJSPropertyNameArray = struct_OpaqueJSPropertyNameArray;
pub const OpaqueJSPropertyNameAccumulator = struct_OpaqueJSPropertyNameAccumulator;
-pub const OpaqueJSValue = struct_OpaqueJSValue;
// const JSProcessID = ;
pub extern fn JSRemoteInspectorDisableAutoStart() void;
diff --git a/src/javascript/jsc/WebKit b/src/javascript/jsc/WebKit
-Subproject 4eb8a5a13ba6f023d9dddf975996052a6f8b5fe
+Subproject e17b749830a4e3faf87f751630fdcc149906ee9
diff --git a/src/javascript/jsc/base.zig b/src/javascript/jsc/base.zig
index 7bd9b96a4..6f39349a9 100644
--- a/src/javascript/jsc/base.zig
+++ b/src/javascript/jsc/base.zig
@@ -1,7 +1,12 @@
pub const js = @import("./JavaScriptCore.zig");
const std = @import("std");
pub usingnamespace @import("../../global.zig");
-const javascript = @import("./javascript.zig");
+usingnamespace @import("./javascript.zig");
+usingnamespace @import("./webcore/response.zig");
+
+const TaggedPointerTypes = @import("../../tagged_pointer.zig");
+const TaggedPointerUnion = TaggedPointerTypes.TaggedPointerUnion;
+
pub const ExceptionValueRef = [*c]js.JSValueRef;
pub const JSValueRef = js.JSValueRef;
@@ -26,10 +31,10 @@ pub const To = struct {
) js.JSValueRef,
) js.JSObjectRef {
var function = js.JSObjectMakeFunctionWithCallback(ctx, name, Callback(ZigContextType, callback).rfn);
- _ = js.JSObjectSetPrivate(
+ std.debug.assert(js.JSObjectSetPrivate(
function,
- @ptrCast(*c_void, @alignCast(@alignOf(*c_void), zig)),
- );
+ JSPrivateDataPtr.init(zig).ptr(),
+ ));
return function;
}
@@ -44,12 +49,8 @@ pub const To = struct {
pub fn rfn(
object: js.JSObjectRef,
) callconv(.C) void {
- var object_ptr_ = js.JSObjectGetPrivate(object);
- if (object_ptr_ == null) return;
-
return ctxfn(
- @ptrCast(*ZigContextType, @alignCast(@alignOf(*ZigContextType), object_ptr_.?)),
- object,
+ GetJSPrivateData(ZigContextType, object) orelse return,
);
}
};
@@ -128,26 +129,25 @@ pub const To = struct {
) callconv(.C) js.JSValueRef {
var object_ptr: *c_void = undefined;
- if (comptime ZigContextType != c_void) {
- var object_ptr_ = js.JSObjectGetPrivate(function);
- if (object_ptr_ == null) {
- object_ptr_ = js.JSObjectGetPrivate(thisObject);
- }
-
- if (object_ptr_ == null) {
- return js.JSValueMakeUndefined(ctx);
- }
- object_ptr = object_ptr_.?;
+ if (comptime ZigContextType == c_void) {
+ return ctxfn(
+ js.JSObjectGetPrivate(function) or js.jsObjectGetPrivate(thisObject),
+ ctx,
+ function,
+ thisObject,
+ if (arguments) |args| args[0..argumentCount] else &[_]js.JSValueRef{},
+ exception,
+ );
+ } else {
+ return ctxfn(
+ GetJSPrivateData(ZigContextType, function) orelse GetJSPrivateData(ZigContextType, thisObject) orelse return js.JSValueMakeUndefined(ctx),
+ ctx,
+ function,
+ thisObject,
+ if (arguments) |args| args[0..argumentCount] else &[_]js.JSValueRef{},
+ exception,
+ );
}
-
- return ctxfn(
- @ptrCast(*ZigContextType, @alignCast(@alignOf(*ZigContextType), object_ptr)),
- ctx,
- function,
- thisObject,
- if (arguments) |args| args[0..argumentCount] else &[_]js.JSValueRef{},
- exception,
- );
}
};
}
@@ -164,15 +164,7 @@ pub const To = struct {
return buf[0..js.JSStringGetUTF8CString(Ref.str(ref), buf.ptr, buf.len)];
}
pub inline fn ptr(comptime StructType: type, obj: js.JSObjectRef) *StructType {
- return @ptrCast(
- *StructType,
- @alignCast(
- @alignOf(
- *StructType,
- ),
- js.JSObjectGetPrivate(obj).?,
- ),
- );
+ return GetJSPrivateData(StructType, obj).?;
}
};
};
@@ -764,10 +756,6 @@ pub fn NewClass(
pub const static_value_count = static_properties.len;
- pub fn new(ctx: js.JSContextRef, ptr: ?*ZigType) js.JSObjectRef {
- return js.JSObjectMake(ctx, get().*, ptr);
- }
-
pub fn get() callconv(.C) [*c]js.JSClassRef {
if (!loaded) {
loaded = true;
@@ -795,6 +783,17 @@ pub fn NewClass(
return ClassGetter;
}
+ pub fn customHasInstance(ctx: js.JSContextRef, obj: js.JSObjectRef, value: js.JSValueRef, exception: ExceptionRef) callconv(.C) bool {
+ return js.JSValueIsObjectOfClass(ctx, obj, get().*);
+ }
+
+ pub fn make(ctx: js.JSContextRef, ptr: *ZigType) callconv(.C) js.JSObjectRef {
+ return js.JSObjectMake(
+ ctx,
+ get().*,
+ JSPrivateDataPtr.init(ptr).ptr(),
+ );
+ }
pub fn GetClass(comptime ReceiverType: type) type {
const ClassGetter = struct {
get: fn (
@@ -825,21 +824,7 @@ pub fn NewClass(
prop: js.JSStringRef,
exception: js.ExceptionRef,
) callconv(.C) js.JSValueRef {
- var instance_pointer_ = js.JSObjectGetPrivate(obj);
- if (comptime ZigType != c_void) {
- if (instance_pointer_ == null) return null;
- }
-
- var instance_pointer: *c_void = if (comptime ZigType == c_void) undefined else instance_pointer_.?;
- var ptr = @ptrCast(
- *ZigType,
- @alignCast(
- @alignOf(
- *ZigType,
- ),
- instance_pointer,
- ),
- );
+ var pointer = GetJSPrivateData(ZigType, obj) orelse return js.JSValueMakeUndefined(ctx);
if (singleton) {
inline for (function_names) |propname, i| {
@@ -876,17 +861,7 @@ pub fn NewClass(
prop: js.JSStringRef,
exception: js.ExceptionRef,
) callconv(.C) js.JSValueRef {
- var instance_pointer_ = js.JSObjectGetPrivate(obj);
- if (instance_pointer_ == null) return null;
- var this: *ZigType = @ptrCast(
- *ZigType,
- @alignCast(
- @alignOf(
- *ZigType,
- ),
- instance_pointer_.?,
- ),
- );
+ var this = GetJSPrivateData(ZigType, obj) orelse return js.JSValueMakeUndefined(ctx);
var exc: js.JSValueRef = null;
const Field = @TypeOf(@field(
@@ -958,17 +933,7 @@ pub fn NewClass(
value: js.JSValueRef,
exception: js.ExceptionRef,
) callconv(.C) bool {
- var instance_pointer_ = js.JSObjectGetPrivate(obj);
- if (instance_pointer_ == null) return false;
- var this: *ZigType = @ptrCast(
- *ZigType,
- @alignCast(
- @alignOf(
- *ZigType,
- ),
- instance_pointer_.?,
- ),
- );
+ var this = GetJSPrivateData(ZigType, obj) orelse return js.JSValueMakeUndefined(ctx);
var exc: js.ExceptionRef = null;
@@ -1375,13 +1340,14 @@ pub fn NewClass(
}
static_properties[i].name = property_names[i][0.. :0].ptr;
}
-
def.staticValues = (&static_properties);
}
def.className = class_name_str;
// def.getProperty = getPropertyCallback;
+ if (!singleton)
+ def.hasInstance = customHasInstance;
return def;
}
};
@@ -1430,8 +1396,19 @@ pub const ArrayBuffer = struct {
};
pub fn castObj(obj: js.JSObjectRef, comptime Type: type) *Type {
- return @ptrCast(
- *Type,
- @alignCast(@alignOf(*Type), js.JSObjectGetPrivate(obj).?),
- );
+ return JSPrivateDataPtr.from(js.JSObjectGetPrivate(obj)).as(Type);
+}
+
+pub const JSPrivateDataPtr = TaggedPointerUnion(.{
+ ResolveError,
+ BuildError,
+ Response,
+ Request,
+ FetchEvent,
+ Headers,
+ Body,
+});
+
+pub inline fn GetJSPrivateData(comptime Type: type, ref: js.JSObjectRef) ?*Type {
+ return JSPrivateDataPtr.from(js.JSObjectGetPrivate(ref)).get(Type);
}
diff --git a/src/javascript/jsc/bindings/ZigGlobalObject.cpp b/src/javascript/jsc/bindings/ZigGlobalObject.cpp
index 8897b8d21..4a4c3ec96 100644
--- a/src/javascript/jsc/bindings/ZigGlobalObject.cpp
+++ b/src/javascript/jsc/bindings/ZigGlobalObject.cpp
@@ -147,7 +147,7 @@ JSC::Identifier GlobalObject::moduleLoaderResolve(JSGlobalObject *globalObject,
return toIdentifier(res.result.value, globalObject);
} else {
auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
- throwException(scope, res.result.err.message, globalObject);
+ throwException(scope, res.result.err, globalObject);
return globalObject->vm().propertyNames->emptyIdentifier;
}
}
@@ -168,7 +168,7 @@ JSC::JSInternalPromise *GlobalObject::moduleLoaderImportModule(JSGlobalObject *g
globalObject, toZigString(moduleNameValue, globalObject),
sourceURL.isEmpty() ? ZigStringCwd : toZigString(sourceURL.fileSystemPath()));
if (!resolved.success) {
- throwException(scope, resolved.result.err.message, globalObject);
+ throwException(scope, resolved.result.err, globalObject);
return promise->rejectWithCaughtException(globalObject, scope);
}
@@ -196,11 +196,15 @@ JSC::JSInternalPromise *GlobalObject::moduleLoaderFetch(JSGlobalObject *globalOb
auto moduleKey = key.toWTFString(globalObject);
RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope));
auto moduleKeyZig = toZigString(moduleKey);
+ ErrorableResolvedSource res;
+ res.success = false;
+ res.result.err.code = 0;
+ res.result.err.ptr = nullptr;
- auto res = Zig__GlobalObject__fetch(globalObject, moduleKeyZig, ZigStringEmpty);
+ Zig__GlobalObject__fetch(&res, globalObject, moduleKeyZig, ZigStringEmpty);
if (!res.success) {
- throwException(scope, res.result.err.message, globalObject);
+ throwException(scope, res.result.err, globalObject);
RETURN_IF_EXCEPTION(scope, promise->rejectWithCaughtException(globalObject, scope));
}
diff --git a/src/javascript/jsc/bindings/bindings.cpp b/src/javascript/jsc/bindings/bindings.cpp
index 9afe9a00b..a7e2849ad 100644
--- a/src/javascript/jsc/bindings/bindings.cpp
+++ b/src/javascript/jsc/bindings/bindings.cpp
@@ -1,10 +1,14 @@
#include "helpers.h"
#include "root.h"
+#include <JavaScriptCore/AggregateError.h>
+#include <JavaScriptCore/BytecodeIndex.h>
+#include <JavaScriptCore/CodeBlock.h>
#include <JavaScriptCore/Completion.h>
#include <JavaScriptCore/ErrorInstance.h>
#include <JavaScriptCore/ExceptionScope.h>
#include <JavaScriptCore/FunctionConstructor.h>
#include <JavaScriptCore/Identifier.h>
+#include <JavaScriptCore/JSArray.h>
#include <JavaScriptCore/JSCInlines.h>
#include <JavaScriptCore/JSCallbackObject.h>
#include <JavaScriptCore/JSClassRef.h>
@@ -16,15 +20,17 @@
#include <JavaScriptCore/JSSet.h>
#include <JavaScriptCore/JSString.h>
#include <JavaScriptCore/ParserError.h>
+#include <JavaScriptCore/ScriptExecutable.h>
#include <JavaScriptCore/StackFrame.h>
+#include <JavaScriptCore/StackVisitor.h>
#include <JavaScriptCore/VM.h>
#include <JavaScriptCore/WasmFaultSignalHandler.h>
#include <wtf/text/ExternalStringImpl.h>
#include <wtf/text/StringCommon.h>
#include <wtf/text/StringImpl.h>
#include <wtf/text/StringView.h>
-#include <wtf/text/WTFString.h>
+#include <wtf/text/WTFString.h>
extern "C" {
// #pragma mark - JSC::PropertyNameArray
@@ -131,18 +137,49 @@ static JSC::JSValue doLink(JSC__JSGlobalObject *globalObject, JSC::JSValue modul
return JSC::linkAndEvaluateModule(globalObject, moduleKey, JSC::JSValue());
}
+JSC__JSValue JSC__JSGlobalObject__createAggregateError(JSC__JSGlobalObject *globalObject,
+ JSC__JSValue *errors, uint16_t errors_count,
+ ZigString arg3) {
+ JSC::VM &vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ JSC::JSValue message = JSC::JSValue(JSC::jsOwnedString(vm, Zig::toString(arg3)));
+ JSC::JSValue options = JSC::jsUndefined();
+ JSC::JSArray *array = nullptr;
+ {
+ JSC::ObjectInitializationScope initializationScope(vm);
+ if ((array = JSC::JSArray::tryCreateUninitializedRestricted(
+ initializationScope, nullptr,
+ globalObject->arrayStructureForIndexingTypeDuringAllocation(JSC::ArrayWithContiguous),
+ errors_count))) {
+
+ for (uint16_t i = 0; i < errors_count; ++i) {
+ array->initializeIndexWithoutBarrier(initializationScope, i,
+ JSC::JSValue::decode(errors[i]));
+ }
+ }
+ }
+ if (!array) {
+ JSC::throwOutOfMemoryError(globalObject, scope);
+ return JSC::JSValue::encode(JSC::JSValue());
+ }
+
+ JSC::Structure *errorStructure = globalObject->errorStructure(JSC::ErrorType::AggregateError);
+ return RELEASE_AND_RETURN(scope, JSC::JSValue::encode(JSC::createAggregateError(
+ globalObject, vm, errorStructure, array, message, options,
+ nullptr, JSC::TypeNothing, false)));
+}
// static JSC::JSNativeStdFunction* resolverFunction;
// static JSC::JSNativeStdFunction* rejecterFunction;
// static bool resolverFunctionInitialized = false;
-static JSC::EncodedJSValue resolverFunctionCallback(JSC::JSGlobalObject *globalObject,
- JSC::CallFrame *callFrame) {
- return JSC::JSValue::encode(doLink(globalObject, callFrame->argument(0)));
+JSC__JSValue ZigString__toValue(ZigString arg0, JSC__JSGlobalObject *arg1) {
+ return JSC::JSValue::encode(JSC::JSValue(JSC::jsOwnedString(arg1->vm(), Zig::toString(arg0))));
}
-static JSC::EncodedJSValue rejecterFunctionCallback(JSC::JSGlobalObject *globalObject,
+static JSC::EncodedJSValue resolverFunctionCallback(JSC::JSGlobalObject *globalObject,
JSC::CallFrame *callFrame) {
- return JSC::JSValue::encode(callFrame->argument(0));
+ return JSC::JSValue::encode(doLink(globalObject, callFrame->argument(0)));
}
JSC__JSInternalPromise *
@@ -157,9 +194,14 @@ JSC__JSModuleLoader__loadAndEvaluateModule(JSC__JSGlobalObject *globalObject, Zi
JSC::JSNativeStdFunction *resolverFunction = JSC::JSNativeStdFunction::create(
globalObject->vm(), globalObject, 1, String(), resolverFunctionCallback);
JSC::JSNativeStdFunction *rejecterFunction = JSC::JSNativeStdFunction::create(
- globalObject->vm(), globalObject, 1, String(), rejecterFunctionCallback);
+ globalObject->vm(), globalObject, 1, String(),
+ [&arg1](JSC::JSGlobalObject *globalObject, JSC::CallFrame *callFrame) -> JSC::EncodedJSValue {
+ return JSC::JSValue::encode(
+ JSC::JSInternalPromise::rejectedPromise(globalObject, callFrame->argument(0)));
+ });
+
globalObject->vm().drainMicrotasks();
- auto result = promise->then(globalObject, resolverFunction, nullptr);
+ auto result = promise->then(globalObject, resolverFunction, rejecterFunction);
globalObject->vm().drainMicrotasks();
// if (promise->status(globalObject->vm()) ==
@@ -687,100 +729,321 @@ bWTF__String JSC__JSValue__toWTFString(JSC__JSValue JSValue0, JSC__JSGlobalObjec
return Wrap<WTF::String, bWTF__String>::wrap(value.toWTFString(arg1));
};
-static ZigException fromErrorInstance(JSC::JSGlobalObject *global, JSC::ErrorInstance *err,
- JSC::JSValue val) {
- ZigException except = Zig::ZigExceptionNone;
- JSC::JSObject *obj = JSC::jsDynamicCast<JSC::JSObject *>(global->vm(), val);
- if (err->stackTrace() != nullptr && err->stackTrace()->size() > 0) {
- JSC::StackFrame *stack = &err->stackTrace()->first();
- except.sourceURL = Zig::toZigString(stack->sourceURL());
-
- if (stack->hasLineAndColumnInfo()) {
- unsigned lineNumber;
- unsigned column;
- stack->computeLineAndColumn(lineNumber, column);
- except.line = lineNumber;
- except.column = column;
+static void populateStackFrameMetadata(const JSC::StackFrame *stackFrame, ZigStackFrame *frame) {
+ frame->source_url = Zig::toZigString(stackFrame->sourceURL());
+
+ if (stackFrame->isWasmFrame()) {
+ frame->code_type = ZigStackFrameCodeWasm;
+ return;
+ }
+
+ auto m_codeBlock = stackFrame->codeBlock();
+ if (m_codeBlock) {
+ switch (m_codeBlock->codeType()) {
+ case JSC::EvalCode: {
+ frame->code_type = ZigStackFrameCodeEval;
+ return;
+ }
+ case JSC::ModuleCode: {
+ frame->code_type = ZigStackFrameCodeModule;
+ return;
+ }
+ case JSC::GlobalCode: {
+ frame->code_type = ZigStackFrameCodeGlobal;
+ return;
+ }
+ case JSC::FunctionCode: {
+ frame->code_type =
+ !m_codeBlock->isConstructor() ? ZigStackFrameCodeFunction : ZigStackFrameCodeConstructor;
+ break;
+ }
+ default: ASSERT_NOT_REACHED();
}
+ }
+
+ auto calleeCell = stackFrame->callee();
+ if (!calleeCell || !calleeCell->isObject()) return;
+
+ JSC::JSObject *callee = JSC::jsCast<JSC::JSObject *>(calleeCell);
+ // Does the code block have a user-defined name property?
+ JSC::JSValue name = callee->getDirect(m_codeBlock->vm(), m_codeBlock->vm().propertyNames->name);
+ if (name && name.isString()) {
+ auto str = name.toWTFString(m_codeBlock->globalObject());
+ frame->function_name = Zig::toZigString(str);
+ return;
+ }
+
+ /* For functions (either JSFunction or InternalFunction), fallback to their "native" name
+ * property. Based on JSC::getCalculatedDisplayName, "inlining" the
+ * JSFunction::calculatedDisplayName\InternalFunction::calculatedDisplayName calls */
+ if (JSC::JSFunction *function =
+ JSC::jsDynamicCast<JSC::JSFunction *>(m_codeBlock->vm(), callee)) {
+
+ WTF::String actualName = function->name(m_codeBlock->vm());
+ if (!actualName.isEmpty() || function->isHostOrBuiltinFunction()) {
+ frame->function_name = Zig::toZigString(actualName);
+ return;
+ }
+
+ auto inferred_name = function->jsExecutable()->name();
+ frame->function_name = Zig::toZigString(inferred_name.string());
+ }
+
+ if (JSC::InternalFunction *function =
+ JSC::jsDynamicCast<JSC::InternalFunction *>(m_codeBlock->vm(), callee)) {
+ // Based on JSC::InternalFunction::calculatedDisplayName, skipping the "displayName" property
+ frame->function_name = Zig::toZigString(function->name());
+ }
+}
+// Based on
+// https://github.com/mceSystems/node-jsc/blob/master/deps/jscshim/src/shim/JSCStackTrace.cpp#L298
+static void populateStackFramePosition(const JSC::StackFrame *stackFrame, ZigString *source_lines,
+ int32_t *source_line_numbers, uint8_t source_lines_count,
+ ZigStackFramePosition *position) {
+ auto m_codeBlock = stackFrame->codeBlock();
+ if (!m_codeBlock) return;
+
+ JSC::BytecodeIndex bytecodeOffset =
+ stackFrame->hasBytecodeIndex() ? stackFrame->bytecodeIndex() : JSC::BytecodeIndex();
+
+ /* Get the "raw" position info.
+ * Note that we're using m_codeBlock->unlinkedCodeBlock()->expressionRangeForBytecodeOffset
+ * rather than m_codeBlock->expressionRangeForBytecodeOffset in order get the "raw" offsets and
+ * avoid the CodeBlock's expressionRangeForBytecodeOffset modifications to the line and column
+ * numbers, (we don't need the column number from it, and we'll calculate the line "fixes"
+ * ourselves). */
+ int startOffset = 0;
+ int endOffset = 0;
+ int divotPoint = 0;
+ unsigned line = 0;
+ unsigned unusedColumn = 0;
+ m_codeBlock->unlinkedCodeBlock()->expressionRangeForBytecodeIndex(
+ bytecodeOffset, divotPoint, startOffset, endOffset, line, unusedColumn);
+ divotPoint += m_codeBlock->sourceOffset();
+
+ // TODO: evaluate if using the API from UnlinkedCodeBlock can be used instead of iterating
+ // through source text.
+
+ /* On the first line of the source code, it seems that we need to "fix" the column with the
+ * starting offset. We currently use codeBlock->source()->startPosition().m_column.oneBasedInt()
+ * as the offset in the first line rather than codeBlock->firstLineColumnOffset(), which seems
+ * simpler (and what CodeBlock::expressionRangeForBytecodeOffset does). This is because
+ * firstLineColumnOffset values seems different from what we expect (according to v8's tests)
+ * and I haven't dove into the relevant parts in JSC (yet) to figure out why. */
+ unsigned columnOffset = line ? 0 : m_codeBlock->source().startColumn().zeroBasedInt();
+
+ // "Fix" the line number
+ JSC::ScriptExecutable *executable = m_codeBlock->ownerExecutable();
+ if (std::optional<int> overrideLine = executable->overrideLineNumber(m_codeBlock->vm())) {
+ line = overrideLine.value();
} else {
- // JSC::ErrorInstance marks these as protected.
- // To work around that, we cast as a JSC::JSObject
- // This code path triggers when there was an exception before the code was executed
- // For example, ParserError becomes one of these
- auto source_url_value = obj->getDirect(global->vm(), global->vm().propertyNames->sourceURL);
- auto str = source_url_value.toWTFString(global);
- except.sourceURL = Zig::toZigString(str);
- except.line = obj->getDirect(global->vm(), global->vm().propertyNames->line).toInt32(global);
- except.column =
- obj->getDirect(global->vm(), global->vm().propertyNames->column).toInt32(global);
+ line += executable->firstLine();
+ }
+
+ // Calculate the staring\ending offsets of the entire expression
+ int expressionStart = divotPoint - startOffset;
+ int expressionStop = divotPoint + endOffset;
+
+ // Make sure the range is valid
+ WTF::StringView sourceString = m_codeBlock->source().provider()->source();
+ if (!expressionStop || expressionStart > static_cast<int>(sourceString.length())) { return; }
+
+ // Search for the beginning of the line
+ unsigned int lineStart = expressionStart;
+ while ((lineStart > 0) && ('\n' != sourceString[lineStart - 1])) { lineStart--; }
+ // Search for the end of the line
+ unsigned int lineStop = expressionStop;
+ unsigned int sourceLength = sourceString.length();
+ while ((lineStop < sourceLength) && ('\n' != sourceString[lineStop])) { lineStop++; }
+ if (source_lines_count > 1 && source_lines != nullptr) {
+ auto chars = sourceString.characters8();
+
+ // Most of the time, when you look at a stack trace, you want a couple lines above
+
+ source_lines[0] = {&chars[lineStart], lineStop - lineStart};
+ source_line_numbers[0] = line;
+
+ if (lineStart > 0) {
+ auto byte_offset_in_source_string = lineStart - 1;
+ uint8_t source_line_i = 1;
+ auto remaining_lines_to_grab = source_lines_count - 1;
+
+ while (byte_offset_in_source_string > 0 && remaining_lines_to_grab > 0) {
+ unsigned int end_of_line_offset = byte_offset_in_source_string;
+
+ // This should probably be code points instead of newlines
+ while (byte_offset_in_source_string > 0 && chars[byte_offset_in_source_string] != '\n') {
+ byte_offset_in_source_string--;
+ }
+
+ // We are at the beginning of the line
+ source_lines[source_line_i] = {&chars[byte_offset_in_source_string],
+ end_of_line_offset - byte_offset_in_source_string + 1};
+
+ source_line_numbers[source_line_i] = line - source_line_i;
+ source_line_i++;
+
+ remaining_lines_to_grab--;
+
+ byte_offset_in_source_string -= byte_offset_in_source_string > 0;
+ }
+ }
}
- if (obj->hasProperty(global, global->vm().propertyNames->stack)) {
- except.stack = Zig::toZigString(
- obj->getDirect(global->vm(), global->vm().propertyNames->stack).toWTFString(global));
+ /* Finally, store the source "positions" info.
+ * Notes:
+ * - The retrieved column seem to point the "end column". To make sure we're current, we'll
+ *calculate the columns ourselves, since we've already found where the line starts. Note that in
+ *v8 it should be 0-based here (in contrast the 1-based column number in v8::StackFrame).
+ * - The static_casts are ugly, but comes from differences between JSC and v8's api, and should
+ *be OK since no source should be longer than "max int" chars.
+ * TODO: If expressionStart == expressionStop, then m_endColumn will be equal to m_startColumn.
+ *Should we handle this case?
+ */
+ position->expression_start = expressionStart;
+ position->expression_stop = expressionStop;
+ position->line = WTF::OrdinalNumber::fromOneBasedInt(static_cast<int>(line)).zeroBasedInt();
+ position->column_start = (expressionStart - lineStart) + columnOffset;
+ position->column_stop = position->column_start + (expressionStop - expressionStart);
+ position->line_start = lineStart;
+ position->line_stop = lineStop;
+
+ return;
+}
+static void populateStackFrame(ZigStackTrace *trace, const JSC::StackFrame *stackFrame,
+ ZigStackFrame *frame, bool is_top) {
+ populateStackFrameMetadata(stackFrame, frame);
+ populateStackFramePosition(stackFrame, is_top ? trace->source_lines_ptr : nullptr,
+ is_top ? trace->source_lines_numbers : nullptr,
+ is_top ? trace->source_lines_to_collect : 0, &frame->position);
+}
+static void populateStackTrace(const WTF::Vector<JSC::StackFrame> &frames, ZigStackTrace *trace) {
+ uint8_t frame_i = 0;
+ size_t stack_frame_i = 0;
+ const size_t total_frame_count = frames.size();
+ const uint8_t frame_count =
+ total_frame_count < trace->frames_len ? total_frame_count : trace->frames_len;
+
+ while (frame_i < frame_count && stack_frame_i < total_frame_count) {
+ // Skip native frames
+ while (stack_frame_i < total_frame_count && !(&frames.at(stack_frame_i))->codeBlock() &&
+ !(&frames.at(stack_frame_i))->isWasmFrame()) {
+ stack_frame_i++;
+ }
+ if (stack_frame_i >= total_frame_count) break;
+
+ ZigStackFrame *frame = &trace->frames_ptr[frame_i];
+ populateStackFrame(trace, &frames[stack_frame_i], frame, frame_i == 0);
+ stack_frame_i++;
+ frame_i++;
+ }
+ trace->frames_len = frame_i;
+}
+static void fromErrorInstance(ZigException *except, JSC::JSGlobalObject *global,
+ JSC::ErrorInstance *err, const Vector<JSC::StackFrame> *stackTrace,
+ JSC::JSValue val) {
+ JSC::JSObject *obj = JSC::jsDynamicCast<JSC::JSObject *>(global->vm(), val);
+ if (stackTrace != nullptr && stackTrace->size() > 0) {
+ populateStackTrace(*stackTrace, &except->stack);
+ } else if (err->stackTrace() != nullptr && err->stackTrace()->size() > 0) {
+ populateStackTrace(*err->stackTrace(), &except->stack);
}
- except.code = (unsigned char)err->errorType();
- if (err->isStackOverflowError()) { except.code = 253; }
- if (err->isOutOfMemoryError()) { except.code = 8; }
+ except->code = (unsigned char)err->errorType();
+ if (err->isStackOverflowError()) { except->code = 253; }
+ if (err->isOutOfMemoryError()) { except->code = 8; }
if (obj->hasProperty(global, global->vm().propertyNames->message)) {
- except.message = Zig::toZigString(
+ except->message = Zig::toZigString(
obj->getDirect(global->vm(), global->vm().propertyNames->message).toWTFString(global));
} else {
- except.message = Zig::toZigString(err->sanitizedMessageString(global));
+ except->message = Zig::toZigString(err->sanitizedMessageString(global));
}
- except.name = Zig::toZigString(err->sanitizedNameString(global));
- except.runtime_type = err->runtimeTypeForCause();
-
- except.exception = err;
+ except->name = Zig::toZigString(err->sanitizedNameString(global));
+ except->runtime_type = err->runtimeTypeForCause();
+
+ except->exception = err;
+}
+
+void exceptionFromString(ZigException *except, JSC::JSValue value, JSC::JSGlobalObject *global) {
+ // Fallback case for when it's a user-defined ErrorLike-object that doesn't inherit from
+ // ErrorInstance
+ if (JSC::JSObject *obj = JSC::jsDynamicCast<JSC::JSObject *>(global->vm(), value)) {
+ if (obj->hasProperty(global, global->vm().propertyNames->name)) {
+ auto name_str =
+ obj->getDirect(global->vm(), global->vm().propertyNames->name).toWTFString(global);
+ except->name = Zig::toZigString(name_str);
+ if (name_str == "Error"_s) {
+ except->code = JSErrorCodeError;
+ } else if (name_str == "EvalError"_s) {
+ except->code = JSErrorCodeEvalError;
+ } else if (name_str == "RangeError"_s) {
+ except->code = JSErrorCodeRangeError;
+ } else if (name_str == "ReferenceError"_s) {
+ except->code = JSErrorCodeReferenceError;
+ } else if (name_str == "SyntaxError"_s) {
+ except->code = JSErrorCodeSyntaxError;
+ } else if (name_str == "TypeError"_s) {
+ except->code = JSErrorCodeTypeError;
+ } else if (name_str == "URIError"_s) {
+ except->code = JSErrorCodeURIError;
+ } else if (name_str == "AggregateError"_s) {
+ except->code = JSErrorCodeAggregateError;
+ }
+ }
- return except;
-}
+ if (obj->hasProperty(global, global->vm().propertyNames->message)) {
+ except->message = Zig::toZigString(
+ obj->getDirect(global->vm(), global->vm().propertyNames->message).toWTFString(global));
+ }
-static ZigException exceptionFromString(WTF::String &str) {
- ZigException except = Zig::ZigExceptionNone;
- auto ref = OpaqueJSString::tryCreate(str);
- except.message = ZigString{ref->characters8(), ref->length()};
- ref->ref();
+ if (obj->hasProperty(global, global->vm().propertyNames->sourceURL)) {
+ except->stack.frames_ptr[0].source_url = Zig::toZigString(
+ obj->getDirect(global->vm(), global->vm().propertyNames->sourceURL).toWTFString(global));
+ except->stack.frames_len = 1;
+ }
- return except;
-}
+ if (obj->hasProperty(global, global->vm().propertyNames->line)) {
+ except->stack.frames_ptr[0].position.line =
+ obj->getDirect(global->vm(), global->vm().propertyNames->line).toInt32(global);
+ except->stack.frames_len = 1;
+ }
-static ZigException exceptionFromString(JSC::JSValue value, JSC::JSGlobalObject *global) {
+ return;
+ }
auto scope = DECLARE_THROW_SCOPE(global->vm());
auto str = value.toWTFString(global);
if (scope.exception()) {
scope.clearException();
scope.release();
- return Zig::ZigExceptionNone;
+ return;
}
scope.release();
- ZigException except = Zig::ZigExceptionNone;
auto ref = OpaqueJSString::tryCreate(str);
- except.message = ZigString{ref->characters8(), ref->length()};
+ except->message = ZigString{ref->characters8(), ref->length()};
ref->ref();
-
- return except;
}
-ZigException JSC__JSValue__toZigException(JSC__JSValue JSValue0, JSC__JSGlobalObject *arg1) {
+void JSC__JSValue__toZigException(JSC__JSValue JSValue0, JSC__JSGlobalObject *arg1,
+ ZigException *exception) {
JSC::JSValue value = JSC::JSValue::decode(JSValue0);
- if (JSC::ErrorInstance *error = JSC::jsDynamicCast<JSC::ErrorInstance *>(arg1->vm(), value)) {
- return fromErrorInstance(arg1, error, value);
- }
-
- if (JSC::Exception *exception = JSC::jsDynamicCast<JSC::Exception *>(arg1->vm(), value)) {
+ if (JSC::Exception *jscException = JSC::jsDynamicCast<JSC::Exception *>(arg1->vm(), value)) {
if (JSC::ErrorInstance *error =
- JSC::jsDynamicCast<JSC::ErrorInstance *>(arg1->vm(), exception->value())) {
- return fromErrorInstance(arg1, error, value);
+ JSC::jsDynamicCast<JSC::ErrorInstance *>(arg1->vm(), jscException->value())) {
+ fromErrorInstance(exception, arg1, error, &jscException->stack(), value);
+ return;
}
}
- return exceptionFromString(value, arg1);
+ if (JSC::ErrorInstance *error = JSC::jsDynamicCast<JSC::ErrorInstance *>(arg1->vm(), value)) {
+ fromErrorInstance(exception, arg1, error, nullptr, value);
+ return;
+ }
+
+ exceptionFromString(exception, value, arg1);
}
#pragma mark - JSC::PropertyName
diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig
index 4055c26bb..1b7205aa9 100644
--- a/src/javascript/jsc/bindings/bindings.zig
+++ b/src/javascript/jsc/bindings/bindings.zig
@@ -2,6 +2,7 @@ usingnamespace @import("./shared.zig");
usingnamespace @import("./headers.zig");
pub const Shimmer = @import("./shimmer.zig").Shimmer;
const hasRef = std.meta.trait.hasField("ref");
+const C_API = @import("../JavaScriptCore.zig");
pub const JSObject = extern struct {
pub const shim = Shimmer("JSC", "JSObject", @This());
@@ -37,6 +38,10 @@ pub const JSObject = extern struct {
pub const ZigString = extern struct {
ptr: [*]const u8,
len: usize,
+ pub const shim = Shimmer("Zig", "ZigString", @This());
+
+ pub const name = "ZigString";
+ pub const namespace = "Zig";
pub fn init(slice_: []const u8) ZigString {
return ZigString{ .ptr = slice_.ptr, .len = slice_.len };
@@ -47,6 +52,18 @@ pub const ZigString = extern struct {
pub fn slice(this: *const ZigString) []const u8 {
return this.ptr[0..std.math.min(this.len, 4096)];
}
+
+ pub fn toValue(this: ZigString, global: *JSGlobalObject) JSValue {
+ return shim.cppFn("toValue", .{ this, global });
+ }
+
+ pub fn toJSStringRef(this: *const ZigString) C_API.JSStringRef {
+ return C_API.JSStringCreateStatic(this.ptr, this.len);
+ }
+
+ pub const Extern = [_][]const u8{
+ "toValue",
+ };
};
pub const JSCell = extern struct {
@@ -184,11 +201,12 @@ pub fn NewGlobalObject(comptime Type: type) type {
}
return ErrorableZigString.err(error.ResolveFailed, "resolve not implemented");
}
- pub fn fetch(global: *JSGlobalObject, specifier: ZigString, source: ZigString) callconv(.C) ErrorableResolvedSource {
+ pub fn fetch(ret: *ErrorableResolvedSource, global: *JSGlobalObject, specifier: ZigString, source: ZigString) callconv(.C) void {
if (comptime @hasDecl(Type, "fetch")) {
- return @call(.{ .modifier = .always_inline }, Type.fetch, .{ global, specifier, source });
+ @call(.{ .modifier = .always_inline }, Type.fetch, .{ ret, global, specifier, source });
+ return;
}
- return ErrorableResolvedSource.err(error.FetchFailed, "Module fetch not implemented");
+ ret.* = ErrorableResolvedSource.err(error.FetchFailed, "Module fetch not implemented");
}
pub fn promiseRejectionTracker(global: *JSGlobalObject, promise: *JSPromise, rejection: JSPromiseRejectionOperation) callconv(.C) JSValue {
if (comptime @hasDecl(Type, "promiseRejectionTracker")) {
@@ -776,11 +794,16 @@ pub const JSGlobalObject = extern struct {
return cppFn("asyncGeneratorFunctionPrototype", .{this});
}
+ pub fn createAggregateError(globalObject: *JSGlobalObject, errors: [*]JSValue, errors_len: u16, message: ZigString) JSValue {
+ return cppFn("createAggregateError", .{ globalObject, errors, errors_len, message });
+ }
+
pub fn vm(this: *JSGlobalObject) *VM {
return cppFn("vm", .{this});
}
pub const Extern = [_][]const u8{
+ "createAggregateError",
"objectPrototype",
"functionPrototype",
"arrayPrototype",
@@ -1087,6 +1110,7 @@ pub const JSValue = enum(i64) {
pub fn jsNumberFromInt32(i: i32) JSValue {
return cppFn("jsNumberFromInt32", .{i});
}
+
pub fn jsNumberFromInt64(i: i64) JSValue {
return cppFn("jsNumberFromInt64", .{i});
}
@@ -1165,8 +1189,8 @@ pub const JSValue = enum(i64) {
return cppFn("isException", .{ this, vm });
}
- pub fn toZigException(this: JSValue, global: *JSGlobalObject) ZigException {
- return cppFn("toZigException", .{ this, global });
+ pub fn toZigException(this: JSValue, global: *JSGlobalObject, exception: *ZigException) void {
+ return cppFn("toZigException", .{ this, global, exception });
}
// On exception, this returns the empty string.
diff --git a/src/javascript/jsc/bindings/exports.zig b/src/javascript/jsc/bindings/exports.zig
index 1c2dae1f9..8813870b2 100644
--- a/src/javascript/jsc/bindings/exports.zig
+++ b/src/javascript/jsc/bindings/exports.zig
@@ -3,6 +3,7 @@ usingnamespace @import("./shared.zig");
const Fs = @import("../../../fs.zig");
const CAPI = @import("../JavaScriptCore.zig");
const JS = @import("../javascript.zig");
+const JSBase = @import("../base.zig");
const Handler = struct {
pub export fn global_signal_handler_fn(sig: i32, info: *const std.os.siginfo_t, ctx_ptr: ?*const c_void) callconv(.C) void {
Global.panic("C++ Crash!!", .{});
@@ -47,11 +48,11 @@ pub const ZigGlobalObject = extern struct {
}
return @call(.{ .modifier = .always_inline }, Interface.resolve, .{ global, specifier, source });
}
- pub fn fetch(global: *JSGlobalObject, specifier: ZigString, source: ZigString) callconv(.C) ErrorableResolvedSource {
+ pub fn fetch(ret: *ErrorableResolvedSource, global: *JSGlobalObject, specifier: ZigString, source: ZigString) callconv(.C) void {
if (comptime is_bindgen) {
unreachable;
}
- return @call(.{ .modifier = .always_inline }, Interface.fetch, .{ global, specifier, source });
+ @call(.{ .modifier = .always_inline }, Interface.fetch, .{ ret, global, specifier, source });
}
pub fn promiseRejectionTracker(global: *JSGlobalObject, promise: *JSPromise, rejection: JSPromiseRejectionOperation) callconv(.C) JSValue {
@@ -106,7 +107,8 @@ pub const ZigGlobalObject = extern struct {
}
};
-const ErrorCodeInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8);
+const ErrorCodeInt = usize;
+
pub const ErrorCode = enum(ErrorCodeInt) {
_,
@@ -114,18 +116,33 @@ pub const ErrorCode = enum(ErrorCodeInt) {
return @intToEnum(ErrorCode, @errorToInt(code));
}
- pub const Type = switch (@sizeOf(anyerror)) {
- 0, 1 => u8,
- 2 => u16,
- 3 => u32,
- 4 => u64,
- else => @compileError("anyerror is too big"),
- };
+ pub const ParserError = @enumToInt(ErrorCode.from(error.ParserError));
+ pub const JSErrorObject = @enumToInt(ErrorCode.from(error.JSErrorObject));
+
+ pub const Type = ErrorCodeInt;
};
pub const ZigErrorType = extern struct {
+ pub const shim = Shimmer("Zig", "ErrorType", @This());
+ pub const name = "ErrorType";
+ pub const namespace = shim.namespace;
+
code: ErrorCode,
- message: ZigString,
+ ptr: ?*c_void,
+
+ pub fn isPrivateData(ptr: ?*c_void) callconv(.C) bool {
+ return JSBase.JSPrivateDataPtr.isValidPtr(ptr);
+ }
+
+ pub const Export = shim.exportFunctions(.{
+ .@"isPrivateData" = isPrivateData,
+ });
+
+ comptime {
+ @export(isPrivateData, .{
+ .name = Export[0].symbol_name,
+ });
+ }
};
pub const JSErrorCode = enum(u8) {
@@ -140,6 +157,7 @@ pub const JSErrorCode = enum(u8) {
// StackOverflow & OutOfMemoryError is not an ErrorType in <JavaScriptCore/ErrorType.h> within JSC, so the number here is just totally made up
OutOfMemoryError = 8,
+ BundlerError = 252,
StackOverflow = 253,
UserErrorCode = 254,
_,
@@ -181,18 +199,12 @@ pub fn Errorable(comptime Type: type) type {
}
threadlocal var err_buf: [4096]u8 = undefined;
- pub fn errFmt(code: anyerror, comptime fmt: []const u8, args: anytype) @This() {
- const message = std.fmt.bufPrint(&err_buf, fmt, args) catch @as([]const u8, @errorName(code)[0..]);
-
- return @call(.{ .modifier = .always_inline }, err, .{ code, message });
- }
-
- pub fn err(code: anyerror, msg: []const u8) @This() {
+ pub fn err(code: anyerror, ptr: *c_void) @This() {
return @This(){
.result = .{
.err = .{
.code = ErrorCode.from(code),
- .message = ZigString.init(msg),
+ .ptr = ptr,
},
},
.success = false,
@@ -215,10 +227,200 @@ pub const ResolvedSource = extern struct {
bytecodecache_fd: u64,
};
-pub const ErrorableResolvedSource = Errorable(ResolvedSource);
+pub const ZigStackFrameCode = enum(u8) {
+ None = 0,
+ // 🏃
+ Eval = 1,
+ // 📦
+ Module = 2,
+ // λ
+ Function = 3,
+ // 🌎
+ Global = 4,
+ // ⚙️
+ Wasm = 5,
+ // 👷
+ Constructor = 6,
+ _,
-pub const ErrorableZigString = Errorable(ZigString);
-pub const ErrorableJSValue = Errorable(JSValue);
+ pub fn emoji(this: ZigStackFrameCode) u21 {
+ return switch (this) {
+ .Eval => 0x1F3C3,
+ .Module => 0x1F4E6,
+ .Function => 0x03BB,
+ .Global => 0x1F30E,
+ .Wasm => 0xFE0F,
+ .Constructor => 0xF1477,
+ else => ' ',
+ };
+ }
+
+ pub fn ansiColor(this: ZigStackFrameCode) string {
+ return switch (this) {
+ .Eval => "\x1b[31m",
+ .Module => "\x1b[36m",
+ .Function => "\x1b[32m",
+ .Global => "\x1b[35m",
+ .Wasm => "\x1b[37m",
+ .Constructor => "\x1b[33m",
+ else => "",
+ };
+ }
+};
+
+pub const ZigStackTrace = extern struct {
+ source_lines_ptr: [*c]ZigString,
+ source_lines_numbers: [*c]i32,
+ source_lines_len: u8,
+ source_lines_to_collect: u8,
+
+ frames_ptr: [*c]ZigStackFrame,
+ frames_len: u8,
+
+ pub fn frames(this: *const ZigStackTrace) []const ZigStackFrame {
+ return this.frames_ptr[0..this.frames_len];
+ }
+
+ pub const SourceLineIterator = struct {
+ trace: *const ZigStackTrace,
+ i: i16,
+
+ pub const SourceLine = struct {
+ line: i32,
+ text: string,
+ };
+
+ pub fn untilLast(this: *SourceLineIterator) ?SourceLine {
+ if (this.i < 1) return null;
+ return this.next();
+ }
+
+ pub fn next(this: *SourceLineIterator) ?SourceLine {
+ if (this.i < 0) return null;
+
+ const result = SourceLine{
+ .line = this.trace.source_lines_numbers[@intCast(usize, this.i)],
+ .text = this.trace.source_lines_ptr[@intCast(usize, this.i)].slice(),
+ };
+ this.i -= 1;
+ return result;
+ }
+ };
+
+ pub fn sourceLineIterator(this: *const ZigStackTrace) SourceLineIterator {
+ var i: usize = 0;
+ for (this.source_lines_numbers[0..this.source_lines_len]) |num, j| {
+ if (num > 0) {
+ i = j;
+ }
+ }
+ return SourceLineIterator{ .trace = this, .i = @intCast(i16, i) };
+ }
+};
+
+pub const ZigStackFrame = extern struct {
+ pub const SourceURLFormatter = struct {
+ source_url: ZigString,
+ position: ZigStackFramePosition,
+ enable_color: bool,
+
+ pub fn format(this: SourceURLFormatter, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
+ try writer.writeAll(this.source_url.slice());
+ if (this.position.line > -1 and this.position.column_start > -1) {
+ try std.fmt.format(writer, ":{d}:{d}", .{ this.position.line, this.position.column_start });
+ } else if (this.position.line > -1) {
+ try std.fmt.format(writer, ":{d}", .{
+ this.position.line,
+ });
+ }
+ }
+ };
+
+ pub const NameFormatter = struct {
+ function_name: ZigString,
+ code_type: ZigStackFrameCode,
+ enable_color: bool,
+
+ pub fn format(this: NameFormatter, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
+ const name = this.function_name.slice();
+
+ switch (this.code_type) {
+ .Eval => {
+ try writer.writeAll("(eval)");
+ },
+ .Module => {
+ try writer.writeAll("(esm)");
+ },
+ .Function => {
+ if (name.len > 0) {
+ try std.fmt.format(writer, "{s}", .{name});
+ } else {
+ try writer.writeAll("(anonymous)");
+ }
+ },
+ .Global => {
+ if (name.len > 0) {
+ try std.fmt.format(writer, "globalThis {s}", .{name});
+ } else {
+ try writer.writeAll("globalThis");
+ }
+ },
+ .Wasm => {
+ try std.fmt.format(writer, "WASM {s}", .{name});
+ },
+ .Constructor => {
+ try std.fmt.format(writer, "new {s}", .{name});
+ },
+ else => {},
+ }
+ }
+ };
+
+ pub const Zero: ZigStackFrame = ZigStackFrame{
+ .function_name = ZigString{ .ptr = "", .len = 0 },
+ .code_type = ZigStackFrameCode.None,
+ .source_url = ZigString{ .ptr = "", .len = 0 },
+ .position = ZigStackFramePosition.Invalid,
+ };
+
+ function_name: ZigString,
+ source_url: ZigString,
+ position: ZigStackFramePosition,
+ code_type: ZigStackFrameCode,
+
+ pub fn nameFormatter(this: *const ZigStackFrame, comptime enable_color: bool) NameFormatter {
+ return NameFormatter{ .function_name = this.function_name, .code_type = this.code_type, .enable_color = enable_color };
+ }
+
+ pub fn sourceURLFormatter(this: *const ZigStackFrame, comptime enable_color: bool) SourceURLFormatter {
+ return SourceURLFormatter{ .source_url = this.source_url, .position = this.position, .enable_color = enable_color };
+ }
+};
+
+pub const ZigStackFramePosition = extern struct {
+ source_offset: i32,
+ line: i32,
+ line_start: i32,
+ line_stop: i32,
+ column_start: i32,
+ column_stop: i32,
+ expression_start: i32,
+ expression_stop: i32,
+
+ pub const Invalid = ZigStackFramePosition{
+ .source_offset = -1,
+ .line = -1,
+ .line_start = -1,
+ .line_stop = -1,
+ .column_start = -1,
+ .column_stop = -1,
+ .expression_start = -1,
+ .expression_stop = -1,
+ };
+ pub fn isInvalid(this: *const ZigStackFramePosition) bool {
+ return std.mem.eql(u8, std.mem.asBytes(this), std.mem.asBytes(&Invalid));
+ }
+};
pub const ZigException = extern struct {
pub const shim = Shimmer("Zig", "Exception", @This());
@@ -229,12 +431,68 @@ pub const ZigException = extern struct {
runtime_type: JSRuntimeType,
name: ZigString,
message: ZigString,
- sourceURL: ZigString,
- line: i32,
- column: i32,
- stack: ZigString,
+ stack: ZigStackTrace,
+
exception: ?*c_void,
+ pub const Holder = extern struct {
+ const frame_count = 24;
+ const source_lines_count = 6;
+ source_line_numbers: [source_lines_count]i32,
+ source_lines: [source_lines_count]ZigString,
+ frames: [frame_count]ZigStackFrame,
+ loaded: bool,
+ zig_exception: ZigException,
+
+ pub const Zero: Holder = Holder{
+ .frames = brk: {
+ var _frames: [frame_count]ZigStackFrame = undefined;
+ std.mem.set(ZigStackFrame, &_frames, ZigStackFrame.Zero);
+ break :brk _frames;
+ },
+ .source_line_numbers = brk: {
+ var lines: [source_lines_count]i32 = undefined;
+ std.mem.set(i32, &lines, -1);
+ break :brk lines;
+ },
+
+ .source_lines = brk: {
+ var lines: [source_lines_count]ZigString = undefined;
+ std.mem.set(ZigString, &lines, ZigString.Empty);
+ break :brk lines;
+ },
+ .zig_exception = undefined,
+ .loaded = false,
+ };
+
+ pub fn init() Holder {
+ return Holder.Zero;
+ }
+
+ pub fn zigException(this: *Holder) *ZigException {
+ if (!this.loaded) {
+ this.zig_exception = ZigException{
+ .code = @intToEnum(JSErrorCode, 255),
+ .runtime_type = JSRuntimeType.Nothing,
+ .name = ZigString.Empty,
+ .message = ZigString.Empty,
+ .exception = null,
+ .stack = ZigStackTrace{
+ .source_lines_ptr = &this.source_lines,
+ .source_lines_numbers = &this.source_line_numbers,
+ .source_lines_len = source_lines_count,
+ .source_lines_to_collect = source_lines_count,
+ .frames_ptr = &this.frames,
+ .frames_len = this.frames.len,
+ },
+ };
+ this.loaded = true;
+ }
+
+ return &this.zig_exception;
+ }
+ };
+
pub fn fromException(exception: *Exception) ZigException {
return shim.cppFn("fromException", .{exception});
}
@@ -242,6 +500,10 @@ pub const ZigException = extern struct {
pub const Extern = [_][]const u8{"fromException"};
};
+pub const ErrorableResolvedSource = Errorable(ResolvedSource);
+pub const ErrorableZigString = Errorable(ZigString);
+pub const ErrorableJSValue = Errorable(JSValue);
+
pub const ZigConsoleClient = struct {
pub const shim = Shimmer("Zig", "ConsoleClient", @This());
pub const Type = *c_void;
@@ -463,3 +725,8 @@ pub const ZigConsoleClient = struct {
pub inline fn toGlobalContextRef(ptr: *JSGlobalObject) CAPI.JSGlobalContextRef {
return @ptrCast(CAPI.JSGlobalContextRef, ptr);
}
+
+comptime {
+ @export(ErrorCode.ParserError, .{ .name = "Zig_ErrorCodeParserError" });
+ @export(ErrorCode.JSErrorObject, .{ .name = "Zig_ErrorCodeJSErrorObject" });
+}
diff --git a/src/javascript/jsc/bindings/header-gen.zig b/src/javascript/jsc/bindings/header-gen.zig
index e912bf4f8..8b9bb504e 100644
--- a/src/javascript/jsc/bindings/header-gen.zig
+++ b/src/javascript/jsc/bindings/header-gen.zig
@@ -577,7 +577,7 @@ pub fn HeaderGen(comptime import: type, comptime fname: []const u8) type {
const Generator = C_Generator;
validateGenerator(Generator);
var file_writer = file.writer();
- file_writer.print("//-- AUTOGENERATED FILE -- {d}\n", .{std.time.timestamp()}) catch unreachable;
+ file_writer.print("//-- AUTOGENERATED FILE -- {d}\n// clang-format: off\n", .{std.time.timestamp()}) catch unreachable;
file.writeAll(
\\#pragma once
\\
@@ -594,18 +594,15 @@ pub fn HeaderGen(comptime import: type, comptime fname: []const u8) type {
\\#define CPP_DECL AUTO_EXTERN_C
\\#define CPP_SIZE AUTO_EXTERN_C
\\
- \\typedef uint16_t ZigErrorCode;
\\#ifndef __cplusplus
\\typedef void* JSClassRef;
\\#endif
- \\typedef struct ZigString { const unsigned char* ptr; size_t len; } ZigString;
- \\typedef struct ZigErrorType { ZigErrorCode code; ZigString message; } ZigErrorType;
- \\typedef struct ZigException { unsigned char code; uint16_t runtime_type; ZigString name; ZigString message; ZigString sourceURL; int32_t line; int32_t column; ZigString stack; void* exception; } ZigException;
- \\typedef union ErrorableZigStringResult { ZigString value; ZigErrorType err; } ErrorableZigStringResult;
- \\typedef struct ErrorableZigString { ErrorableZigStringResult result; bool success; } ErrorableZigString;
- \\typedef struct ResolvedSource { ZigString specifier; ZigString source_code; ZigString source_url; uint32_t hash; uint32_t bytecodecache_fd; } ResolvedSource;
- \\typedef union ErrorableResolvedSourceResult { ResolvedSource value; ZigErrorType err; } ErrorableResolvedSourceResult;
- \\typedef struct ErrorableResolvedSource { ErrorableResolvedSourceResult result; bool success; } ErrorableResolvedSource;
+ \\
+ \\#ifdef __cplusplus
+ \\#include "root.h"
+ \\#include <JavaScriptCore/JSClassRef.h>
+ \\#endif
+ \\#include "headers-handwritten.h"
\\
) catch {};
diff --git a/src/javascript/jsc/bindings/headers-cpp.h b/src/javascript/jsc/bindings/headers-cpp.h
index e8b096bb2..d51bfdfc2 100644
--- a/src/javascript/jsc/bindings/headers-cpp.h
+++ b/src/javascript/jsc/bindings/headers-cpp.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1627603981
+//-- AUTOGENERATED FILE -- 1627867755
// clang-format off
#pragma once
@@ -224,8 +224,8 @@ extern "C" const size_t Zig__GlobalObject_object_align_ = alignof(Zig::GlobalObj
extern "C" const size_t Zig__ConsoleClient_object_size_ = sizeof(Zig::ConsoleClient);
extern "C" const size_t Zig__ConsoleClient_object_align_ = alignof(Zig::ConsoleClient);
-const size_t sizes[27] = {sizeof(JSC::JSObject), sizeof(JSC::JSCell), sizeof(JSC::JSString), sizeof(Inspector::ScriptArguments), sizeof(JSC::JSModuleLoader), sizeof(JSC::JSModuleRecord), sizeof(JSC::JSPromise), sizeof(JSC::JSInternalPromise), sizeof(JSC::SourceOrigin), sizeof(JSC::SourceCode), sizeof(JSC::JSFunction), sizeof(JSC::JSGlobalObject), sizeof(WTF::URL), sizeof(WTF::String), sizeof(JSC::JSValue), sizeof(JSC::PropertyName), sizeof(JSC::Exception), sizeof(JSC::VM), sizeof(JSC::ThrowScope), sizeof(JSC::CatchScope), sizeof(JSC::CallFrame), sizeof(JSC::Identifier), sizeof(WTF::StringImpl), sizeof(WTF::ExternalStringImpl), sizeof(WTF::StringView), sizeof(Zig::GlobalObject), sizeof(ZigException)};
+const size_t sizes[28] = {sizeof(JSC::JSObject), sizeof(ZigString), sizeof(JSC::JSCell), sizeof(JSC::JSString), sizeof(Inspector::ScriptArguments), sizeof(JSC::JSModuleLoader), sizeof(JSC::JSModuleRecord), sizeof(JSC::JSPromise), sizeof(JSC::JSInternalPromise), sizeof(JSC::SourceOrigin), sizeof(JSC::SourceCode), sizeof(JSC::JSFunction), sizeof(JSC::JSGlobalObject), sizeof(WTF::URL), sizeof(WTF::String), sizeof(JSC::JSValue), sizeof(JSC::PropertyName), sizeof(JSC::Exception), sizeof(JSC::VM), sizeof(JSC::ThrowScope), sizeof(JSC::CatchScope), sizeof(JSC::CallFrame), sizeof(JSC::Identifier), sizeof(WTF::StringImpl), sizeof(WTF::ExternalStringImpl), sizeof(WTF::StringView), sizeof(Zig::GlobalObject), sizeof(ZigException)};
-const char* names[27] = {"JSC__JSObject", "JSC__JSCell", "JSC__JSString", "Inspector__ScriptArguments", "JSC__JSModuleLoader", "JSC__JSModuleRecord", "JSC__JSPromise", "JSC__JSInternalPromise", "JSC__SourceOrigin", "JSC__SourceCode", "JSC__JSFunction", "JSC__JSGlobalObject", "WTF__URL", "WTF__String", "JSC__JSValue", "JSC__PropertyName", "JSC__Exception", "JSC__VM", "JSC__ThrowScope", "JSC__CatchScope", "JSC__CallFrame", "JSC__Identifier", "WTF__StringImpl", "WTF__ExternalStringImpl", "WTF__StringView", "Zig__GlobalObject", "ZigException"};
+const char* names[28] = {"JSC__JSObject", "ZigString", "JSC__JSCell", "JSC__JSString", "Inspector__ScriptArguments", "JSC__JSModuleLoader", "JSC__JSModuleRecord", "JSC__JSPromise", "JSC__JSInternalPromise", "JSC__SourceOrigin", "JSC__SourceCode", "JSC__JSFunction", "JSC__JSGlobalObject", "WTF__URL", "WTF__String", "JSC__JSValue", "JSC__PropertyName", "JSC__Exception", "JSC__VM", "JSC__ThrowScope", "JSC__CatchScope", "JSC__CallFrame", "JSC__Identifier", "WTF__StringImpl", "WTF__ExternalStringImpl", "WTF__StringView", "Zig__GlobalObject", "ZigException"};
-const size_t aligns[27] = {alignof(JSC::JSObject), alignof(JSC::JSCell), alignof(JSC::JSString), alignof(Inspector::ScriptArguments), alignof(JSC::JSModuleLoader), alignof(JSC::JSModuleRecord), alignof(JSC::JSPromise), alignof(JSC::JSInternalPromise), alignof(JSC::SourceOrigin), alignof(JSC::SourceCode), alignof(JSC::JSFunction), alignof(JSC::JSGlobalObject), alignof(WTF::URL), alignof(WTF::String), alignof(JSC::JSValue), alignof(JSC::PropertyName), alignof(JSC::Exception), alignof(JSC::VM), alignof(JSC::ThrowScope), alignof(JSC::CatchScope), alignof(JSC::CallFrame), alignof(JSC::Identifier), alignof(WTF::StringImpl), alignof(WTF::ExternalStringImpl), alignof(WTF::StringView), alignof(Zig::GlobalObject), alignof(ZigException)};
+const size_t aligns[28] = {alignof(JSC::JSObject), alignof(ZigString), alignof(JSC::JSCell), alignof(JSC::JSString), alignof(Inspector::ScriptArguments), alignof(JSC::JSModuleLoader), alignof(JSC::JSModuleRecord), alignof(JSC::JSPromise), alignof(JSC::JSInternalPromise), alignof(JSC::SourceOrigin), alignof(JSC::SourceCode), alignof(JSC::JSFunction), alignof(JSC::JSGlobalObject), alignof(WTF::URL), alignof(WTF::String), alignof(JSC::JSValue), alignof(JSC::PropertyName), alignof(JSC::Exception), alignof(JSC::VM), alignof(JSC::ThrowScope), alignof(JSC::CatchScope), alignof(JSC::CallFrame), alignof(JSC::Identifier), alignof(WTF::StringImpl), alignof(WTF::ExternalStringImpl), alignof(WTF::StringView), alignof(Zig::GlobalObject), alignof(ZigException)};
diff --git a/src/javascript/jsc/bindings/headers-handwritten.h b/src/javascript/jsc/bindings/headers-handwritten.h
new file mode 100644
index 000000000..133222b39
--- /dev/null
+++ b/src/javascript/jsc/bindings/headers-handwritten.h
@@ -0,0 +1,95 @@
+typedef uint16_t ZigErrorCode;
+
+typedef struct ZigString {
+ const unsigned char *ptr;
+ size_t len;
+} ZigString;
+typedef struct ZigErrorType {
+ ZigErrorCode code;
+ void *ptr;
+} ZigErrorType;
+typedef union ErrorableZigStringResult {
+ ZigString value;
+ ZigErrorType err;
+} ErrorableZigStringResult;
+typedef struct ErrorableZigString {
+ ErrorableZigStringResult result;
+ bool success;
+} ErrorableZigString;
+typedef struct ResolvedSource {
+ ZigString specifier;
+ ZigString source_code;
+ ZigString source_url;
+ uint32_t hash;
+ uint32_t bytecodecache_fd;
+} ResolvedSource;
+typedef union ErrorableResolvedSourceResult {
+ ResolvedSource value;
+ ZigErrorType err;
+} ErrorableResolvedSourceResult;
+typedef struct ErrorableResolvedSource {
+ ErrorableResolvedSourceResult result;
+ bool success;
+} ErrorableResolvedSource;
+
+typedef uint8_t ZigStackFrameCode;
+const ZigStackFrameCode ZigStackFrameCodeNone = 0;
+const ZigStackFrameCode ZigStackFrameCodeEval = 1;
+const ZigStackFrameCode ZigStackFrameCodeModule = 2;
+const ZigStackFrameCode ZigStackFrameCodeFunction = 3;
+const ZigStackFrameCode ZigStackFrameCodeGlobal = 4;
+const ZigStackFrameCode ZigStackFrameCodeWasm = 5;
+const ZigStackFrameCode ZigStackFrameCodeConstructor = 6;
+
+typedef struct ZigStackFramePosition {
+ int32_t source_offset;
+ int32_t line;
+ int32_t line_start;
+ int32_t line_stop;
+ int32_t column_start;
+ int32_t column_stop;
+ int32_t expression_start;
+ int32_t expression_stop;
+} ZigStackFramePosition;
+
+typedef struct ZigStackFrame {
+ ZigString function_name;
+ ZigString source_url;
+ ZigStackFramePosition position;
+ ZigStackFrameCode code_type;
+} ZigStackFrame;
+
+typedef struct ZigStackTrace {
+ ZigString *source_lines_ptr;
+ int32_t *source_lines_numbers;
+ uint8_t source_lines_len;
+ uint8_t source_lines_to_collect;
+ ZigStackFrame *frames_ptr;
+ uint8_t frames_len;
+} ZigStackTrace;
+
+typedef struct ZigException {
+ unsigned char code;
+ uint16_t runtime_type;
+ ZigString name;
+ ZigString message;
+ ZigStackTrace stack;
+ void *exception;
+} ZigException;
+
+typedef uint8_t JSErrorCode;
+const JSErrorCode JSErrorCodeError = 0;
+const JSErrorCode JSErrorCodeEvalError = 1;
+const JSErrorCode JSErrorCodeRangeError = 2;
+const JSErrorCode JSErrorCodeReferenceError = 3;
+const JSErrorCode JSErrorCodeSyntaxError = 4;
+const JSErrorCode JSErrorCodeTypeError = 5;
+const JSErrorCode JSErrorCodeURIError = 6;
+const JSErrorCode JSErrorCodeAggregateError = 7;
+const JSErrorCode JSErrorCodeOutOfMemoryError = 8;
+const JSErrorCode JSErrorCodeStackOverflow = 253;
+const JSErrorCode JSErrorCodeUserErrorCode = 254;
+
+#ifdef __cplusplus
+extern "C" ZigErrorCode Zig_ErrorCodeParserError;
+#endif \ No newline at end of file
diff --git a/src/javascript/jsc/bindings/headers.zig b/src/javascript/jsc/bindings/headers.zig
index 2dfc7eb11..80a048443 100644
--- a/src/javascript/jsc/bindings/headers.zig
+++ b/src/javascript/jsc/bindings/headers.zig
@@ -37,7 +37,7 @@ pub const __mbstate_t = extern union {
pub const __darwin_mbstate_t = __mbstate_t;
pub const __darwin_ptrdiff_t = c_long;
pub const __darwin_size_t = c_ulong;
-
+
pub const JSC__RegExpPrototype = struct_JSC__RegExpPrototype;
pub const JSC__GeneratorPrototype = struct_JSC__GeneratorPrototype;
@@ -100,6 +100,7 @@ pub const JSC__MapIteratorPrototype = struct_JSC__MapIteratorPrototype;
pub extern fn JSC__JSObject__getArrayLength(arg0: [*c]JSC__JSObject) usize;
pub extern fn JSC__JSObject__getAtIndex(arg0: [*c]JSC__JSObject, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]JSC__PropertyName, arg3: u32) JSC__JSValue;
pub extern fn JSC__JSObject__putAtIndex(arg0: [*c]JSC__JSObject, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]JSC__PropertyName, arg3: u32) bool;
+pub extern fn ZigString__toValue(arg0: ZigString, arg1: [*c]JSC__JSGlobalObject) JSC__JSValue;
pub extern fn JSC__JSCell__getObject(arg0: [*c]JSC__JSCell) [*c]JSC__JSObject;
pub extern fn JSC__JSCell__getString(arg0: [*c]JSC__JSCell, arg1: [*c]JSC__JSGlobalObject) bWTF__String;
pub extern fn JSC__JSCell__getType(arg0: [*c]JSC__JSCell) u8;
@@ -167,6 +168,7 @@ pub extern fn JSC__JSGlobalObject__asyncGeneratorPrototype(arg0: [*c]JSC__JSGlob
pub extern fn JSC__JSGlobalObject__asyncIteratorPrototype(arg0: [*c]JSC__JSGlobalObject) ?*JSC__AsyncIteratorPrototype;
pub extern fn JSC__JSGlobalObject__bigIntPrototype(arg0: [*c]JSC__JSGlobalObject) ?*JSC__BigIntPrototype;
pub extern fn JSC__JSGlobalObject__booleanPrototype(arg0: [*c]JSC__JSGlobalObject) [*c]JSC__JSObject;
+pub extern fn JSC__JSGlobalObject__createAggregateError(arg0: [*c]JSC__JSGlobalObject, arg1: JSC__JSValue, arg2: u16, arg3: ZigString) JSC__JSValue;
pub extern fn JSC__JSGlobalObject__datePrototype(arg0: [*c]JSC__JSGlobalObject) [*c]JSC__JSObject;
pub extern fn JSC__JSGlobalObject__errorPrototype(arg0: [*c]JSC__JSGlobalObject) [*c]JSC__JSObject;
pub extern fn JSC__JSGlobalObject__functionPrototype(arg0: [*c]JSC__JSGlobalObject) ?*JSC__FunctionPrototype;
@@ -271,7 +273,7 @@ pub extern fn JSC__JSValue__toPropertyKeyValue(JSValue0: JSC__JSValue, arg1: [*c
pub extern fn JSC__JSValue__toString(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject) [*c]JSC__JSString;
pub extern fn JSC__JSValue__toStringOrNull(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject) [*c]JSC__JSString;
pub extern fn JSC__JSValue__toWTFString(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject) bWTF__String;
-pub extern fn JSC__JSValue__toZigException(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject) ZigException;
+pub extern fn JSC__JSValue__toZigException(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]ZigException) void;
pub extern fn JSC__PropertyName__eqlToIdentifier(arg0: [*c]JSC__PropertyName, arg1: [*c]const JSC__Identifier) bool;
pub extern fn JSC__PropertyName__eqlToPropertyName(arg0: [*c]JSC__PropertyName, arg1: [*c]const JSC__PropertyName) bool;
pub extern fn JSC__PropertyName__publicName(arg0: [*c]JSC__PropertyName) [*c]const WTF__StringImpl;
diff --git a/src/javascript/jsc/bindings/helpers.h b/src/javascript/jsc/bindings/helpers.h
index a24ecefcb..e35dd34f4 100644
--- a/src/javascript/jsc/bindings/helpers.h
+++ b/src/javascript/jsc/bindings/helpers.h
@@ -124,9 +124,9 @@ static ZigString toZigString(JSC::Identifier *str, JSC::JSGlobalObject *global)
static WTF::StringView toStringView(ZigString str) { return WTF::StringView(str.ptr, str.len); }
-static void throwException(JSC::ThrowScope &scope, ZigString msg, JSC::JSGlobalObject *global) {
- auto str = toJSString(msg, global);
- scope.throwException(global, JSC::Exception::create(global->vm(), JSC::JSValue(str)));
+static void throwException(JSC::ThrowScope &scope, ZigErrorType err, JSC::JSGlobalObject *global) {
+ scope.throwException(
+ global, JSC::Exception::create(global->vm(), JSC::JSValue((JSC::EncodedJSValue)err.ptr)));
}
static ZigString toZigString(JSC::JSValue val, JSC::JSGlobalObject *global) {
@@ -144,6 +144,4 @@ static ZigString toZigString(JSC::JSValue val, JSC::JSGlobalObject *global) {
return toZigString(str);
}
-static ZigException ZigExceptionNone = ZigException{
- 0, 0, ZigStringEmpty, ZigStringEmpty, ZigStringEmpty, -1, -1, ZigStringEmpty, nullptr};
-} // namespace Zig
+}; // namespace Zig
diff --git a/src/javascript/jsc/bindings/static_export.zig b/src/javascript/jsc/bindings/static_export.zig
index 83707b984..f8936f0df 100644
--- a/src/javascript/jsc/bindings/static_export.zig
+++ b/src/javascript/jsc/bindings/static_export.zig
@@ -4,6 +4,7 @@ symbol_name: []const u8,
local_name: []const u8,
Parent: type,
+
pub fn Decl(comptime this: *const @This()) std.builtin.TypeInfo.Declaration {
return comptime std.meta.declarationInfo(this.Parent, this.local_name);
}
diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig
index e63cee40f..50c40e746 100644
--- a/src/javascript/jsc/javascript.zig
+++ b/src/javascript/jsc/javascript.zig
@@ -11,7 +11,7 @@ const Bundler = @import("../../bundler.zig").ServeBundler;
const js_printer = @import("../../js_printer.zig");
const hash_map = @import("../../hash_map.zig");
const http = @import("../../http.zig");
-
+const ImportKind = ast.ImportKind;
usingnamespace @import("./node_env_buf_map.zig");
usingnamespace @import("./base.zig");
usingnamespace @import("./webcore/response.zig");
@@ -26,8 +26,12 @@ pub const GlobalClasses = [_]type{
Response.Class,
Headers.Class,
EventListenerMixin.addEventListener(VirtualMachine),
+ BuildError.Class,
+ ResolveError.Class,
};
+pub const LazyClasses = [_]type{};
+
pub const Module = struct {
reload_pending: bool = false,
};
@@ -106,7 +110,12 @@ pub const VirtualMachine = struct {
threadlocal var source_code_printer: js_printer.BufferPrinter = undefined;
threadlocal var source_code_printer_loaded: bool = false;
- inline fn _fetch(global: *JSGlobalObject, specifier: string, source: string) !ResolvedSource {
+ inline fn _fetch(
+ global: *JSGlobalObject,
+ specifier: string,
+ source: string,
+ log: *logger.Log,
+ ) !ResolvedSource {
std.debug.assert(VirtualMachine.vm_loaded);
std.debug.assert(VirtualMachine.vm.global == global);
@@ -158,6 +167,10 @@ pub const VirtualMachine = struct {
}
}
+ var old = vm.bundler.log;
+ vm.bundler.log = log;
+ defer vm.bundler.log = old;
+
var parse_result = vm.bundler.parse(
vm.bundler.allocator,
path,
@@ -202,7 +215,7 @@ pub const VirtualMachine = struct {
return ResolvedSource{
.source_code = ZigString.init(vm.allocator.dupe(u8, source_code_printer.ctx.written) catch unreachable),
.specifier = ZigString.init(specifier),
- .source_url = ZigString.init(path.pretty),
+ .source_url = ZigString.init(path.text),
.hash = 0,
.bytecodecache_fd = 0,
};
@@ -211,7 +224,7 @@ pub const VirtualMachine = struct {
return ResolvedSource{
.source_code = ZigString.init(try strings.quotedAlloc(VirtualMachine.vm.allocator, path.pretty)),
.specifier = ZigString.init(path.text),
- .source_url = ZigString.init(path.pretty),
+ .source_url = ZigString.init(path.text),
.hash = 0,
.bytecodecache_fd = 0,
};
@@ -295,15 +308,32 @@ pub const VirtualMachine = struct {
return ErrorableZigString.ok(ZigString.init(result));
}
- pub fn fetch(global: *JSGlobalObject, specifier: ZigString, source: ZigString) callconv(.C) ErrorableResolvedSource {
+ pub fn fetch(ret: *ErrorableResolvedSource, global: *JSGlobalObject, specifier: ZigString, source: ZigString) callconv(.C) void {
+ var log = logger.Log.init(vm.bundler.allocator);
const result = _fetch(global, specifier.slice(), source.slice()) catch |err| {
- return ErrorableResolvedSource.errFmt(err, "{s}: \"{s}\"", .{
- @errorName(err),
- specifier.slice(),
- });
+ switch (err) {
+ error.ParserError => {
+ std.debug.assert(log.msgs.items.len > 0);
+
+ switch (log.msgs.items.len) {
+ 1 => {
+ return ErrorableResolvedSource.err(error.ParserError, BuildError.create(vm.bundler.allocator, &log.msgs.items[0]));
+ },
+ else => {
+
+ },
+ }
+ },
+ else => {
+ ret.* = ErrorableResolvedSource.errFmt(err, "{s}: \"{s}\"", .{
+ @errorName(err),
+ specifier.slice(),
+ });
+ },
+ }
};
- return ErrorableResolvedSource.ok(result);
+ ret.* = ErrorableResolvedSource.ok(result);
}
pub fn loadEntryPoint(this: *VirtualMachine, entry_point: string) !void {
@@ -318,15 +348,179 @@ pub const VirtualMachine = struct {
}
if (promise.status(this.global.vm()) == JSPromise.Status.Rejected) {
- var exception = promise.result(this.global.vm()).toZigException(this.global);
- Output.prettyErrorln("<r><red>{s}<r><d>:<r> <b>{s}<r>\n<blue>{s}<r>:{d}:{d}\n{s}", .{
- exception.name.slice(),
- exception.message.slice(),
- exception.sourceURL.slice(),
- exception.line,
- exception.column,
- exception.stack.slice(),
- });
+ var exception_holder = ZigException.Holder.init();
+ var exception = exception_holder.zigException();
+ promise.result(this.global.vm()).toZigException(vm.global, exception);
+ var stderr: std.fs.File = Output.errorStream();
+ var buffered = std.io.bufferedWriter(stderr.writer());
+ var writer = buffered.writer();
+ defer buffered.flush() catch unreachable;
+ // We are going to print the stack trace backwards
+ const stack = exception.stack.frames();
+ if (stack.len > 0) {
+ var i = @intCast(i16, stack.len - 1);
+
+ var func_name_pad: usize = 0;
+ while (i >= 0) : (i -= 1) {
+ const frame = stack[@intCast(usize, i)];
+ func_name_pad = std.math.max(func_name_pad, std.fmt.count("{any}", .{
+ frame.nameFormatter(true),
+ }));
+ }
+
+ i = @intCast(i16, stack.len - 1);
+
+ while (i >= 0) : (i -= 1) {
+ const frame = stack[@intCast(usize, i)];
+ const file = frame.source_url.slice();
+ const func = frame.function_name.slice();
+
+ try writer.print(" {any}", .{frame.sourceURLFormatter(true)});
+ try writer.writeAll(" in ");
+ try writer.print(" {any}\n", .{frame.nameFormatter(true)});
+
+ // if (!frame.position.isInvalid()) {
+ // if (func.len > 0) {
+ // writer.print(
+ // comptime Output.prettyFmt("<r><d>{s}<r> {s}{s} - {s}:{d}:{d}\n", true),
+ // .{
+ // if (i > 1) "↓" else "↳",
+ // frame.code_type.ansiColor(),
+ // func,
+ // file,
+ // frame.position.line,
+ // frame.position.column_start,
+ // },
+ // ) catch unreachable;
+ // } else {
+ // writer.print(comptime Output.prettyFmt("<r><d>{s}<r> {u} - {s}{s}:{d}:{d}\n", true), .{
+ // if (i > 1) "↓" else "↳",
+ // frame.code_type.emoji(),
+
+ // frame.code_type.ansiColor(),
+ // file,
+ // frame.position.line,
+ // frame.position.column_start,
+ // }) catch unreachable;
+ // }
+ // } else {
+ // if (func.len > 0) {
+ // writer.print(
+ // comptime Output.prettyFmt("<r><d>{s}<r> {s}{s} - {s}\n", true),
+ // .{
+ // if (i > 1) "↓" else "↳",
+ // frame.code_type.ansiColor(),
+ // func,
+ // file,
+ // },
+ // ) catch unreachable;
+ // } else {
+ // writer.print(
+ // comptime Output.prettyFmt("<r><d>{s}<r> {u} - {s}{s}\n", true),
+ // .{
+ // if (i > 1) "↓" else "↳",
+ // frame.code_type.emoji(),
+ // frame.code_type.ansiColor(),
+ // file,
+ // },
+ // ) catch unreachable;
+ // }
+ // }
+ }
+ }
+
+ var line_numbers = exception.stack.source_lines_numbers[0..exception.stack.source_lines_len];
+ var max_line: i32 = -1;
+ for (line_numbers) |line| max_line = std.math.max(max_line, line);
+ const max_line_number_pad = std.fmt.count("{d}", .{max_line});
+
+ var source_lines = exception.stack.sourceLineIterator();
+ var last_pad: u64 = 0;
+ while (source_lines.untilLast()) |source| {
+ const int_size = std.fmt.count("{d}", .{source.line});
+ const pad = max_line_number_pad - int_size;
+ last_pad = pad;
+ writer.writeByteNTimes(' ', pad) catch unreachable;
+ writer.print(
+ comptime Output.prettyFmt("<r><d>{d} | <r>{s}\n", true),
+ .{
+ source.line,
+ std.mem.trim(u8, source.text, "\n"),
+ },
+ ) catch unreachable;
+ }
+
+ const name = exception.name.slice();
+ const message = exception.message.slice();
+ var did_print_name = false;
+ if (source_lines.next()) |source| {
+ const int_size = std.fmt.count("{d}", .{source.line});
+ const pad = max_line_number_pad - int_size;
+ writer.writeByteNTimes(' ', pad) catch unreachable;
+
+ std.debug.assert(!stack[0].position.isInvalid());
+ var remainder = std.mem.trim(u8, source.text, "\n");
+ const prefix = remainder[0..@intCast(usize, stack[0].position.column_start)];
+ const underline = remainder[@intCast(usize, stack[0].position.column_start)..@intCast(usize, stack[0].position.column_stop)];
+ const suffix = remainder[@intCast(usize, stack[0].position.column_stop)..];
+
+ writer.print(
+ comptime Output.prettyFmt("<r><d>{d} |<r> {s}<red>{s}<r>{s}<r>\n<r>", true),
+ .{
+ source.line,
+ prefix,
+ underline,
+ suffix,
+ },
+ ) catch unreachable;
+ var first_non_whitespace = @intCast(u32, stack[0].position.column_start);
+ while (first_non_whitespace < source.text.len and source.text[first_non_whitespace] == ' ') {
+ first_non_whitespace += 1;
+ }
+ std.debug.assert(stack.len > 0);
+ const indent = @intCast(usize, pad) + " | ".len + first_non_whitespace + 1;
+
+ writer.writeByteNTimes(' ', indent) catch unreachable;
+ writer.print(comptime Output.prettyFmt(
+ "<red><b>^<r>\n",
+ true,
+ ), .{}) catch unreachable;
+
+ if (name.len > 0 and message.len > 0) {
+ writer.print(comptime Output.prettyFmt(" <r><red><b>{s}<r><d>:<r> <b>{s}<r>\n", true), .{
+ name,
+ message,
+ }) catch unreachable;
+ } else if (name.len > 0) {
+ writer.print(comptime Output.prettyFmt(" <r><b>{s}<r>\n", true), .{name}) catch unreachable;
+ } else if (message.len > 0) {
+ writer.print(comptime Output.prettyFmt(" <r><b>{s}<r>\n", true), .{message}) catch unreachable;
+ }
+
+ did_print_name = true;
+ }
+
+ if (!did_print_name) {
+ if (name.len > 0 and message.len > 0) {
+ writer.print(comptime Output.prettyFmt("<r><red><b>{s}<r><d>:<r> <b>{s}<r>\n", true), .{
+ name,
+ message,
+ }) catch unreachable;
+ } else if (name.len > 0) {
+ writer.print(comptime Output.prettyFmt("<r><b>{s}<r>\n", true), .{name}) catch unreachable;
+ } else if (message.len > 0) {
+ writer.print(comptime Output.prettyFmt("<r><b>{s}<r>\n", true), .{name}) catch unreachable;
+ }
+ }
+
+ // Output.prettyErrorln("<r><red>{s}<r><d>:<r> <b>{s}<r>\n<blue>{s}<r>:{d}:{d}\n{s}", .{
+ // exception.name.slice(),
+ // exception.message.slice(),
+ // exception.sourceURL.slice(),
+ // exception.line,
+ // exception.column,
+ // exception.stack.slice(),
+ // });
}
}
};
@@ -411,11 +605,7 @@ pub const EventListenerMixin = struct {
var fetch_args: [1]js.JSObjectRef = undefined;
for (listeners.items) |listener| {
- fetch_args[0] = js.JSObjectMake(
- vm.ctx,
- FetchEvent.Class.get().*,
- fetch_event,
- );
+ fetch_args[0] = FetchEvent.Class.make(vm.global, fetch_event);
_ = js.JSObjectCallAsFunction(
vm.ctx,
@@ -510,3 +700,281 @@ pub const EventListenerMixin = struct {
);
}
};
+
+pub const ResolveError = struct {
+ msg: logger.Msg,
+ allocator: *std.mem.Allocator,
+ referrer: ?Fs.Path = null,
+
+ pub const Class = NewClass(
+ ResolveError,
+ .{
+ .name = "ResolveError",
+ .read_only = true,
+ },
+ .{
+ .@"referrer" = .{
+ .@"get" = getReferrer,
+ .ro = true,
+ .ts = d.ts{ .@"return" = "string" },
+ },
+ .@"message" = .{
+ .@"get" = getMessage,
+ .ro = true,
+ .ts = d.ts{ .@"return" = "string" },
+ },
+ .@"name" = .{
+ .@"get" = getName,
+ .ro = true,
+ .ts = d.ts{ .@"return" = "string" },
+ },
+ .@"specifier" = .{
+ .@"get" = getSpecifier,
+ .ro = true,
+ .ts = d.ts{ .@"return" = "string" },
+ },
+ .@"importKind" = .{
+ .@"get" = getImportKind,
+ .ro = true,
+ .ts = d.ts{ .@"return" = "string" },
+ },
+ .@"position" = .{
+ .@"get" = getPosition,
+ .ro = true,
+ .ts = d.ts{ .@"return" = "string" },
+ },
+ },
+ .{},
+ );
+
+ pub fn create(
+ msg: logger.Msg,
+ allocator: *std.mem.Allocator,
+ ) js.JSObjectRef {
+ var resolve_error = allocator.create(ResolveError) catch unreachable;
+ resolve_error.* = ResolveError{
+ .msg = msg,
+ .allocator = allocator,
+ };
+
+ return Class.make(VirtualMachine.vm.global, resolve_error);
+ }
+
+ pub fn getPosition(
+ this: *ResolveError,
+ ctx: js.JSContextRef,
+ thisObject: js.JSObjectRef,
+ prop: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef {
+ return BuildError.generatePositionObject(this.msg, ctx, exception);
+ }
+
+ pub fn getMessage(
+ this: *BuildError,
+ ctx: js.JSContextRef,
+ thisObject: js.JSObjectRef,
+ prop: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef {
+ return ZigString.init(this.msg.data.text).toValue(VirtualMachine.vm.global);
+ }
+
+ pub fn getSpecifier(
+ this: *BuildError,
+ ctx: js.JSContextRef,
+ thisObject: js.JSObjectRef,
+ prop: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef {
+ return ZigString.init(this.msg.metadata.Resolve.specifier.slice(this.msg.data.text)).toValue(VirtualMachine.vm.global);
+ }
+
+ pub fn getImportKind(
+ this: *BuildError,
+ ctx: js.JSContextRef,
+ thisObject: js.JSObjectRef,
+ prop: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef {
+ return ZigString.init(@tagName(this.msg.metadata.Resolve.import_kind)).toValue(VirtualMachine.vm.global);
+ }
+
+ pub fn getReferrer(
+ this: *BuildError,
+ ctx: js.JSContextRef,
+ thisObject: js.JSObjectRef,
+ prop: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef {
+ if (this.referrer) |referrer| {
+ return ZigString.init(referrer.text).toValue(VirtualMachine.vm.global);
+ } else {
+ return js.JSValueMakeNull(ctx);
+ }
+ }
+
+ const BuildErrorName = "ResolveError";
+ pub fn getName(
+ this: *BuildError,
+ ctx: js.JSContextRef,
+ thisObject: js.JSObjectRef,
+ prop: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef {
+ return ZigString.init(BuildErrorName).toValue(VirtualMachine.vm.global);
+ }
+};
+
+pub const BuildError = struct {
+ msg: logger.Msg,
+ // resolve_result: resolver.Result,
+ allocator: *std.mem.Allocator,
+
+ pub const Class = NewClass(
+ BuildError,
+ .{
+ .name = "BuildError",
+ .read_only = true,
+ },
+ .{},
+ .{
+ .@"message" = .{
+ .@"get" = getMessage,
+ .ro = true,
+ },
+ .@"name" = .{
+ .@"get" = getName,
+ .ro = true,
+ },
+ // This is called "position" instead of "location" because "location" may be confused with Location.
+ .@"position" = .{
+ .@"get" = getPosition,
+ .ro = true,
+ },
+ },
+ );
+
+ pub fn create(
+ allocator: *std.mem.Allocator,
+ msg: *const logger.Msg,
+ // resolve_result: *const resolver.Result,
+ ) js.JSObjectRef {
+ var build_error = allocator.create(BuildError) catch unreachable;
+ build_error.* = BuildError{
+ .msg = msg.*,
+ // .resolve_result = resolve_result.*,
+ .allocator = allocator,
+ };
+
+ return Class.make(VirtualMachine.vm.global, build_error);
+ }
+
+ pub fn getPosition(
+ this: *BuildError,
+ ctx: js.JSContextRef,
+ thisObject: js.JSObjectRef,
+ prop: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef {
+ return generatePositionObject(this.msg, ctx, exception);
+ }
+
+ pub const PositionProperties = struct {
+ const _file = ZigString.init("file");
+ var file_ptr: js.JSStringRef = null;
+ pub fn file() js.JSStringRef {
+ if (file_ptr == null) {
+ file_ptr = _file.toJSStringRef();
+ }
+ return file_ptr.?;
+ }
+ const _namespace = ZigString.init("namespace");
+ var namespace_ptr: js.JSStringRef = null;
+ pub fn namespace() js.JSStringRef {
+ if (namespace_ptr == null) {
+ namespace_ptr = _namespace.toJSStringRef();
+ }
+ return namespace_ptr.?;
+ }
+ const _line = ZigString.init("line");
+ var line_ptr: js.JSStringRef = null;
+ pub fn line() js.JSStringRef {
+ if (line_ptr == null) {
+ line_ptr = _line.toJSStringRef();
+ }
+ return line_ptr.?;
+ }
+ const _column = ZigString.init("column");
+ var column_ptr: js.JSStringRef = null;
+ pub fn column() js.JSStringRef {
+ if (column_ptr == null) {
+ column_ptr = _column.toJSStringRef();
+ }
+ return column_ptr.?;
+ }
+ const _length = ZigString.init("length");
+ var length_ptr: js.JSStringRef = null;
+ pub fn length() js.JSStringRef {
+ if (length_ptr == null) {
+ length_ptr = _length.toJSStringRef();
+ }
+ return length_ptr.?;
+ }
+ const _lineText = ZigString.init("lineText");
+ var lineText_ptr: js.JSStringRef = null;
+ pub fn lineText() js.JSStringRef {
+ if (lineText_ptr == null) {
+ lineText_ptr = _lineText.toJSStringRef();
+ }
+ return lineText_ptr.?;
+ }
+ const _offset = ZigString.init("offset");
+ var offset_ptr: js.JSStringRef = null;
+ pub fn offset() js.JSStringRef {
+ if (offset_ptr == null) {
+ offset_ptr = _offset.toJSStringRef();
+ }
+ return offset_ptr.?;
+ }
+ };
+
+ pub fn generatePositionObject(msg: logger.Msg, ctx: js.JSContextRef, exception: ExceptionValueRef) js.JSValue {
+ if (msg.data.location) |location| {
+ const ref = js.JSObjectMake(ctx, null, null);
+ js.JSObjectSetProperty(ctx, ref, PositionProperties.lineText(), ZigString.init(location.line_text orelse "").toJSStringRef(), 0, exception);
+ js.JSObjectSetProperty(ctx, ref, PositionProperties.file(), ZigString.init(location.file).toJSStringRef(), 0, exception);
+ js.JSObjectSetProperty(ctx, ref, PositionProperties.namespace(), ZigString.init(location.namespace).toJSStringRef(), 0, exception);
+ js.JSObjectSetProperty(ctx, ref, PositionProperties.line(), js.JSValueMakeNumber(ctx, location.line), 0, exception);
+ js.JSObjectSetProperty(ctx, ref, PositionProperties.column(), js.JSValueMakeNumber(ctx, location.column), 0, exception);
+ js.JSObjectSetProperty(ctx, ref, PositionProperties.length(), js.JSValueMakeNumber(ctx, location.length), 0, exception);
+ js.JSObjectSetProperty(ctx, ref, PositionProperties.offset(), js.JSValueMakeNumber(ctx, location.offset), 0, exception);
+ return ref;
+ }
+
+ return js.JSValueMakeNull(ctx);
+ }
+
+ pub fn getMessage(
+ this: *BuildError,
+ ctx: js.JSContextRef,
+ thisObject: js.JSObjectRef,
+ prop: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef {
+ return ZigString.init(this.msg.data.text).toValue(VirtualMachine.vm.global);
+ }
+
+ const BuildErrorName = "BuildError";
+ pub fn getName(
+ this: *BuildError,
+ ctx: js.JSContextRef,
+ thisObject: js.JSObjectRef,
+ prop: js.JSStringRef,
+ exception: js.ExceptionRef,
+ ) js.JSValueRef {
+ return ZigString.init(BuildErrorName).toValue(VirtualMachine.vm.global);
+ }
+};
+
+pub const JSPrivateDataTag = JSPrivateDataPtr.Tag;
diff --git a/src/javascript/jsc/webcore/response.zig b/src/javascript/jsc/webcore/response.zig
index 36c6528b5..06ca76d2f 100644
--- a/src/javascript/jsc/webcore/response.zig
+++ b/src/javascript/jsc/webcore/response.zig
@@ -121,13 +121,16 @@ pub const Response = struct {
// return null;
// }
- var response = getAllocator(ctx).create(Response) catch return null;
+ var tup = Repsonse.Class.makeObject(
+ ctx,
+ getAllocator(ctx),
+ );
- response.* = Response{
+ tup.ptr.* = Response{
.body = body,
.allocator = getAllocator(ctx),
};
- return js.JSObjectMake(ctx, Response.Class.get().*, response);
+ return tup.ref;
}
};
@@ -290,7 +293,7 @@ pub const Headers = struct {
};
}
- return js.JSObjectMake(ctx, Headers.Class.get().*, headers);
+ return Headers.Class.make(ctx, headers);
}
pub fn finalize(
@@ -922,7 +925,7 @@ pub const Request = struct {
this.headers = Headers.fromRequestCtx(getAllocator(ctx), this.request_context) catch unreachable;
}
- return js.JSObjectMake(ctx, Headers.Class.get().*, &this.headers.?);
+ return Headers.Class.make(ctx, &this.headers.?);
}
pub fn getIntegrity(
this: *Request,
@@ -1068,7 +1071,7 @@ pub const FetchEvent = struct {
prop: js.JSStringRef,
exception: js.ExceptionRef,
) js.JSValueRef {
- return js.JSObjectMake(ctx, Request.Class.get().*, &this.request);
+ return Request.Class.make(ctx, &this.request);
}
// https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent/respondWith
@@ -1096,14 +1099,11 @@ pub const FetchEvent = struct {
return js.JSValueMakeUndefined(ctx);
}
- var ptr = js.JSObjectGetPrivate(arg);
- if (ptr == null) {
+ var response: *Response = GetJSPrivateData(Response, arg) orelse {
JSError(getAllocator(ctx), "event.respondWith()'s Response object was invalid. This may be an internal error.", .{}, ctx, exception);
this.request_context.sendInternalError(error.respondWithWasInvalid) catch {};
return js.JSValueMakeUndefined(ctx);
- }
-
- var response = @ptrCast(*Response, @alignCast(@alignOf(*Response), ptr.?));
+ };
var needs_mime_type = true;
var content_length: ?usize = null;
diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig
index a987351c7..5ca0b3f57 100644
--- a/src/js_parser/js_parser.zig
+++ b/src/js_parser/js_parser.zig
@@ -17,17 +17,22 @@ usingnamespace @import("imports.zig");
const TemplatePartTuple = std.meta.Tuple(&[_]type{ []E.TemplatePart, logger.Loc });
const ScopeOrderList = std.ArrayListUnmanaged(?ScopeOrder);
-pub fn ExpressionTransposer(comptime ctx: type, visitor: fn (ptr: *ctx, arg: Expr, state: anytype) Expr) type {
+pub fn ExpressionTransposer(
+ comptime Kontext: type,
+ visitor: fn (ptr: *Kontext, arg: Expr, state: anytype) Expr,
+) type {
return struct {
+ pub const Context = Kontext;
+ pub const This = @This();
context: *Context,
- pub fn init(c: *Context) @This() {
- return @This(){
+ pub fn init(c: *Context) This {
+ return This{
.context = c,
};
}
- pub fn maybeTransposeIf(self: *@This(), arg: Expr, state: anytype) Expr {
+ pub fn maybeTransposeIf(self: *This, arg: Expr, state: anytype) Expr {
switch (arg.data) {
.e_if => |ex| {
ex.yes = self.maybeTransposeIf(ex.yes, state);
@@ -39,7 +44,6 @@ pub fn ExpressionTransposer(comptime ctx: type, visitor: fn (ptr: *ctx, arg: Exp
},
}
}
- pub const Context = ctx;
};
}
diff --git a/src/js_printer.zig b/src/js_printer.zig
index 2f02e4208..727a849b6 100644
--- a/src/js_printer.zig
+++ b/src/js_printer.zig
@@ -127,10 +127,6 @@ pub fn NewPrinter(
comptime rewrite_esm_to_cjs: bool,
comptime speedy: bool,
) type {
- // comptime const comptime_buf_len = 64;
- // comptime var comptime_buf = [comptime_buf_len]u8{};
- // comptime var comptime_buf_i: usize = 0;
-
return struct {
symbols: Symbol.Map,
import_records: []importRecord.ImportRecord,
@@ -153,53 +149,6 @@ pub fn NewPrinter(
prev_stmt_tag: Stmt.Tag = .s_empty,
const Printer = @This();
- pub fn comptime_flush(p: *Printer) void {}
-
- // pub fn comptime_flush(p: *Printer) callconv(.Inline) void {
- // const result = comptime {
- // if (comptime_buf_i > 0) {
- // return comptime_buf[0..comptime_buf_i];
- // } else {
- // return "";
- // }
- // };
-
- // if (result.len) {
- // p.print(result);
- // comptime {
- // if (comptime_buf_i > 0) {
- // comptime_buf_i = 0;
- // while (comptime_buf_i < comptime_buf_i) {
- // comptime_buf[comptime_buf_i] = 0;
- // comptime_buf_i += 1;
- // }
- // comptime_buf_i = 0;
- // }
- // }
- // }
- // }
- // pub fn comptime_print(p: *Printer, str: comptime []const u8) callconv(.Inline) void {
- // comptime const needsFlush = (str.len + comptime_buf_i >= comptime_buf_len - 1);
- // if (needsFlush) {
- // p.comptime_flush();
- // }
-
- // comptime {
- // if (str.len > 63) {
- // @compileError("comptime_print buffer overflow");
- // return;
- // }
- // }
-
- // comptime {
- // comptime str_i = 0;
- // while (str_i < str.len) {
- // comptime_buf[comptime_buf_i] = str[str_i];
- // comptime_buf_i += 1;
- // str_i += 1;
- // }
- // }
- // }
pub fn writeAll(p: *Printer, bytes: anytype) anyerror!void {
p.print(bytes);
@@ -234,8 +183,6 @@ pub fn NewPrinter(
}
pub fn printIndent(p: *Printer) void {
- comptime_flush(p);
-
if (p.options.indent == 0) {
return;
}
@@ -2149,7 +2096,6 @@ pub fn NewPrinter(
debug("<printStmt>: {s}\n", .{stmt});
defer debug("</printStmt>: {s}\n", .{stmt});
- p.comptime_flush();
p.addSourceMapping(stmt.loc);
switch (stmt.data) {
diff --git a/src/linker.zig b/src/linker.zig
index 44439a0ec..4e90d0072 100644
--- a/src/linker.zig
+++ b/src/linker.zig
@@ -160,12 +160,10 @@ pub fn NewLinker(comptime BundlerType: type) type {
unreachable;
}
-
pub inline fn nodeModuleBundleImportPath(this: *const ThisLinker) string {
return if (this.options.node_modules_bundle_url.len > 0) this.options.node_modules_bundle_url else this.options.node_modules_bundle.?.bundle.import_from_name;
}
-
// pub const Scratch = struct {
// threadlocal var externals: std.ArrayList(u32) = undefined;
// threadlocal var has_externals: std.ArrayList(u32) = undefined;
@@ -317,24 +315,26 @@ pub fn NewLinker(comptime BundlerType: type) type {
error.ModuleNotFound => {
if (Resolver.isPackagePath(import_record.path.text)) {
if (linker.options.platform.isWebLike() and Options.ExternalModules.isNodeBuiltin(import_record.path.text)) {
- try linker.log.addRangeErrorFmt(
+ try linker.log.addResolveError(
&result.source,
import_record.range,
linker.allocator,
"Could not resolve: \"{s}\". Try setting --platform=\"node\"",
.{import_record.path.text},
+ import_record.kind,
);
} else {
- try linker.log.addRangeErrorFmt(
+ try linker.log.addResolveError(
&result.source,
import_record.range,
linker.allocator,
"Could not resolve: \"{s}\". Maybe you need to \"npm install\" (or yarn/pnpm)?",
.{import_record.path.text},
+ import_record.kind,
);
}
} else {
- try linker.log.addRangeErrorFmt(
+ try linker.log.addResolveError(
&result.source,
import_record.range,
linker.allocator,
@@ -342,6 +342,7 @@ pub fn NewLinker(comptime BundlerType: type) type {
.{
import_record.path.text,
},
+ import_record.kind,
);
continue;
}
diff --git a/src/logger.zig b/src/logger.zig
index 9ab04b398..fdf628ef7 100644
--- a/src/logger.zig
+++ b/src/logger.zig
@@ -1,6 +1,7 @@
const std = @import("std");
const Api = @import("./api/schema.zig").Api;
-
+const js = @import("./javascript/jsc/bindings/bindings.zig");
+const ImportKind = @import("./import_record.zig").ImportKind;
usingnamespace @import("global.zig");
const fs = @import("fs.zig");
@@ -161,11 +162,42 @@ pub const Data = struct {
}
};
+pub const BabyString = packed struct {
+ offset: u16,
+ len: u16,
+
+ pub fn in(parent: string, text: string) BabyString {
+ return BabyString{
+ .offset = @truncate(u16, std.mem.indexOf(u8, parent, text) orelse unreachable),
+ .len = @truncate(u16, text.len),
+ };
+ }
+
+ pub fn slice(container: string) string {
+ return container[offset..][0..len];
+ }
+};
+
pub const Msg = struct {
kind: Kind = Kind.err,
data: Data,
+ metadata: Metadata = .{ .build = 0 },
notes: ?[]Data = null,
+ pub const Metadata = union(Tag) {
+ build: u0,
+ resolve: Resolve,
+ pub const Tag = enum(u8) {
+ build = 1,
+ resolve = 2,
+ };
+
+ pub const Resolve = struct {
+ specifier: BabyString,
+ import_kind: ImportKind,
+ };
+ };
+
pub fn toAPI(this: *const Msg, allocator: *std.mem.Allocator) Api.Message {
var msg = Api.Message{
.kind = this.kind.toAPI(),
@@ -183,6 +215,7 @@ pub const Msg = struct {
return msg;
}
+
pub fn toAPIFromList(comptime ListType: type, list: ListType, allocator: *std.mem.Allocator) ![]Api.Message {
var out_list = try allocator.alloc(Api.Msg, list.items.len);
for (list.items) |item, i| {
@@ -316,6 +349,32 @@ pub const Log = struct {
});
}
+ pub fn addResolveError(
+ log: *Log,
+ source: *const Source,
+ r: Range,
+ allocator: *std.mem.Allocator,
+ comptime fmt: string,
+ args: anytype,
+ import_kind: ImportKind,
+ ) !void {
+ const text = try std.fmt.allocPrint(allocator, fmt, args);
+ // TODO: fix this. this is stupid, it should be returned in allocPrint.
+ const specifier = BabyString.in(text, args.@"0");
+ log.errors += 1;
+ try log.addMsg(
+ Msg{
+ .kind = .err,
+ .data = rangeData(
+ source,
+ r,
+ text,
+ ),
+ .metadata = .{ .resolve = Msg.Metadata.Resolve{ .specifier = specifier, .import_kind = import_kind } },
+ },
+ );
+ }
+
pub fn addRangeError(log: *Log, source: ?*const Source, r: Range, text: string) !void {
log.errors += 1;
try log.addMsg(Msg{
@@ -432,6 +491,15 @@ pub const Log = struct {
try msg.writeFormat(to);
}
}
+
+ pub fn toZigException(this: *const Log, allocator: *std.mem.Allocator) *js.ZigException.Holder {
+ var holder = try allocator.create(js.ZigException.Holder);
+ holder.* = js.ZigException.Holder.init();
+ var zig_exception: *js.ZigException = holder.zigException();
+ zig_exception.exception = this;
+ zig_exception.code = js.JSErrorCode.BundlerError;
+ return holder;
+ }
};
pub inline fn usize2Loc(loc: usize) Loc {
diff --git a/src/runtime/errors.ts b/src/runtime/errors.ts
new file mode 100644
index 000000000..ad54cc322
--- /dev/null
+++ b/src/runtime/errors.ts
@@ -0,0 +1,82 @@
+var __BuildError;
+var __ResolveError;
+var __ImportKind;
+{
+ enum ImportKind {
+ entry_point = 0,
+ stmt = 1,
+ require = 2,
+ dynamic = 3,
+ require_resolve = 4,
+ at = 5,
+ at_conditional = 6,
+ url = 7,
+ }
+
+ type ErrorPosition = {
+ file: string;
+ namespace: string;
+ line: number; // 1-based
+ column: number; // 0-based, byte offset relative to lineText
+ length: number; // in bytes
+ /** line of text, possibly empty */
+ lineText: string;
+ /** byte offset relative to the start of the file */
+ offset: number;
+ };
+
+ interface BuildErrorImplementation {
+ position: ErrorPosition;
+ name: string;
+ message: string;
+ }
+
+ interface ResolveErrorImplementation extends BuildErrorImplementation {
+ specifier: string;
+ importKind: ImportKind;
+ }
+
+ class BuildError extends Error {
+ constructor(data: BuildErrorImplementation) {
+ super(data.message);
+ this.name = data.name;
+ this.data = data;
+ }
+ data: BuildErrorImplementation;
+
+ get position() {
+ return this.data.position;
+ }
+
+ get [Symbol.toStringTag]() {
+ return `${this.name}: ${this.message}`;
+ }
+ }
+
+ class ResolveError extends BuildError {
+ constructor(data: ResolveErrorImplementation) {
+ super(data);
+ this.name = data.name;
+ this.data = data;
+ }
+ data: ResolveErrorImplementation;
+
+ get importKind() {
+ return this.data.importKind;
+ }
+
+ get specifier() {
+ return this.data.specifier || "";
+ }
+ }
+
+ __ResolveError = ResolveError;
+ __BuildError = BuildError;
+ __ImportKind = ImportKind;
+}
+
+export {
+ __ResolveError as ResolveError,
+ __BuildError as BuildError,
+ __ImportKind as ImportKind,
+};
diff --git a/src/runtime/index.ts b/src/runtime/index.ts
index 873666412..1566c70b8 100644
--- a/src/runtime/index.ts
+++ b/src/runtime/index.ts
@@ -1,2 +1,3 @@
export * from "./hmr";
+export * from "./errors";
export * from "../runtime.js";
diff --git a/src/tagged_pointer.zig b/src/tagged_pointer.zig
new file mode 100644
index 000000000..332464007
--- /dev/null
+++ b/src/tagged_pointer.zig
@@ -0,0 +1,186 @@
+const std = @import("std");
+
+const TagSize = u15;
+const AddressableSize = u49;
+
+const TaggedPointer = packed struct {
+ _ptr: AddressableSize,
+ data: TagSize,
+
+ pub inline fn init(ptr: anytype, data: TagSize) TaggedPointer {
+ const Ptr = @TypeOf(ptr);
+
+ if (comptime @typeInfo(Ptr) != .Pointer and Ptr != ?*c_void) {
+ @compileError(@typeName(Ptr) ++ " must be a ptr, received: " ++ @tagName(@typeInfo(Ptr)));
+ }
+
+ const address = @ptrToInt(ptr);
+
+ return TaggedPointer{
+ ._ptr = @truncate(AddressableSize, address),
+ .data = data,
+ };
+ }
+
+ pub inline fn get(this: TaggedPointer, comptime Type: type) *Type {
+ return @intToPtr(*Type, @intCast(usize, this._ptr));
+ }
+
+ pub inline fn from(val: anytype) TaggedPointer {
+ const ValueType = @TypeOf(val);
+ return switch (ValueType) {
+ f64, i64, u64 => @bitCast(TaggedPointer, val),
+ ?*c_void, *c_void => @bitCast(TaggedPointer, @ptrToInt(val)),
+ else => @compileError("Unsupported type: " ++ @typeName(ValueType)),
+ };
+ }
+
+ pub inline fn to(this: TaggedPointer) *c_void {
+ return @intToPtr(*c_void, @bitCast(u64, this));
+ }
+};
+
+pub fn TaggedPointerUnion(comptime Types: anytype) type {
+ const TagType: type = tag_break: {
+ var enumFields: [Types.len]std.builtin.TypeInfo.EnumField = undefined;
+ var decls = [_]std.builtin.TypeInfo.Declaration{};
+
+ inline for (Types) |field, i| {
+ enumFields[i] = .{
+ .name = @typeName(field),
+ .value = std.math.maxInt(TagSize) - 1 - i,
+ };
+ }
+
+ break :tag_break @Type(.{
+ .Enum = .{
+ .layout = .Auto,
+ .tag_type = TagSize,
+ .fields = &enumFields,
+ .decls = &decls,
+ .is_exhaustive = false,
+ },
+ });
+ };
+
+ return struct {
+ pub const Tag = TagType;
+ repr: TaggedPointer,
+ const This = @This();
+ fn assert_type(comptime Type: type) void {
+ if (!comptime @hasField(Tag, @typeName(Type))) {
+ @compileError("TaggedPointerUnion does not have " ++ @typeName(Type) ++ ".");
+ }
+ }
+ pub inline fn get(this: This, comptime Type: anytype) ?*Type {
+ comptime assert_type(Type);
+
+ return if (this.is(Type)) this.as(Type) else null;
+ }
+
+ pub inline fn tag(this: This) TagType {
+ return @intToEnum(TagType, this.repr.data);
+ }
+
+ /// unsafely cast a tagged pointer to a specific type, without checking that it's really that type
+ pub inline fn as(this: This, comptime Type: type) *Type {
+ comptime assert_type(Type);
+ return this.repr.get(Type);
+ }
+
+ pub inline fn is(this: This, comptime Type: type) bool {
+ comptime assert_type(Type);
+ return this.repr.data == comptime @enumToInt(@field(Tag, @typeName(Type)));
+ }
+
+ pub inline fn isValidPtr(_ptr: ?*c_void) bool {
+ return This.isValid(This.from(_ptr));
+ }
+
+ pub inline fn isValid(this: This) bool {
+ return switch (this.repr.data) {
+ @enumToInt(
+ @field(Tag, @typeName(Types[Types.len - 1])),
+ )...@enumToInt(
+ @field(Tag, @typeName(Types[0])),
+ ) => true,
+ else => false,
+ };
+ }
+
+ pub inline fn from(_ptr: ?*c_void) This {
+ return This{ .repr = TaggedPointer.from(_ptr) };
+ }
+
+ pub inline fn ptr(this: This) *c_void {
+ return this.repr.to();
+ }
+
+ pub inline fn init(_ptr: anytype) This {
+ const Type = std.meta.Child(@TypeOf(_ptr));
+
+ // there will be a compiler error if the passed in type doesn't exist in the enum
+ return This{ .repr = TaggedPointer.init(_ptr, @enumToInt(@field(Tag, @typeName(Type)))) };
+ }
+ };
+}
+
+test "TaggedPointerUnion" {
+ const IntPrimtiive = struct { val: u32 = 0 };
+ const StringPrimitive = struct { val: []const u8 = "" };
+ const Object = struct { blah: u32, val: u32 };
+ // const Invalid = struct {
+ // wrong: bool = true,
+ // };
+ const Union = TaggedPointerUnion(.{ IntPrimtiive, StringPrimitive, Object });
+ var str = try std.heap.c_allocator.create(StringPrimitive);
+ str.* = StringPrimitive{ .val = "hello!" };
+ var un = Union.init(str);
+ try std.testing.expect(un.is(StringPrimitive));
+ try std.testing.expectEqualStrings(un.as(StringPrimitive).val, "hello!");
+ try std.testing.expect(!un.is(IntPrimtiive));
+ const num = try std.heap.c_allocator.create(IntPrimtiive);
+ num.val = 9999;
+
+ var un2 = Union.init(num);
+
+ try std.testing.expect(un2.as(IntPrimtiive).val == 9999);
+
+ try std.testing.expect(un.tag() == .StringPrimitive);
+ try std.testing.expect(un2.tag() == .IntPrimtiive);
+
+ un2.repr.data = 0;
+ try std.testing.expect(un2.tag() != .IntPrimtiive);
+ try std.testing.expect(un2.get(IntPrimtiive) == null);
+ // try std.testing.expect(un2.is(Invalid) == false);
+}
+
+test "TaggedPointer" {
+ const Hello = struct {
+ what: []const u8,
+ };
+
+ var hello_struct_ptr = try std.heap.c_allocator.create(Hello);
+ hello_struct_ptr.* = Hello{ .what = "hiiii" };
+ var tagged = TaggedPointer.init(hello_struct_ptr, 0);
+ try std.testing.expectEqual(tagged.get(Hello), hello_struct_ptr);
+ try std.testing.expectEqualStrings(tagged.get(Hello).what, hello_struct_ptr.what);
+ tagged = TaggedPointer.init(hello_struct_ptr, 100);
+ try std.testing.expectEqual(tagged.get(Hello), hello_struct_ptr);
+ try std.testing.expectEqualStrings(tagged.get(Hello).what, hello_struct_ptr.what);
+ tagged = TaggedPointer.init(hello_struct_ptr, std.math.maxInt(TagSize) - 500);
+ try std.testing.expectEqual(tagged.get(Hello), hello_struct_ptr);
+ try std.testing.expectEqual(tagged.data, std.math.maxInt(TagSize) - 500);
+ try std.testing.expectEqualStrings(tagged.get(Hello).what, hello_struct_ptr.what);
+
+ var i: TagSize = 0;
+ while (i < std.math.maxInt(TagSize) - 1) : (i += 1) {
+ hello_struct_ptr = try std.heap.c_allocator.create(Hello);
+ const what = try std.fmt.allocPrint(std.heap.c_allocator, "hiiii {d}", .{i});
+ hello_struct_ptr.* = Hello{ .what = what };
+ try std.testing.expectEqualStrings(TaggedPointer.from(TaggedPointer.init(hello_struct_ptr, i).to()).get(Hello).what, what);
+ var this = TaggedPointer.from(TaggedPointer.init(hello_struct_ptr, i).to());
+ try std.testing.expect(this.data == i);
+ try std.testing.expect(this.data != i + 1);
+ }
+}