Skip to content

Commit 940570a

Browse files
committed
skeleton code
1 parent bdfb5a9 commit 940570a

File tree

9 files changed

+500
-219
lines changed

9 files changed

+500
-219
lines changed

src/bundler.zig

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ pub const Bundler = struct {
123123
// 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
124124
virtual_modules: std.ArrayList(*ClientEntryPoint),
125125

126-
macro_context: ?*js_ast.Macro.MacroContext = null,
126+
macro_context: ?js_ast.Macro.MacroContext = null,
127127

128128
pub const isCacheEnabled = cache_files;
129129

@@ -826,7 +826,7 @@ pub const Bundler = struct {
826826
} else {}
827827

828828
for (bundler.options.entry_points) |entry_point| {
829-
if (bundler.options.platform == .bun) continue;
829+
if (bundler.options.platform.isBun()) continue;
830830
defer this.bundler.resetStore();
831831

832832
const entry_point_path = bundler.normalizeEntryPointPath(entry_point);
@@ -846,7 +846,7 @@ pub const Bundler = struct {
846846
bundler.options.framework.?.override_modules_hashes[i] = std.hash.Wyhash.hash(0, key);
847847
}
848848
}
849-
if (bundler.options.platform == .bun) {
849+
if (bundler.options.platform.isBun()) {
850850
if (framework.server.isEnabled()) {
851851
const resolved = try bundler.linker.resolver.resolve(
852852
bundler.fs.top_level_dir,
@@ -1047,7 +1047,7 @@ pub const Bundler = struct {
10471047

10481048
const basename = std.fs.path.basename(std.mem.span(destination));
10491049
const extname = std.fs.path.extension(basename);
1050-
javascript_bundle.import_from_name = if (bundler.options.platform == .bun)
1050+
javascript_bundle.import_from_name = if (bundler.options.platform.isBun())
10511051
"/node_modules.server.bun"
10521052
else
10531053
try std.fmt.allocPrint(
@@ -2406,20 +2406,21 @@ pub const Bundler = struct {
24062406
// or you're running in SSR
24072407
// or the file is a node_module
24082408
opts.features.hot_module_reloading = bundler.options.hot_module_reloading and
2409-
bundler.options.platform != .bun and
2409+
bundler.options.platform.isNotBun() and
24102410
(!opts.can_import_from_bundle or
24112411
(opts.can_import_from_bundle and !path.isNodeModule()));
24122412
opts.features.react_fast_refresh = opts.features.hot_module_reloading and
24132413
jsx.parse and
24142414
bundler.options.jsx.supports_fast_refresh;
24152415
opts.filepath_hash_for_hmr = file_hash orelse 0;
2416-
opts.warn_about_unbundled_modules = bundler.options.platform != .bun;
2416+
opts.warn_about_unbundled_modules = bundler.options.platform.isNotBun();
24172417

24182418
if (bundler.macro_context == null) {
24192419
bundler.macro_context = js_ast.Macro.MacroContext.init(bundler);
24202420
}
24212421

24222422
opts.macro_context = &bundler.macro_context.?;
2423+
opts.features.is_macro_runtime = bundler.options.platform == .bun_macro;
24232424

24242425
const value = (bundler.resolver.caches.js.parse(
24252426
allocator,

src/defines.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,10 +268,10 @@ pub const Define = struct {
268268
// Step 2. Swap in certain literal values because those can be constant folded
269269
define.identifiers.putAssumeCapacity("undefined", value_define);
270270
define.identifiers.putAssumeCapacity("NaN", DefineData{
271-
.value = js_ast.Expr.Data{ .e_number = &nan_val },
271+
.value = js_ast.Expr.Data{ .e_number = nan_val },
272272
});
273273
define.identifiers.putAssumeCapacity("Infinity", DefineData{
274-
.value = js_ast.Expr.Data{ .e_number = &inf_val },
274+
.value = js_ast.Expr.Data{ .e_number = inf_val },
275275
});
276276

277277
// Step 3. Load user data into hash tables

src/feature_flags.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,5 @@ pub const CSSInJSImportBehavior = enum {
6767
// having issues compiling WebKit with this enabled
6868
pub const remote_inspector = false;
6969
pub const auto_import_buffer = false;
70+
71+
pub const is_macro_enabled = env.isDebug;

src/javascript/jsc/base.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,6 +1539,7 @@ export fn MarkedArrayBuffer_deallocator(bytes_: *c_void, ctx_: *c_void) void {
15391539
pub fn castObj(obj: js.JSObjectRef, comptime Type: type) *Type {
15401540
return JSPrivateDataPtr.from(js.JSObjectGetPrivate(obj)).as(Type);
15411541
}
1542+
const JSExpr = @import("../../js_ast.zig").Macro.JSExpr;
15421543

15431544
pub const JSPrivateDataPtr = TaggedPointerUnion(.{
15441545
ResolveError,
@@ -1549,6 +1550,7 @@ pub const JSPrivateDataPtr = TaggedPointerUnion(.{
15491550
Headers,
15501551
Body,
15511552
Router,
1553+
JSExpr,
15521554
});
15531555

15541556
pub inline fn GetJSPrivateData(comptime Type: type, ref: js.JSObjectRef) ?*Type {

src/javascript/jsc/javascript.zig

Lines changed: 113 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ const Fs = @import("../../fs.zig");
44
const Resolver = @import("../../resolver/resolver.zig");
55
const ast = @import("../../import_record.zig");
66
const NodeModuleBundle = @import("../../node_module_bundle.zig").NodeModuleBundle;
7+
const MacroEntryPoint = @import("../../bundler.zig").MacroEntryPoint;
78
const logger = @import("../../logger.zig");
89
const Api = @import("../../api/schema.zig").Api;
910
const options = @import("../../options.zig");
1011
const Bundler = @import("../../bundler.zig").Bundler;
1112
const ServerEntryPoint = @import("../../bundler.zig").ServerEntryPoint;
1213
const js_printer = @import("../../js_printer.zig");
1314
const js_parser = @import("../../js_parser.zig");
15+
const js_ast = @import("../../js_ast.zig");
1416
const hash_map = @import("../../hash_map.zig");
1517
const http = @import("../../http.zig");
1618
const ImportKind = ast.ImportKind;
@@ -87,6 +89,41 @@ pub const Bun = struct {
8789
return css_imports_list_strings[0..tail];
8890
}
8991

92+
pub fn registerMacro(
93+
this: void,
94+
ctx: js.JSContextRef,
95+
function: js.JSObjectRef,
96+
thisObject: js.JSObjectRef,
97+
arguments: []const js.JSValueRef,
98+
exception: js.ExceptionRef,
99+
) js.JSValueRef {
100+
if (arguments.len != 2 or !js.JSValueIsNumber(ctx, arguments[0])) {
101+
JSError(getAllocator(ctx), "Internal error registering macros: invalid args", .{}, ctx, exception);
102+
return js.JSValueMakeUndefined(ctx);
103+
}
104+
// TODO: make this faster
105+
const id = @truncate(i32, @floatToInt(i64, js.JSValueToNumber(ctx, arguments[0], exception)));
106+
if (id == -1 or id == 0) {
107+
JSError(getAllocator(ctx), "Internal error registering macros: invalid id", .{}, ctx, exception);
108+
return js.JSValueMakeUndefined(ctx);
109+
}
110+
111+
if (!js.JSValueIsObject(ctx, arguments[1]) or !js.JSObjectIsFunction(ctx, arguments[1])) {
112+
JSError(getAllocator(ctx), "Macro must be a function. Received: {s}", .{@tagName(js.JSValueGetType(ctx, arguments[1]))}, ctx, exception);
113+
return js.JSValueMakeUndefined(ctx);
114+
}
115+
116+
var get_or_put_result = VirtualMachine.vm.macros.getOrPut(id) catch unreachable;
117+
if (get_or_put_result.found_existing) {
118+
js.JSValueUnprotect(ctx, get_or_put_result.value_ptr.*);
119+
}
120+
121+
js.JSValueProtect(ctx, arguments[1]);
122+
get_or_put_result.value_ptr.* = arguments[1];
123+
124+
return js.JSValueMakeUndefined(ctx);
125+
}
126+
90127
pub fn getCWD(
91128
this: void,
92129
ctx: js.JSContextRef,
@@ -403,6 +440,13 @@ pub const Bun = struct {
403440
.@"return" = "string",
404441
},
405442
},
443+
.registerMacro = .{
444+
.rfn = Bun.registerMacro,
445+
.ts = d.ts{
446+
.name = "registerMacro",
447+
.@"return" = "undefined",
448+
},
449+
},
406450
},
407451
.{
408452
.main = .{
@@ -462,8 +506,25 @@ pub const VirtualMachine = struct {
462506
transpiled_count: usize = 0,
463507
resolved_count: usize = 0,
464508
had_errors: bool = false,
465-
pub var vm_loaded = false;
466-
pub var vm: *VirtualMachine = undefined;
509+
510+
macros: MacroMap,
511+
macro_entry_points: std.AutoArrayHashMap(i32, *MacroEntryPoint),
512+
macro_mode: bool = false,
513+
514+
pub const MacroMap = std.AutoArrayHashMap(i32, js.JSObjectRef);
515+
516+
pub threadlocal var vm_loaded = false;
517+
pub threadlocal var vm: *VirtualMachine = undefined;
518+
519+
pub fn enableMacroMode(this: *VirtualMachine) void {
520+
this.bundler.options.platform = .bun_macro;
521+
this.macro_mode = true;
522+
}
523+
524+
pub fn disableMacroMode(this: *VirtualMachine) void {
525+
this.bundler.options.platform = .bun;
526+
this.macro_mode = false;
527+
}
467528

468529
pub fn init(
469530
allocator: *std.mem.Allocator,
@@ -502,6 +563,9 @@ pub const VirtualMachine = struct {
502563
.log = log,
503564
.flush_list = std.ArrayList(string).init(allocator),
504565
.blobs = try Blob.Group.init(allocator),
566+
567+
.macros = MacroMap.init(allocator),
568+
.macro_entry_points = @TypeOf(VirtualMachine.vm.macro_entry_points).init(allocator),
505569
};
506570

507571
VirtualMachine.vm.bundler.configureLinker();
@@ -771,10 +835,16 @@ pub const VirtualMachine = struct {
771835
ret.result = null;
772836
ret.path = vm.entry_point.source.path.text;
773837
return;
838+
} else if (specifier.len > js_ast.Macro.namespaceWithColon.len and strings.eqlComptimeIgnoreLen(specifier[0..js_ast.Macro.namespaceWithColon.len], js_ast.Macro.namespaceWithColon)) {
839+
ret.result = null;
840+
ret.path = specifier;
841+
return;
774842
}
775843

844+
const is_special_source = strings.eqlComptime(source, main_file_name) or js_ast.Macro.isMacroPath(source);
845+
776846
const result = try vm.bundler.resolver.resolve(
777-
if (!strings.eqlComptime(source, main_file_name)) Fs.PathName.init(source).dirWithTrailingSlash() else VirtualMachine.vm.bundler.fs.top_level_dir,
847+
if (!is_special_source) Fs.PathName.init(source).dirWithTrailingSlash() else VirtualMachine.vm.bundler.fs.top_level_dir,
778848
specifier,
779849
.stmt,
780850
);
@@ -1050,6 +1120,46 @@ pub const VirtualMachine = struct {
10501120
return promise;
10511121
}
10521122

1123+
pub fn loadMacroEntryPoint(this: *VirtualMachine, entry_path: string, function_name: string, specifier: string, hash: i32) !*JSInternalPromise {
1124+
var entry_point_entry = try this.macro_entry_points.getOrPut(hash);
1125+
1126+
if (!entry_point_entry.found_existing) {
1127+
var macro_entry_pointer: *MacroEntryPoint = this.allocator.create(MacroEntryPoint) catch unreachable;
1128+
entry_point_entry.value_ptr.* = macro_entry_pointer;
1129+
try macro_entry_pointer.generate(&this.bundler, Fs.PathName.init(entry_path), function_name, hash, specifier);
1130+
}
1131+
var entry_point = entry_point_entry.value_ptr.*;
1132+
1133+
var promise: *JSInternalPromise = undefined;
1134+
// We first import the node_modules bundle. This prevents any potential TDZ issues.
1135+
// The contents of the node_modules bundle are lazy, so hopefully this should be pretty quick.
1136+
if (this.node_modules != null) {
1137+
promise = JSModuleLoader.loadAndEvaluateModule(this.global, ZigString.init(std.mem.span(bun_file_import_path)));
1138+
1139+
this.global.vm().drainMicrotasks();
1140+
1141+
while (promise.status(this.global.vm()) == JSPromise.Status.Pending) {
1142+
this.global.vm().drainMicrotasks();
1143+
}
1144+
1145+
if (promise.status(this.global.vm()) == JSPromise.Status.Rejected) {
1146+
return promise;
1147+
}
1148+
1149+
_ = promise.result(this.global.vm());
1150+
}
1151+
1152+
promise = JSModuleLoader.loadAndEvaluateModule(this.global, ZigString.init(entry_point.source.path.text));
1153+
1154+
this.global.vm().drainMicrotasks();
1155+
1156+
while (promise.status(this.global.vm()) == JSPromise.Status.Pending) {
1157+
this.global.vm().drainMicrotasks();
1158+
}
1159+
1160+
return promise;
1161+
}
1162+
10531163
// 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.
10541164
// This is for:
10551165
// - BuildError

0 commit comments

Comments
 (0)