Former-commit-id: 0dc1c1a74b845d037326f4f2facd786924ca722e
This commit is contained in:
Jarred Sumner
2021-08-01 19:04:38 -07:00
parent 7245f90b2d
commit 85b6d448ce
27 changed files with 1743 additions and 324 deletions

View File

@@ -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;