Skip to content

Commit

Permalink
skeleton code
Browse files Browse the repository at this point in the history
  • Loading branch information
Jarred-Sumner committed Sep 24, 2021
1 parent bdfb5a9 commit 940570a
Show file tree
Hide file tree
Showing 9 changed files with 500 additions and 219 deletions.
13 changes: 7 additions & 6 deletions src/bundler.zig
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ pub const Bundler = struct {
// must be pointer array because we can't we don't want the source to point to invalid memory if the array size is reallocated
virtual_modules: std.ArrayList(*ClientEntryPoint),

macro_context: ?*js_ast.Macro.MacroContext = null,
macro_context: ?js_ast.Macro.MacroContext = null,

pub const isCacheEnabled = cache_files;

Expand Down Expand Up @@ -826,7 +826,7 @@ pub const Bundler = struct {
} else {}

for (bundler.options.entry_points) |entry_point| {
if (bundler.options.platform == .bun) continue;
if (bundler.options.platform.isBun()) continue;
defer this.bundler.resetStore();

const entry_point_path = bundler.normalizeEntryPointPath(entry_point);
Expand All @@ -846,7 +846,7 @@ pub const Bundler = struct {
bundler.options.framework.?.override_modules_hashes[i] = std.hash.Wyhash.hash(0, key);
}
}
if (bundler.options.platform == .bun) {
if (bundler.options.platform.isBun()) {
if (framework.server.isEnabled()) {
const resolved = try bundler.linker.resolver.resolve(
bundler.fs.top_level_dir,
Expand Down Expand Up @@ -1047,7 +1047,7 @@ pub const Bundler = struct {

const basename = std.fs.path.basename(std.mem.span(destination));
const extname = std.fs.path.extension(basename);
javascript_bundle.import_from_name = if (bundler.options.platform == .bun)
javascript_bundle.import_from_name = if (bundler.options.platform.isBun())
"/node_modules.server.bun"
else
try std.fmt.allocPrint(
Expand Down Expand Up @@ -2406,20 +2406,21 @@ pub const Bundler = struct {
// or you're running in SSR
// or the file is a node_module
opts.features.hot_module_reloading = bundler.options.hot_module_reloading and
bundler.options.platform != .bun and
bundler.options.platform.isNotBun() and
(!opts.can_import_from_bundle or
(opts.can_import_from_bundle and !path.isNodeModule()));
opts.features.react_fast_refresh = opts.features.hot_module_reloading and
jsx.parse and
bundler.options.jsx.supports_fast_refresh;
opts.filepath_hash_for_hmr = file_hash orelse 0;
opts.warn_about_unbundled_modules = bundler.options.platform != .bun;
opts.warn_about_unbundled_modules = bundler.options.platform.isNotBun();

if (bundler.macro_context == null) {
bundler.macro_context = js_ast.Macro.MacroContext.init(bundler);
}

opts.macro_context = &bundler.macro_context.?;
opts.features.is_macro_runtime = bundler.options.platform == .bun_macro;

const value = (bundler.resolver.caches.js.parse(
allocator,
Expand Down
4 changes: 2 additions & 2 deletions src/defines.zig
Original file line number Diff line number Diff line change
Expand Up @@ -268,10 +268,10 @@ pub const Define = struct {
// Step 2. Swap in certain literal values because those can be constant folded
define.identifiers.putAssumeCapacity("undefined", value_define);
define.identifiers.putAssumeCapacity("NaN", DefineData{
.value = js_ast.Expr.Data{ .e_number = &nan_val },
.value = js_ast.Expr.Data{ .e_number = nan_val },
});
define.identifiers.putAssumeCapacity("Infinity", DefineData{
.value = js_ast.Expr.Data{ .e_number = &inf_val },
.value = js_ast.Expr.Data{ .e_number = inf_val },
});

// Step 3. Load user data into hash tables
Expand Down
2 changes: 2 additions & 0 deletions src/feature_flags.zig
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,5 @@ pub const CSSInJSImportBehavior = enum {
// having issues compiling WebKit with this enabled
pub const remote_inspector = false;
pub const auto_import_buffer = false;

pub const is_macro_enabled = env.isDebug;
2 changes: 2 additions & 0 deletions src/javascript/jsc/base.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1539,6 +1539,7 @@ export fn MarkedArrayBuffer_deallocator(bytes_: *c_void, ctx_: *c_void) void {
pub fn castObj(obj: js.JSObjectRef, comptime Type: type) *Type {
return JSPrivateDataPtr.from(js.JSObjectGetPrivate(obj)).as(Type);
}
const JSExpr = @import("../../js_ast.zig").Macro.JSExpr;

pub const JSPrivateDataPtr = TaggedPointerUnion(.{
ResolveError,
Expand All @@ -1549,6 +1550,7 @@ pub const JSPrivateDataPtr = TaggedPointerUnion(.{
Headers,
Body,
Router,
JSExpr,
});

pub inline fn GetJSPrivateData(comptime Type: type, ref: js.JSObjectRef) ?*Type {
Expand Down
116 changes: 113 additions & 3 deletions src/javascript/jsc/javascript.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ const Fs = @import("../../fs.zig");
const Resolver = @import("../../resolver/resolver.zig");
const ast = @import("../../import_record.zig");
const NodeModuleBundle = @import("../../node_module_bundle.zig").NodeModuleBundle;
const MacroEntryPoint = @import("../../bundler.zig").MacroEntryPoint;
const logger = @import("../../logger.zig");
const Api = @import("../../api/schema.zig").Api;
const options = @import("../../options.zig");
const Bundler = @import("../../bundler.zig").Bundler;
const ServerEntryPoint = @import("../../bundler.zig").ServerEntryPoint;
const js_printer = @import("../../js_printer.zig");
const js_parser = @import("../../js_parser.zig");
const js_ast = @import("../../js_ast.zig");
const hash_map = @import("../../hash_map.zig");
const http = @import("../../http.zig");
const ImportKind = ast.ImportKind;
Expand Down Expand Up @@ -87,6 +89,41 @@ pub const Bun = struct {
return css_imports_list_strings[0..tail];
}

pub fn registerMacro(
this: void,
ctx: js.JSContextRef,
function: js.JSObjectRef,
thisObject: js.JSObjectRef,
arguments: []const js.JSValueRef,
exception: js.ExceptionRef,
) js.JSValueRef {
if (arguments.len != 2 or !js.JSValueIsNumber(ctx, arguments[0])) {
JSError(getAllocator(ctx), "Internal error registering macros: invalid args", .{}, ctx, exception);
return js.JSValueMakeUndefined(ctx);
}
// TODO: make this faster
const id = @truncate(i32, @floatToInt(i64, js.JSValueToNumber(ctx, arguments[0], exception)));
if (id == -1 or id == 0) {
JSError(getAllocator(ctx), "Internal error registering macros: invalid id", .{}, ctx, exception);
return js.JSValueMakeUndefined(ctx);
}

if (!js.JSValueIsObject(ctx, arguments[1]) or !js.JSObjectIsFunction(ctx, arguments[1])) {
JSError(getAllocator(ctx), "Macro must be a function. Received: {s}", .{@tagName(js.JSValueGetType(ctx, arguments[1]))}, ctx, exception);
return js.JSValueMakeUndefined(ctx);
}

var get_or_put_result = VirtualMachine.vm.macros.getOrPut(id) catch unreachable;
if (get_or_put_result.found_existing) {
js.JSValueUnprotect(ctx, get_or_put_result.value_ptr.*);
}

js.JSValueProtect(ctx, arguments[1]);
get_or_put_result.value_ptr.* = arguments[1];

return js.JSValueMakeUndefined(ctx);
}

pub fn getCWD(
this: void,
ctx: js.JSContextRef,
Expand Down Expand Up @@ -403,6 +440,13 @@ pub const Bun = struct {
.@"return" = "string",
},
},
.registerMacro = .{
.rfn = Bun.registerMacro,
.ts = d.ts{
.name = "registerMacro",
.@"return" = "undefined",
},
},
},
.{
.main = .{
Expand Down Expand Up @@ -462,8 +506,25 @@ pub const VirtualMachine = struct {
transpiled_count: usize = 0,
resolved_count: usize = 0,
had_errors: bool = false,
pub var vm_loaded = false;
pub var vm: *VirtualMachine = undefined;

macros: MacroMap,
macro_entry_points: std.AutoArrayHashMap(i32, *MacroEntryPoint),
macro_mode: bool = false,

pub const MacroMap = std.AutoArrayHashMap(i32, js.JSObjectRef);

pub threadlocal var vm_loaded = false;
pub threadlocal var vm: *VirtualMachine = undefined;

pub fn enableMacroMode(this: *VirtualMachine) void {
this.bundler.options.platform = .bun_macro;
this.macro_mode = true;
}

pub fn disableMacroMode(this: *VirtualMachine) void {
this.bundler.options.platform = .bun;
this.macro_mode = false;
}

pub fn init(
allocator: *std.mem.Allocator,
Expand Down Expand Up @@ -502,6 +563,9 @@ pub const VirtualMachine = struct {
.log = log,
.flush_list = std.ArrayList(string).init(allocator),
.blobs = try Blob.Group.init(allocator),

.macros = MacroMap.init(allocator),
.macro_entry_points = @TypeOf(VirtualMachine.vm.macro_entry_points).init(allocator),
};

VirtualMachine.vm.bundler.configureLinker();
Expand Down Expand Up @@ -771,10 +835,16 @@ pub const VirtualMachine = struct {
ret.result = null;
ret.path = vm.entry_point.source.path.text;
return;
} else if (specifier.len > js_ast.Macro.namespaceWithColon.len and strings.eqlComptimeIgnoreLen(specifier[0..js_ast.Macro.namespaceWithColon.len], js_ast.Macro.namespaceWithColon)) {
ret.result = null;
ret.path = specifier;
return;
}

const is_special_source = strings.eqlComptime(source, main_file_name) or js_ast.Macro.isMacroPath(source);

const result = try vm.bundler.resolver.resolve(
if (!strings.eqlComptime(source, main_file_name)) Fs.PathName.init(source).dirWithTrailingSlash() else VirtualMachine.vm.bundler.fs.top_level_dir,
if (!is_special_source) Fs.PathName.init(source).dirWithTrailingSlash() else VirtualMachine.vm.bundler.fs.top_level_dir,
specifier,
.stmt,
);
Expand Down Expand Up @@ -1050,6 +1120,46 @@ pub const VirtualMachine = struct {
return promise;
}

pub fn loadMacroEntryPoint(this: *VirtualMachine, entry_path: string, function_name: string, specifier: string, hash: i32) !*JSInternalPromise {
var entry_point_entry = try this.macro_entry_points.getOrPut(hash);

if (!entry_point_entry.found_existing) {
var macro_entry_pointer: *MacroEntryPoint = this.allocator.create(MacroEntryPoint) catch unreachable;
entry_point_entry.value_ptr.* = macro_entry_pointer;
try macro_entry_pointer.generate(&this.bundler, Fs.PathName.init(entry_path), function_name, hash, specifier);
}
var entry_point = entry_point_entry.value_ptr.*;

var promise: *JSInternalPromise = undefined;
// We first import the node_modules bundle. This prevents any potential TDZ issues.
// The contents of the node_modules bundle are lazy, so hopefully this should be pretty quick.
if (this.node_modules != null) {
promise = JSModuleLoader.loadAndEvaluateModule(this.global, ZigString.init(std.mem.span(bun_file_import_path)));

this.global.vm().drainMicrotasks();

while (promise.status(this.global.vm()) == JSPromise.Status.Pending) {
this.global.vm().drainMicrotasks();
}

if (promise.status(this.global.vm()) == JSPromise.Status.Rejected) {
return promise;
}

_ = promise.result(this.global.vm());
}

promise = JSModuleLoader.loadAndEvaluateModule(this.global, ZigString.init(entry_point.source.path.text));

this.global.vm().drainMicrotasks();

while (promise.status(this.global.vm()) == JSPromise.Status.Pending) {
this.global.vm().drainMicrotasks();
}

return promise;
}

// When the Error-like object is one of our own, it's best to rely on the object directly instead of serializing it to a ZigException.
// This is for:
// - BuildError
Expand Down
Loading

0 comments on commit 940570a

Please sign in to comment.