diff options
author | 2021-09-25 00:32:17 -0700 | |
---|---|---|
committer | 2021-09-25 14:16:05 -0700 | |
commit | ff8393ce3264f1d40fc82aef428dbb8c766b2b6f (patch) | |
tree | 091d0a96e60ee00b3eb4b1e3dc57d0e53bf8aec7 | |
parent | 8b209aecf96a1490825dca07c248e2e17a77a7ca (diff) | |
download | bun-ff8393ce3264f1d40fc82aef428dbb8c766b2b6f.tar.gz bun-ff8393ce3264f1d40fc82aef428dbb8c766b2b6f.tar.zst bun-ff8393ce3264f1d40fc82aef428dbb8c766b2b6f.zip |
WIP
-rw-r--r-- | src/ast/ast.js | 106 | ||||
-rw-r--r-- | src/ast/ast.ts | 153 | ||||
-rw-r--r-- | src/js_ast.zig | 499 |
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, |