aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-09-25 00:32:17 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-09-25 14:16:05 -0700
commitff8393ce3264f1d40fc82aef428dbb8c766b2b6f (patch)
tree091d0a96e60ee00b3eb4b1e3dc57d0e53bf8aec7
parent8b209aecf96a1490825dca07c248e2e17a77a7ca (diff)
downloadbun-ff8393ce3264f1d40fc82aef428dbb8c766b2b6f.tar.gz
bun-ff8393ce3264f1d40fc82aef428dbb8c766b2b6f.tar.zst
bun-ff8393ce3264f1d40fc82aef428dbb8c766b2b6f.zip
WIP
-rw-r--r--src/ast/ast.js106
-rw-r--r--src/ast/ast.ts153
-rw-r--r--src/js_ast.zig499
3 files changed, 651 insertions, 107 deletions
diff --git a/src/ast/ast.js b/src/ast/ast.js
deleted file mode 100644
index 06be333c5..000000000
--- a/src/ast/ast.js
+++ /dev/null
@@ -1,106 +0,0 @@
-globalThis.BunASTNode ??= class BunASTNode {
- position = -1;
-};
-
-if (!globalThis.BunAST) {
- globalThis.BunAST = {
- EArray: class EArray extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EUnary: class EUnary extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EBinary: class EBinary extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EClass: class EClass extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- ENew: class ENew extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EFunction: class EFunction extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- ECall: class ECall extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EDot: class EDot extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EIndex: class EIndex extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EArrow: class EArrow extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EIdentifier: class EIdentifier extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EImportIdentifier: class EImportIdentifier extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EPrivateIdentifier: class EPrivateIdentifier extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EJsxElement: class EJsxElement extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EObject: class EObject extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- ESpread: class ESpread extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- ETemplatePart: class ETemplatePart extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- ETemplate: class ETemplate extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- ERegExp: class ERegExp extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EAwait: class EAwait extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EYield: class EYield extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EIf: class EIf extends BunASTNode {
- no = Number.MAX_SAFE_INTEGER;
- yes = Number.MAX_SAFE_INTEGER;
- },
- ERequire: class ERequire extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EImport: class EImport extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EBoolean: class EBoolean extends BunASTNode {
- val = false;
- },
- ENumber: class ENumber extends BunASTNode {
- val = 0;
- },
- EBigInt: class EBigInt extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EString: class EString extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EMissing: class EMissing extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EThis: class EThis extends BunASTNode {},
- ESuper: class ESuper extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- ENull: class ENull extends BunASTNode {},
- EUndefined: class EUndefined extends BunASTNode {},
- ENewTarget: class ENewTarget extends BunASTNode {
- #ptr = Number.MAX_SAFE_INTEGER;
- },
- EImportMeta: class EImportMeta extends BunASTNode {},
- };
-}
diff --git a/src/ast/ast.ts b/src/ast/ast.ts
new file mode 100644
index 000000000..2ab25644d
--- /dev/null
+++ b/src/ast/ast.ts
@@ -0,0 +1,153 @@
+class BunASTNode {
+ position = -1;
+}
+globalThis.BunASTNode = BunASTNode;
+// hint to JS engine to store it as a f64
+const NullPtrValue = Number.MAX_SAFE_INTEGER;
+const bindings = globalThis.BunASTBindings;
+
+const BunAST = {
+ EArray: class EArray extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EUnary: class EUnary extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EBinary: class EBinary extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EClass: class EClass extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ ENew: class ENew extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EFunction: class EFunction extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ ECall: class ECall extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EDot: class EDot extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EIndex: class EIndex extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EArrow: class EArrow extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EIdentifier: class EIdentifier extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EImportIdentifier: class EImportIdentifier extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EPrivateIdentifier: class EPrivateIdentifier extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EJsxElement: class EJsxElement extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EObject: class EObject extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ ESpread: class ESpread extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ ETemplatePart: class ETemplatePart extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ ETemplate: class ETemplate extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ ERegExp: class ERegExp extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EAwait: class EAwait extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EYield: class EYield extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EIf: class EIf extends BunASTNode {
+ no = NullPtrValue;
+ yes = NullPtrValue;
+ test = NullPtrValue;
+ },
+ ERequire: class ERequire extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EImport: class EImport extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EBoolean: class EBoolean extends BunASTNode {
+ val = false;
+ },
+ ENumber: class ENumber extends BunASTNode {
+ val = 0;
+ },
+ EBigInt: class EBigInt extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EString: class EString extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EMissing: class EMissing extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EThis: class EThis extends BunASTNode {},
+ ESuper: class ESuper extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ ENull: class ENull extends BunASTNode {},
+ EUndefined: class EUndefined extends BunASTNode {},
+ ENewTarget: class ENewTarget extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+ EImportMeta: class EImportMeta extends BunASTNode {},
+ SImport: class SImport extends BunASTNode {
+ #ptr = NullPtrValue;
+ },
+};
+globalThis.BunAST = BunAST;
+const bunTags = [
+ BunAST.EArray,
+ BunAST.EUnary,
+ BunAST.EBinary,
+ BunAST.EClass,
+ BunAST.ENew,
+ BunAST.EFunction,
+ BunAST.ECall,
+ BunAST.EDot,
+ BunAST.EIndex,
+ BunAST.EArrow,
+ BunAST.EIdentifier,
+ BunAST.EImportIdentifier,
+ BunAST.EPrivateIdentifier,
+ BunAST.EJsxElement,
+ BunAST.EObject,
+ BunAST.ESpread,
+ BunAST.ETemplatePart,
+ BunAST.ETemplate,
+ BunAST.ERegExp,
+ BunAST.EAwait,
+ BunAST.EYield,
+ BunAST.EIf,
+ BunAST.ERequire,
+ BunAST.EImport,
+ BunAST.EBoolean,
+ BunAST.ENumber,
+ BunAST.EBigInt,
+ BunAST.EString,
+ BunAST.EMissing,
+ BunAST.EThis,
+ BunAST.ESuper,
+ BunAST.ENull,
+ BunAST.EUndefined,
+ BunAST.ENewTarget,
+ BunAST.EImportMeta,
+ BunAST.SImport,
+];
+globalThis.bunTags = bunTags;
+
diff --git a/src/js_ast.zig b/src/js_ast.zig
index 3b077fd27..c2fafaf07 100644
--- a/src/js_ast.zig
+++ b/src/js_ast.zig
@@ -985,7 +985,7 @@ pub const E = struct {
/// lineNumber: number | null,
/// }```
/// - `children`:
- /// - static children? the function is React.jsxsDEV, "jsxs" instead of "jsx"
+ /// - static the function is React.jsxsDEV, "jsxs" instead of "jsx"
/// - one child? the function is React.jsxDEV,
/// - no children? the function is React.jsxDEV and children is an empty array.
/// `isStaticChildren`: https://github.com/facebook/react/blob/4ca62cac45c288878d2532e5056981d177f9fdac/packages/react/src/jsx/ReactJSXElementValidator.js#L369-L384
@@ -1061,6 +1061,8 @@ pub const E = struct {
utf8: string = &([_]u8{}),
prefer_template: bool = false,
+ pub var empty = String{};
+
pub fn clone(str: *const String, allocator: *std.mem.Allocator) !String {
if (str.isUTF8()) {
return String{
@@ -4204,8 +4206,15 @@ pub const Macro = struct {
}
};
+ pub const MacroResult = struct {
+ import_statements: []S.Import = &[_]S.Import{},
+ replacement: Expr,
+ };
+
pub const JSExpr = struct {
expr: Expr,
+ import_statements: []S.Import = &[_]S.Import{},
+
pub const Class = JSCBase.NewClass(
JSExpr,
.{
@@ -4236,6 +4245,476 @@ pub const Macro = struct {
},
);
+ pub const JSNode = struct {
+ loc: logger.Loc,
+ data: Data,
+
+ pub fn toExpr(this: JSNode) Expr {
+ switch (this.data) {
+ .e_array => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_array = value } };
+ },
+ .e_unary => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_unary = value } };
+ },
+ .e_binary => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_binary = value } };
+ },
+ .e_function => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_function = value } };
+ },
+ .e_new_target => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_new_target = value } };
+ },
+ .e_import_meta => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_import_meta = value } };
+ },
+ .e_call => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_call = value } };
+ },
+ .e_dot => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_dot = value } };
+ },
+ .e_index => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_index = value } };
+ },
+ .e_arrow => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_arrow = value } };
+ },
+ .e_identifier => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_identifier = value } };
+ },
+ .e_import_identifier => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_import_identifier = value } };
+ },
+ .e_private_identifier => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_private_identifier = value } };
+ },
+ .e_jsx_element => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_jsx_element = value } };
+ },
+ .e_big_int => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_big_int = value } };
+ },
+ .e_object => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_object = value } };
+ },
+ .e_spread => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_spread = value } };
+ },
+ .e_string => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_string = value } };
+ },
+ .e_template_part => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_template_part = value } };
+ },
+ .e_template => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_template = value } };
+ },
+ .e_reg_exp => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_reg_exp = value } };
+ },
+ .e_await => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_await = value } };
+ },
+ .e_yield => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_yield = value } };
+ },
+ .e_if => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_if = value } };
+ },
+ .e_require_or_require_resolve => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_require_or_require_resolve = value } };
+ },
+ .e_import => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_import = value } };
+ },
+ .e_this => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_this = value } };
+ },
+ .e_class => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_class = value } };
+ },
+ .e_require => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_require = value } };
+ },
+ .e_missing => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_missing = value } };
+ },
+ .e_boolean => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_boolean = value } };
+ },
+ .e_super => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_super = value } };
+ },
+ .e_null => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_null = value } };
+ },
+ .e_number => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_number = value } };
+ },
+ .e_undefined => |value| {
+ return Expr{ .loc = this.loc, .data = .{ .e_undefined = value } };
+ },
+ wip, .s_import => {
+ return Expr{ .loc = this.loc, .data = .{ .e_missing = .{} } };
+ },
+ }
+ }
+
+ pub const Data = union(Tag) {
+ e_array: *E.Array,
+ e_unary: *E.Unary,
+ e_binary: *E.Binary,
+ e_function: *E.Function,
+ e_new_target: *E.NewTarget,
+ e_import_meta: *E.ImportMeta,
+ e_call: *E.Call,
+ e_dot: *E.Dot,
+ e_index: *E.Index,
+ e_arrow: *E.Arrow,
+ e_identifier: *E.Identifier,
+ e_import_identifier: *E.ImportIdentifier,
+ e_private_identifier: *E.PrivateIdentifier,
+ e_jsx_element: *E.JsxElement,
+
+ e_big_int: *E.BigInt,
+ e_object: *E.Object,
+ e_spread: *E.Spread,
+ e_string: *E.String,
+ e_template_part: *E.TemplatePart,
+ e_template: *E.Template,
+ e_reg_exp: *E.RegExp,
+ e_await: *E.Await,
+ e_yield: *E.Yield,
+ e_if: *E.If,
+ e_require_or_require_resolve: *E.RequireOrRequireResolve,
+ e_import: *E.Import,
+ e_this: *E.This,
+ e_class: *E.Class,
+ e_require: *E.Require,
+
+ s_import: *S.Import,
+
+ e_missing: E.Missing,
+ e_boolean: E.Boolean,
+ e_super: E.Super,
+ e_null: E.Null,
+ e_number: E.Number,
+ e_undefined: E.Undefined,
+ };
+ pub const Tag = enum(u8) {
+ e_array,
+ e_unary,
+ e_binary,
+ e_boolean,
+ e_super,
+ e_null,
+ e_undefined,
+ e_function,
+ e_new_target,
+ e_import_meta,
+ e_call,
+ e_dot,
+ e_index,
+ e_arrow,
+ e_identifier,
+ e_import_identifier,
+ e_private_identifier,
+ e_jsx_element,
+ e_missing,
+ e_number,
+ e_big_int,
+ e_object,
+ e_spread,
+ e_string,
+ e_template_part,
+ e_template,
+ e_reg_exp,
+ e_await,
+ e_yield,
+ e_if,
+ e_require_or_require_resolve,
+ e_import,
+ e_this,
+ e_class,
+ e_require,
+ s_import,
+
+ wip,
+
+ pub const as_expr_tag: std.EnumArray(Tag, Expr.Tag) = brk: {
+ var list = std.EnumArray(Tag, Expr.Tag).initFill(Expr.Tag.e_missing);
+ list.set(Tag.e_array, Expr.Tag.e_array);
+ list.set(Tag.e_unary, Expr.Tag.e_unary);
+ list.set(Tag.e_binary, Expr.Tag.e_binary);
+ list.set(Tag.e_boolean, Expr.Tag.e_boolean);
+ list.set(Tag.e_super, Expr.Tag.e_super);
+ list.set(Tag.e_null, Expr.Tag.e_null);
+ list.set(Tag.e_undefined, Expr.Tag.e_undefined);
+ list.set(Tag.e_function, Expr.Tag.e_function);
+ list.set(Tag.e_new_target, Expr.Tag.e_new_target);
+ list.set(Tag.e_import_meta, Expr.Tag.e_import_meta);
+ list.set(Tag.e_call, Expr.Tag.e_call);
+ list.set(Tag.e_dot, Expr.Tag.e_dot);
+ list.set(Tag.e_index, Expr.Tag.e_index);
+ list.set(Tag.e_arrow, Expr.Tag.e_arrow);
+ list.set(Tag.e_identifier, Expr.Tag.e_identifier);
+ list.set(Tag.e_import_identifier, Expr.Tag.e_import_identifier);
+ list.set(Tag.e_private_identifier, Expr.Tag.e_private_identifier);
+ list.set(Tag.e_jsx_element, Expr.Tag.e_jsx_element);
+ list.set(Tag.e_missing, Expr.Tag.e_missing);
+ list.set(Tag.e_number, Expr.Tag.e_number);
+ list.set(Tag.e_big_int, Expr.Tag.e_big_int);
+ list.set(Tag.e_object, Expr.Tag.e_object);
+ list.set(Tag.e_spread, Expr.Tag.e_spread);
+ list.set(Tag.e_string, Expr.Tag.e_string);
+ list.set(Tag.e_template_part, Expr.Tag.e_template_part);
+ list.set(Tag.e_template, Expr.Tag.e_template);
+ list.set(Tag.e_reg_exp, Expr.Tag.e_reg_exp);
+ list.set(Tag.e_await, Expr.Tag.e_await);
+ list.set(Tag.e_yield, Expr.Tag.e_yield);
+ list.set(Tag.e_if, Expr.Tag.e_if);
+ list.set(Tag.e_require_or_require_resolve, Expr.Tag.e_require_or_require_resolve);
+ list.set(Tag.e_import, Expr.Tag.e_import);
+ list.set(Tag.e_this, Expr.Tag.e_this);
+ list.set(Tag.e_class, Expr.Tag.e_class);
+ list.set(Tag.e_require, Expr.Tag.e_require);
+ break :brk list;
+ };
+ };
+
+ pub const max_tag: u8 = brk: {
+ const Enum: std.builtin.TypeInfo.Enum = @typeInfo(Tag).Enum;
+ var max_value: u8 = 0;
+ for (Enum.fields) |field| {
+ max_value = std.math.max(@as(u8, field.value), max_value);
+ }
+ break :brk max_value;
+ };
+
+ pub const min_tag: u8 = brk: {
+ const Enum: std.builtin.TypeInfo.Enum = @typeInfo(Tag).Enum;
+ var min: u8 = 255;
+ for (Enum.fields) |field| {
+ min = std.math.min(@as(u8, field.value), min);
+ }
+ break :brk min;
+ };
+ };
+
+ pub const Writer = struct {
+ log: *logger.Log,
+ exception: JSCBase.ExceptionValueRef = null,
+ ctx: js.JSContextRef,
+ errored: bool = false,
+ allocator: *std.mem.Allocator,
+ loc: logger.Loc,
+
+ pub const TagOrJSNode = union(TagOrNodeType) {
+ tag: JSNode.Tag,
+ node: JSNode,
+ invalid: void,
+
+ pub const TagOrNodeType = enum {
+ tag,
+ node,
+ invalid,
+ };
+
+ pub fn fromJSValueRef(writer: *Writer, ctx: js.JSContextRef, value: js.JSValueRef) TagOrJSNode {
+ switch (js.JSValueGetType(ctx, value)) {
+ js.JSType.kJSTypeNumber => {
+ const tag_int = @floatToInt(u8, JSC.JSValue.fromRef(first_arg).asNumber());
+ if (tag_int < JSNode.min_tag or tag_int > JSNode.max_tag) {
+ throwTypeError(ctx, "Node type has invalid value", writer.exception);
+ writer.errored = true;
+ return TagOrJSNode{ .invalid = .{} };
+ }
+ return TagOrJSNode{ .tag = @intToEnum(JSNode.Tag, tag) };
+ },
+ js.JSType.kJSTypeObject => {
+ if (JSCBase.GetJSPrivateData(JSNode, value)) |node| {
+ return TagOrJSNode{ .node = node.* };
+ }
+
+ return TagOrJSNode{ .invalid = .{} };
+ },
+ else => {
+ throwTypeError(writer.ctx, "Invalid Bun AST", writer.exception);
+ return TagOrJSNode{ .invalid = .{} };
+ },
+ }
+ }
+ };
+
+ fn writeFromJSWithTagInExpr(writer: *Writer, tag: JSNode.Tag, expr: *Expr, args: []const js.JSValueRef) ?u32 {
+ switch (tag) {
+ e_array => {
+ var items = std.ArrayList(Expr).init(writer.allocator);
+ // var e_array: E.Array = E.Array{ .items = writer.allocator.alloc(E.Array, args.len) catch return false };
+ var i: u32 = 0;
+ while (i < args.len) {
+ switch (TagOrJSNode.fromJSValueRef(writer, writer.ctx, args[i])) {
+ TagOrJSNode.tag => |tag_| {
+ items.ensureUnusedCapacity(1) catch return null;
+ items.expandToCapacity();
+ i += 1;
+ i += writer.writeFromJSWithTagInExpr(tag_, &items[i], args[i..]) orelse return null;
+ },
+ TagOrJSNode.node => |node_| {
+ const node: JSNode = node_;
+ switch (node.data) {
+ JSNode.Tag.s_import => |import| {
+ return null;
+ },
+ else => {
+ items.append(node.toExpr()) catch return null;
+ i += 1;
+ },
+ }
+ },
+ TagOrJSNode.invalid => {
+ return null;
+ },
+ }
+ }
+ expr.* = Expr.alloc(writer.allocator, E.Array, E.Array{ .items = items.items }, writer.loc);
+ return i;
+ },
+ e_boolean => {
+ expr.* = Expr{ .loc = writer.loc, .data = .{ .e_boolean = JSC.JSValue.toBoolean(JSValue.fromRef(args[0])) } };
+ return 1;
+ },
+ e_null => {
+ expr.* = Expr{ .loc = writer.loc, .data = .{ .e_null = E.Null{} } };
+ return 0;
+ },
+ e_undefined => {
+ expr.* = Expr{ .loc = writer.loc, .data = .{ .e_null = E.Undefined{} } };
+ return 0;
+ },
+ e_number => {
+ expr.* = Expr{ .loc = writer.loc, .data = .{ .e_number = JSC.JSValue.asNumber(JSValue.fromRef(args[0])) } };
+ return 1;
+ },
+ e_string => {
+ var wtf_string = JSC.JSValue.toWTFString(JSValue.fromRef(args[0]), JavaScript.VirtualMachine.vm.global);
+ if (wtf_string.isEmpty()) {
+ expr.* = Expr{
+ .loc = writer.loc,
+ .data = .{
+ .e_string = &E.String.empty,
+ },
+ };
+ } else if (wtf_string.is8Bit()) {
+ expr.* = Expr.alloc(writer.allocator, E.String, E.String{ .utf8 = wtf_string.characters8()[0..wtf_string.length()] }, writer.loc);
+ } else if (wtf_string.is16Bit()) {
+ expr.* = Expr.alloc(writer.allocator, E.String, E.String{ .value = wtf_string.characters16()[0..wtf_string.length()] }, writer.loc);
+ } else {
+ unreachable;
+ }
+ return 1;
+ },
+ e_reg_exp => {
+ var jsstring = js.JSValueToStringCopy(writer.ctx, args[0], writer.exception);
+ const len = js.JSStringGetLength(jsstring);
+ var str = try writer.allocator.alloc(u8, len + 1);
+ const outlen = js.JSStringGetUTF8CString(jsstring, str, len + 1);
+ expr.* = Expr.alloc(writer.allocator, E.RegExp, E.RegExp{ .value = str[0..outlen] }, writer.loc);
+ return 1;
+ },
+ e_object => {
+ var i: u32 = 0;
+
+ const len = @truncate(u16, JSC.JSValue.fromRef(args[0]).toInt32());
+ },
+
+ e_call => {},
+
+ e_dot => {},
+ e_index => {},
+ e_identifier => {},
+ e_import_identifier => {},
+
+ e_big_int => {},
+ e_object => {},
+ e_spread => {},
+
+ e_template_part => {},
+ e_template => {},
+
+ e_await => {},
+ e_yield => {},
+ e_if => {},
+ e_import => {},
+ e_this => {},
+ e_class => {},
+ s_import => {},
+ }
+ }
+
+ fn writeFromJSWithTag(writer: *Writer, tag: JSNode.Tag, node: *JSNode, args: []const js.JSValueRef) bool {
+ switch (tag) {
+ e_array => {
+ var e_array: E.Array = E.Array{ .items = writer.allocator.alloc(E.Array, args.len) catch return false };
+
+ var i: u32 = 0;
+ while (i < args.len) : (i += 1) {}
+ },
+ e_boolean => {},
+ e_null => {},
+ e_undefined => {},
+ e_call => {},
+ e_dot => {},
+ e_index => {},
+ e_identifier => {},
+ e_import_identifier => {},
+ e_number => {},
+ e_big_int => {},
+ e_object => {},
+ e_spread => {},
+ e_string => {},
+ e_template_part => {},
+ e_template => {},
+ e_reg_exp => {},
+ e_await => {},
+ e_yield => {},
+ e_if => {},
+ e_import => {},
+ e_this => {},
+ e_class => {},
+ s_import => {},
+ }
+ }
+
+ pub fn writeFromJS(writer: *Writer, node: *JSNode, args: []const js.JSValueRef) bool {
+ if (writer.errored) return false;
+ const first_arg = args[0];
+
+ switch (js.JSValueGetType(ctx, first_arg)) {
+ js.JSType.kJSTypeNumber => {
+ const value = @floatToInt(u8, JSC.JSValue.fromRef(first_arg).asNumber());
+ const tag = std.meta.intToEnum(JSNode.Tag, value) catch {
+ throwTypeError(ctx, "Node type has invalid value", writer.exception);
+ writer.errored = true;
+ return false;
+ };
+ if (writer.writeFromJSWithTag(writer, tag, node, args[1..])) {
+ return true;
+ }
+
+ return false;
+ },
+ js.JSType.kJSTypeObject => {},
+ else => {
+ throwTypeError(writer.ctx, "Invalid Bun AST", writer.exception);
+ return false;
+ },
+ }
+ }
+ };
+
// pub fn isInstanceOf(
// ctx: js.JSContextRef,
// obj: js.JSObjectRef,
@@ -4245,6 +4724,24 @@ pub const Macro = struct {
// js.JSValueToNumber(ctx, value, exception);
// }
+ fn throwTypeError(ctx: js.JSContextRef, comptime msg: string, exception: js.ExceptionRef) void {
+ JSCBase.JSError(JSCBase.getAllocator(ctx), msg, .{}, ctx, exception);
+ }
+
+ pub fn createFromJavaScript(
+ this: *JSExpr,
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
+ arguments: []const js.JSValueRef,
+ exception: js.ExceptionRef,
+ ) js.JSObjectRef {
+ if (arguments.len != 3 or !js.JSValueIsNumber(ctx, arguments[0]) or !js.JSValueIsObject(ctx, arguments[1]) or !js.JSValueIsArray(ctx, arguments[2])) {
+ this.throwTypeError(ctx, "Invalid arguments for JSExpr", exception);
+ return null;
+ }
+ }
+
pub fn toString(
this: *JSExpr,
ctx: js.JSContextRef,