aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-06-24 22:55:42 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-06-24 22:55:42 -0700
commit3a95a74b7feadb59a215ff06446ccebff4a4008e (patch)
tree81fda0b8e3d27689edf75534238ea1a5ca102377
parentc3f9d77391589b65951616a632af87107fba469f (diff)
downloadbun-3a95a74b7feadb59a215ff06446ccebff4a4008e.tar.gz
bun-3a95a74b7feadb59a215ff06446ccebff4a4008e.tar.zst
bun-3a95a74b7feadb59a215ff06446ccebff4a4008e.zip
I like this direction
-rw-r--r--build.zig1
-rw-r--r--src/javascript/jsc/JavascriptCore.zig238
-rw-r--r--src/javascript/jsc/javascript.zig534
-rw-r--r--src/js_lexer.zig29
-rw-r--r--src/js_parser/js_parser.zig1
-rw-r--r--src/options.zig5
-rw-r--r--src/runtime.footer.js10
-rw-r--r--src/runtime.version2
-rw-r--r--src/string_immutable.zig11
-rw-r--r--src/wtf_string_mutable.zig243
10 files changed, 1047 insertions, 27 deletions
diff --git a/build.zig b/build.zig
index c603a8006..9814ad4fd 100644
--- a/build.zig
+++ b/build.zig
@@ -27,6 +27,7 @@ pub fn build(b: *std.build.Builder) void {
var cwd_buf = [_]u8{0} ** 4096;
var cwd = std.os.getcwd(&cwd_buf) catch unreachable;
var exe: *std.build.LibExeObjStep = undefined;
+ var javascript: *std.build.LibExeObjStep = undefined;
var output_dir_buf = std.mem.zeroes([4096]u8);
var bin_label = if (mode == std.builtin.Mode.Debug) "/debug/" else "/";
diff --git a/src/javascript/jsc/JavascriptCore.zig b/src/javascript/jsc/JavascriptCore.zig
new file mode 100644
index 000000000..1d5806fce
--- /dev/null
+++ b/src/javascript/jsc/JavascriptCore.zig
@@ -0,0 +1,238 @@
+pub const struct_OpaqueJSContextGroup = opaque {};
+pub const JSContextGroupRef = ?*const struct_OpaqueJSContextGroup;
+pub const struct_OpaqueJSContext = opaque {};
+pub const JSContextRef = ?*const struct_OpaqueJSContext;
+pub const JSGlobalContextRef = ?*struct_OpaqueJSContext;
+pub const struct_OpaqueJSString = opaque {};
+pub const JSStringRef = ?*struct_OpaqueJSString;
+pub const struct_OpaqueJSClass = opaque {};
+pub const JSClassRef = ?*struct_OpaqueJSClass;
+pub const struct_OpaqueJSPropertyNameArray = opaque {};
+pub const JSPropertyNameArrayRef = ?*struct_OpaqueJSPropertyNameArray;
+pub const struct_OpaqueJSPropertyNameAccumulator = opaque {};
+pub const JSPropertyNameAccumulatorRef = ?*struct_OpaqueJSPropertyNameAccumulator;
+pub const JSTypedArrayBytesDeallocator = ?fn (?*c_void, ?*c_void) callconv(.C) void;
+pub const struct_OpaqueJSValue = opaque {};
+pub const JSValueRef = ?*const struct_OpaqueJSValue;
+pub const JSObjectRef = ?*struct_OpaqueJSValue;
+pub extern fn JSEvaluateScript(ctx: JSContextRef, script: JSStringRef, thisObject: JSObjectRef, sourceURL: JSStringRef, startingLineNumber: c_int, exception: [*c]JSValueRef) JSValueRef;
+pub extern fn JSCheckScriptSyntax(ctx: JSContextRef, script: JSStringRef, sourceURL: JSStringRef, startingLineNumber: c_int, exception: [*c]JSValueRef) bool;
+pub extern fn JSGarbageCollect(ctx: JSContextRef) void;
+pub const JSType = enum(c_uint) {
+ kJSTypeUndefined,
+ kJSTypeNull,
+ kJSTypeBoolean,
+ kJSTypeNumber,
+ kJSTypeString,
+ kJSTypeObject,
+ kJSTypeSymbol,
+ _,
+};
+pub const kJSTypeUndefined = @enumToInt(JSType.kJSTypeUndefined);
+pub const kJSTypeNull = @enumToInt(JSType.kJSTypeNull);
+pub const kJSTypeBoolean = @enumToInt(JSType.kJSTypeBoolean);
+pub const kJSTypeNumber = @enumToInt(JSType.kJSTypeNumber);
+pub const kJSTypeString = @enumToInt(JSType.kJSTypeString);
+pub const kJSTypeObject = @enumToInt(JSType.kJSTypeObject);
+pub const kJSTypeSymbol = @enumToInt(JSType.kJSTypeSymbol);
+pub const JSTypedArrayType = enum(c_uint) {
+ kJSTypedArrayTypeInt8Array,
+ kJSTypedArrayTypeInt16Array,
+ kJSTypedArrayTypeInt32Array,
+ kJSTypedArrayTypeUint8Array,
+ kJSTypedArrayTypeUint8ClampedArray,
+ kJSTypedArrayTypeUint16Array,
+ kJSTypedArrayTypeUint32Array,
+ kJSTypedArrayTypeFloat32Array,
+ kJSTypedArrayTypeFloat64Array,
+ kJSTypedArrayTypeArrayBuffer,
+ kJSTypedArrayTypeNone,
+ _,
+};
+pub const kJSTypedArrayTypeInt8Array = @enumToInt(JSTypedArrayType.kJSTypedArrayTypeInt8Array);
+pub const kJSTypedArrayTypeInt16Array = @enumToInt(JSTypedArrayType.kJSTypedArrayTypeInt16Array);
+pub const kJSTypedArrayTypeInt32Array = @enumToInt(JSTypedArrayType.kJSTypedArrayTypeInt32Array);
+pub const kJSTypedArrayTypeUint8Array = @enumToInt(JSTypedArrayType.kJSTypedArrayTypeUint8Array);
+pub const kJSTypedArrayTypeUint8ClampedArray = @enumToInt(JSTypedArrayType.kJSTypedArrayTypeUint8ClampedArray);
+pub const kJSTypedArrayTypeUint16Array = @enumToInt(JSTypedArrayType.kJSTypedArrayTypeUint16Array);
+pub const kJSTypedArrayTypeUint32Array = @enumToInt(JSTypedArrayType.kJSTypedArrayTypeUint32Array);
+pub const kJSTypedArrayTypeFloat32Array = @enumToInt(JSTypedArrayType.kJSTypedArrayTypeFloat32Array);
+pub const kJSTypedArrayTypeFloat64Array = @enumToInt(JSTypedArrayType.kJSTypedArrayTypeFloat64Array);
+pub const kJSTypedArrayTypeArrayBuffer = @enumToInt(JSTypedArrayType.kJSTypedArrayTypeArrayBuffer);
+pub const kJSTypedArrayTypeNone = @enumToInt(JSTypedArrayType.kJSTypedArrayTypeNone);
+pub extern fn JSValueGetType(ctx: JSContextRef, value: JSValueRef) JSType;
+pub extern fn JSValueIsUndefined(ctx: JSContextRef, value: JSValueRef) bool;
+pub extern fn JSValueIsNull(ctx: JSContextRef, value: JSValueRef) bool;
+pub extern fn JSValueIsBoolean(ctx: JSContextRef, value: JSValueRef) bool;
+pub extern fn JSValueIsNumber(ctx: JSContextRef, value: JSValueRef) bool;
+pub extern fn JSValueIsString(ctx: JSContextRef, value: JSValueRef) bool;
+pub extern fn JSValueIsSymbol(ctx: JSContextRef, value: JSValueRef) bool;
+pub extern fn JSValueIsObject(ctx: JSContextRef, value: JSValueRef) bool;
+pub extern fn JSValueIsObjectOfClass(ctx: JSContextRef, value: JSValueRef, jsClass: JSClassRef) bool;
+pub extern fn JSValueIsArray(ctx: JSContextRef, value: JSValueRef) bool;
+pub extern fn JSValueIsDate(ctx: JSContextRef, value: JSValueRef) bool;
+pub extern fn JSValueGetTypedArrayType(ctx: JSContextRef, value: JSValueRef, exception: [*c]JSValueRef) JSTypedArrayType;
+pub extern fn JSValueIsEqual(ctx: JSContextRef, a: JSValueRef, b: JSValueRef, exception: [*c]JSValueRef) bool;
+pub extern fn JSValueIsStrictEqual(ctx: JSContextRef, a: JSValueRef, b: JSValueRef) bool;
+pub extern fn JSValueIsInstanceOfConstructor(ctx: JSContextRef, value: JSValueRef, constructor: JSObjectRef, exception: [*c]JSValueRef) bool;
+pub extern fn JSValueMakeUndefined(ctx: JSContextRef) JSValueRef;
+pub extern fn JSValueMakeNull(ctx: JSContextRef) JSValueRef;
+pub extern fn JSValueMakeBoolean(ctx: JSContextRef, boolean: bool) JSValueRef;
+pub extern fn JSValueMakeNumber(ctx: JSContextRef, number: f64) JSValueRef;
+pub extern fn JSValueMakeString(ctx: JSContextRef, string: JSStringRef) JSValueRef;
+pub extern fn JSValueMakeSymbol(ctx: JSContextRef, description: JSStringRef) JSValueRef;
+pub extern fn JSValueMakeFromJSONString(ctx: JSContextRef, string: JSStringRef) JSValueRef;
+pub extern fn JSValueCreateJSONString(ctx: JSContextRef, value: JSValueRef, indent: c_uint, exception: [*c]JSValueRef) JSStringRef;
+pub extern fn JSValueToBoolean(ctx: JSContextRef, value: JSValueRef) bool;
+pub extern fn JSValueToNumber(ctx: JSContextRef, value: JSValueRef, exception: [*c]JSValueRef) f64;
+pub extern fn JSValueToStringCopy(ctx: JSContextRef, value: JSValueRef, exception: [*c]JSValueRef) JSStringRef;
+pub extern fn JSValueToObject(ctx: JSContextRef, value: JSValueRef, exception: [*c]JSValueRef) JSObjectRef;
+pub extern fn JSValueProtect(ctx: JSContextRef, value: JSValueRef) void;
+pub extern fn JSValueUnprotect(ctx: JSContextRef, value: JSValueRef) void;
+pub const JSPropertyAttributes = enum(c_uint) {
+ kJSPropertyAttributeNone = 0,
+ kJSPropertyAttributeReadOnly = 2,
+ kJSPropertyAttributeDontEnum = 4,
+ kJSPropertyAttributeDontDelete = 8,
+ _,
+};
+pub const kJSPropertyAttributeNone = @enumToInt(JSPropertyAttributes.kJSPropertyAttributeNone);
+pub const kJSPropertyAttributeReadOnly = @enumToInt(JSPropertyAttributes.kJSPropertyAttributeReadOnly);
+pub const kJSPropertyAttributeDontEnum = @enumToInt(JSPropertyAttributes.kJSPropertyAttributeDontEnum);
+pub const kJSPropertyAttributeDontDelete = @enumToInt(JSPropertyAttributes.kJSPropertyAttributeDontDelete);
+pub const JSClassAttributes = enum(c_uint) {
+ kJSClassAttributeNone = 0,
+ kJSClassAttributeNoAutomaticPrototype = 2,
+ _,
+};
+
+pub const kJSClassAttributeNone = @enumToInt(JSClassAttributes.kJSClassAttributeNone);
+pub const kJSClassAttributeNoAutomaticPrototype = @enumToInt(JSClassAttributes.kJSClassAttributeNoAutomaticPrototype);
+pub const JSObjectInitializeCallback = ?fn (JSContextRef, JSObjectRef) callconv(.C) void;
+pub const JSObjectFinalizeCallback = ?fn (JSObjectRef) callconv(.C) void;
+pub const JSObjectHasPropertyCallback = ?fn (JSContextRef, JSObjectRef, JSStringRef) callconv(.C) bool;
+pub const JSObjectGetPropertyCallback = ?fn (JSContextRef, JSObjectRef, JSStringRef, [*c]JSValueRef) callconv(.C) JSValueRef;
+pub const JSObjectSetPropertyCallback = ?fn (JSContextRef, JSObjectRef, JSStringRef, JSValueRef, [*c]JSValueRef) callconv(.C) bool;
+pub const JSObjectDeletePropertyCallback = ?fn (JSContextRef, JSObjectRef, JSStringRef, [*c]JSValueRef) callconv(.C) bool;
+pub const JSObjectGetPropertyNamesCallback = ?fn (JSContextRef, JSObjectRef, JSPropertyNameAccumulatorRef) callconv(.C) void;
+pub const JSObjectCallAsFunctionCallback = ?fn (ctx: JSContextRef, function: JSObjectRef, thisObject: JSObjectRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: [*c]JSValueRef) callconv(.C) JSValueRef;
+pub const JSObjectCallAsConstructorCallback = ?fn (JSContextRef, JSObjectRef, usize, [*c]const JSValueRef, [*c]JSValueRef) callconv(.C) JSObjectRef;
+pub const JSObjectHasInstanceCallback = ?fn (JSContextRef, JSObjectRef, JSValueRef, [*c]JSValueRef) callconv(.C) bool;
+pub const JSObjectConvertToTypeCallback = ?fn (JSContextRef, JSObjectRef, JSType, [*c]JSValueRef) callconv(.C) JSValueRef;
+pub const JSStaticValue = extern struct {
+ name: [*c]const u8,
+ getProperty: JSObjectGetPropertyCallback,
+ setProperty: JSObjectSetPropertyCallback,
+ attributes: JSPropertyAttributes,
+};
+pub const JSStaticFunction = extern struct {
+ name: [*c]const u8,
+ callAsFunction: JSObjectCallAsFunctionCallback,
+ attributes: JSPropertyAttributes,
+};
+pub const JSClassDefinition = extern struct {
+ version: c_int,
+ attributes: JSClassAttributes,
+ className: [*c]const u8,
+ parentClass: JSClassRef,
+ staticValues: [*c]const JSStaticValue,
+ staticFunctions: [*c]const JSStaticFunction,
+ initialize: JSObjectInitializeCallback,
+ finalize: JSObjectFinalizeCallback,
+ hasProperty: JSObjectHasPropertyCallback,
+ getProperty: JSObjectGetPropertyCallback,
+ setProperty: JSObjectSetPropertyCallback,
+ deleteProperty: JSObjectDeletePropertyCallback,
+ getPropertyNames: JSObjectGetPropertyNamesCallback,
+ callAsFunction: JSObjectCallAsFunctionCallback,
+ callAsConstructor: JSObjectCallAsConstructorCallback,
+ hasInstance: JSObjectHasInstanceCallback,
+ convertToType: JSObjectConvertToTypeCallback,
+};
+pub extern const kJSClassDefinitionEmpty: JSClassDefinition;
+pub extern fn JSClassCreate(definition: [*c]const JSClassDefinition) JSClassRef;
+pub extern fn JSClassRetain(jsClass: JSClassRef) JSClassRef;
+pub extern fn JSClassRelease(jsClass: JSClassRef) void;
+pub extern fn JSObjectMake(ctx: JSContextRef, jsClass: JSClassRef, data: ?*c_void) JSObjectRef;
+pub extern fn JSObjectMakeFunctionWithCallback(ctx: JSContextRef, name: JSStringRef, callAsFunction: JSObjectCallAsFunctionCallback) JSObjectRef;
+pub extern fn JSObjectMakeConstructor(ctx: JSContextRef, jsClass: JSClassRef, callAsConstructor: JSObjectCallAsConstructorCallback) JSObjectRef;
+pub extern fn JSObjectMakeArray(ctx: JSContextRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: [*c]JSValueRef) JSObjectRef;
+pub extern fn JSObjectMakeDate(ctx: JSContextRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: [*c]JSValueRef) JSObjectRef;
+pub extern fn JSObjectMakeError(ctx: JSContextRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: [*c]JSValueRef) JSObjectRef;
+pub extern fn JSObjectMakeRegExp(ctx: JSContextRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: [*c]JSValueRef) JSObjectRef;
+pub extern fn JSObjectMakeDeferredPromise(ctx: JSContextRef, resolve: [*c]JSObjectRef, reject: [*c]JSObjectRef, exception: [*c]JSValueRef) JSObjectRef;
+pub extern fn JSObjectMakeFunction(ctx: JSContextRef, name: JSStringRef, parameterCount: c_uint, parameterNames: [*c]const JSStringRef, body: JSStringRef, sourceURL: JSStringRef, startingLineNumber: c_int, exception: [*c]JSValueRef) JSObjectRef;
+pub extern fn JSObjectGetPrototype(ctx: JSContextRef, object: JSObjectRef) JSValueRef;
+pub extern fn JSObjectSetPrototype(ctx: JSContextRef, object: JSObjectRef, value: JSValueRef) void;
+pub extern fn JSObjectHasProperty(ctx: JSContextRef, object: JSObjectRef, propertyName: JSStringRef) bool;
+pub extern fn JSObjectGetProperty(ctx: JSContextRef, object: JSObjectRef, propertyName: JSStringRef, exception: [*c]JSValueRef) JSValueRef;
+pub extern fn JSObjectSetProperty(ctx: JSContextRef, object: JSObjectRef, propertyName: JSStringRef, value: JSValueRef, attributes: JSPropertyAttributes, exception: [*c]JSValueRef) void;
+pub extern fn JSObjectDeleteProperty(ctx: JSContextRef, object: JSObjectRef, propertyName: JSStringRef, exception: [*c]JSValueRef) bool;
+pub extern fn JSObjectHasPropertyForKey(ctx: JSContextRef, object: JSObjectRef, propertyKey: JSValueRef, exception: [*c]JSValueRef) bool;
+pub extern fn JSObjectGetPropertyForKey(ctx: JSContextRef, object: JSObjectRef, propertyKey: JSValueRef, exception: [*c]JSValueRef) JSValueRef;
+pub extern fn JSObjectSetPropertyForKey(ctx: JSContextRef, object: JSObjectRef, propertyKey: JSValueRef, value: JSValueRef, attributes: JSPropertyAttributes, exception: [*c]JSValueRef) void;
+pub extern fn JSObjectDeletePropertyForKey(ctx: JSContextRef, object: JSObjectRef, propertyKey: JSValueRef, exception: [*c]JSValueRef) bool;
+pub extern fn JSObjectGetPropertyAtIndex(ctx: JSContextRef, object: JSObjectRef, propertyIndex: c_uint, exception: [*c]JSValueRef) JSValueRef;
+pub extern fn JSObjectSetPropertyAtIndex(ctx: JSContextRef, object: JSObjectRef, propertyIndex: c_uint, value: JSValueRef, exception: [*c]JSValueRef) void;
+pub extern fn JSObjectGetPrivate(object: JSObjectRef) ?*c_void;
+pub extern fn JSObjectSetPrivate(object: JSObjectRef, data: ?*c_void) bool;
+pub extern fn JSObjectIsFunction(ctx: JSContextRef, object: JSObjectRef) bool;
+pub extern fn JSObjectCallAsFunction(ctx: JSContextRef, object: JSObjectRef, thisObject: JSObjectRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: [*c]JSValueRef) JSValueRef;
+pub extern fn JSObjectIsConstructor(ctx: JSContextRef, object: JSObjectRef) bool;
+pub extern fn JSObjectCallAsConstructor(ctx: JSContextRef, object: JSObjectRef, argumentCount: usize, arguments: [*c]const JSValueRef, exception: [*c]JSValueRef) JSObjectRef;
+pub extern fn JSObjectCopyPropertyNames(ctx: JSContextRef, object: JSObjectRef) JSPropertyNameArrayRef;
+pub extern fn JSPropertyNameArrayRetain(array: JSPropertyNameArrayRef) JSPropertyNameArrayRef;
+pub extern fn JSPropertyNameArrayRelease(array: JSPropertyNameArrayRef) void;
+pub extern fn JSPropertyNameArrayGetCount(array: JSPropertyNameArrayRef) usize;
+pub extern fn JSPropertyNameArrayGetNameAtIndex(array: JSPropertyNameArrayRef, index: usize) JSStringRef;
+pub extern fn JSPropertyNameAccumulatorAddName(accumulator: JSPropertyNameAccumulatorRef, propertyName: JSStringRef) void;
+pub extern fn JSContextGroupCreate() JSContextGroupRef;
+pub extern fn JSContextGroupRetain(group: JSContextGroupRef) JSContextGroupRef;
+pub extern fn JSContextGroupRelease(group: JSContextGroupRef) void;
+pub extern fn JSGlobalContextCreate(globalObjectClass: JSClassRef) JSGlobalContextRef;
+pub extern fn JSGlobalContextCreateInGroup(group: JSContextGroupRef, globalObjectClass: JSClassRef) JSGlobalContextRef;
+pub extern fn JSGlobalContextRetain(ctx: JSGlobalContextRef) JSGlobalContextRef;
+pub extern fn JSGlobalContextRelease(ctx: JSGlobalContextRef) void;
+pub extern fn JSContextGetGlobalObject(ctx: JSContextRef) JSObjectRef;
+pub extern fn JSContextGetGroup(ctx: JSContextRef) JSContextGroupRef;
+pub extern fn JSContextGetGlobalContext(ctx: JSContextRef) JSGlobalContextRef;
+pub extern fn JSGlobalContextCopyName(ctx: JSGlobalContextRef) JSStringRef;
+pub extern fn JSGlobalContextSetName(ctx: JSGlobalContextRef, name: JSStringRef) void;
+pub const JSChar = c_ushort;
+pub extern fn JSStringCreateWithCharacters(chars: [*c]const JSChar, numChars: usize) JSStringRef;
+pub extern fn JSStringCreateWithUTF8CString(string: [*c]const u8) JSStringRef;
+pub extern fn JSStringRetain(string: JSStringRef) JSStringRef;
+pub extern fn JSStringRelease(string: JSStringRef) void;
+pub extern fn JSStringGetLength(string: JSStringRef) usize;
+pub extern fn JSStringGetCharactersPtr(string: JSStringRef) [*c]const JSChar;
+pub extern fn JSStringGetMaximumUTF8CStringSize(string: JSStringRef) usize;
+pub extern fn JSStringGetUTF8CString(string: JSStringRef, buffer: [*c]u8, bufferSize: usize) usize;
+pub extern fn JSStringIsEqual(a: JSStringRef, b: JSStringRef) bool;
+pub extern fn JSStringIsEqualToUTF8CString(a: JSStringRef, b: [*c]const u8) bool;
+pub extern fn JSObjectMakeTypedArray(ctx: JSContextRef, arrayType: JSTypedArrayType, length: usize, exception: [*c]JSValueRef) JSObjectRef;
+pub extern fn JSObjectMakeTypedArrayWithBytesNoCopy(ctx: JSContextRef, arrayType: JSTypedArrayType, bytes: ?*c_void, byteLength: usize, bytesDeallocator: JSTypedArrayBytesDeallocator, deallocatorContext: ?*c_void, exception: [*c]JSValueRef) JSObjectRef;
+pub extern fn JSObjectMakeTypedArrayWithArrayBuffer(ctx: JSContextRef, arrayType: JSTypedArrayType, buffer: JSObjectRef, exception: [*c]JSValueRef) JSObjectRef;
+pub extern fn JSObjectMakeTypedArrayWithArrayBufferAndOffset(ctx: JSContextRef, arrayType: JSTypedArrayType, buffer: JSObjectRef, byteOffset: usize, length: usize, exception: [*c]JSValueRef) JSObjectRef;
+pub extern fn JSObjectGetTypedArrayBytesPtr(ctx: JSContextRef, object: JSObjectRef, exception: [*c]JSValueRef) ?*c_void;
+pub extern fn JSObjectGetTypedArrayLength(ctx: JSContextRef, object: JSObjectRef, exception: [*c]JSValueRef) usize;
+pub extern fn JSObjectGetTypedArrayByteLength(ctx: JSContextRef, object: JSObjectRef, exception: [*c]JSValueRef) usize;
+pub extern fn JSObjectGetTypedArrayByteOffset(ctx: JSContextRef, object: JSObjectRef, exception: [*c]JSValueRef) usize;
+pub extern fn JSObjectGetTypedArrayBuffer(ctx: JSContextRef, object: JSObjectRef, exception: [*c]JSValueRef) JSObjectRef;
+pub extern fn JSObjectMakeArrayBufferWithBytesNoCopy(ctx: JSContextRef, bytes: ?*c_void, byteLength: usize, bytesDeallocator: JSTypedArrayBytesDeallocator, deallocatorContext: ?*c_void, exception: [*c]JSValueRef) JSObjectRef;
+pub extern fn JSObjectGetArrayBufferBytesPtr(ctx: JSContextRef, object: JSObjectRef, exception: [*c]JSValueRef) ?*c_void;
+pub extern fn JSObjectGetArrayBufferByteLength(ctx: JSContextRef, object: JSObjectRef, exception: [*c]JSValueRef) usize;
+pub extern fn JSStringCreateWithCFString(string: CFStringRef) JSStringRef;
+pub const OpaqueJSContextGroup = struct_OpaqueJSContextGroup;
+pub const OpaqueJSContext = struct_OpaqueJSContext;
+pub const OpaqueJSString = struct_OpaqueJSString;
+pub const OpaqueJSClass = struct_OpaqueJSClass;
+pub const OpaqueJSPropertyNameArray = struct_OpaqueJSPropertyNameArray;
+pub const OpaqueJSPropertyNameAccumulator = struct_OpaqueJSPropertyNameAccumulator;
+pub const OpaqueJSValue = struct_OpaqueJSValue;
+
+// -- Manual --
+
+// StringImpl::createWithoutCopying
+// https://github.com/WebKit/webkit/blob/main/Source/JavaScriptCore/API/JSStringRef.cpp#L62
+pub extern fn JSStringCreateWithCharactersNoCopy(string: [*c]const JSChar, numChars: size_t) JSStringRef;
+
diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig
new file mode 100644
index 000000000..aff505f22
--- /dev/null
+++ b/src/javascript/jsc/javascript.zig
@@ -0,0 +1,534 @@
+const js = @import("./JavaScriptCore.zig");
+const std = @import("std");
+usingnamespace @import("../../global.zig");
+const Fs = @import("../../fs.zig");
+const resolver = @import("../../resolver/resolver.zig");
+const ast = @import("../../ast/base.zig");
+const NodeModuleBundle = @import("../../node_module_bundle.zig").NodeModuleBundle;
+const WTFString = @import("../../wtf_string_mutable.zig").WTFStringMutable;
+const logger = @import("../../logger.zig");
+pub const ExportJavaScript = union(Tag) {
+ Module: *Module,
+ String: *String,
+ GlobalObject: *GlobalObject,
+
+ pub const Tag = enum {
+ Module,
+ String,
+ GlobalObject,
+ };
+};
+
+pub const ResolveFunctionType = fn (ctx: anytype, source_dir: string, import_path: string, import_kind: ast.ImportKind) anyerror!resolver.Result;
+pub const TranspileFunctionType = fn (ctx: anytype, resolve_result: resolver.Result) anyerror![:0]const u8;
+
+const JSStringMapContext = struct {
+ pub fn hash(self: @This(), s: js.JSStringRef) u64 {
+ return hashString(s);
+ }
+ pub fn eql(self: @This(), a: js.JSStringRef, b: js.JSStringRef) bool {
+ return eqlString(a, b);
+ }
+};
+
+pub fn JSStringMap(comptime V: type) type {
+ return std.HashMap(js.JSStringRef, V, JSStringMapContext, 60);
+}
+
+// If you read JavascriptCore/API/JSVirtualMachine.mm - https://github.com/WebKit/WebKit/blob/acff93fb303baa670c055cb24c2bad08691a01a0/Source/JavaScriptCore/API/JSVirtualMachine.mm#L101
+// We can see that it's sort of like std.mem.Allocator but for JSGlobalContextRef, to support Automatic Reference Counting
+// Its unavailable on Linux
+pub const VirtualMachine = struct {
+ const RequireCacheType = std.AutoHashMap(u64, Module);
+ ctx: js.JSGlobalContextRef,
+ group: js.JSContextGroupRef,
+ allocator: *std.mem.Allocator,
+ transpile_ctx: *c_void = undefined,
+ transpile: *TranspileFunctionType = undefined,
+ require_cache: RequireCacheType,
+ resolve_: *ResolveFunctionType = undefined,
+ resolve_ctx: *c_void = undefined,
+ node_modules: ?*NodeModuleBundle = null,
+ node_modules_ref: js.JSObjectRef = null,
+ global: GlobalObject,
+
+ pub fn init(allocator: *std.mem.Allocator) !*VirtualMachine {
+ var group = js.JSContextGroupCreate();
+ var ctx = js.JSGlobalContextCreateInGroup(group, null);
+
+ Properties.init();
+ var vm = try allocator.create(VirtualMachine);
+ vm.* = .{
+ .allocator = allocator,
+ .group = group,
+ .ctx = ctx,
+ .require_cache = RequireCacheType.init(allocator),
+ .global = undefined,
+ };
+ vm.global = GlobalObject{ .vm = undefined };
+ return vm;
+ }
+
+ pub fn setupGlobals(this: *VirtualMachine) void {}
+
+ pub fn resolve(
+ this: *VirtualMachine,
+ from: *const Module,
+ to: string,
+ ) !js.JSValueRef {
+ return (try this.resolve_(this.resolve_ctx, from.path.dir, to, .require)) orelse return error.ModuleNotFound;
+ }
+ threadlocal var require_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+
+ // Assume bundle is already transpiled, so we skip transpiling in here.
+ pub fn requireFromBundle(this: *VirtualMachine, import_path: string) !js.JSValueRef {}
+
+ pub fn require(
+ this: *VirtualMachine,
+ module: *const Module,
+ path_value: js.JSValueRef,
+ ) !js.JSValueRef {
+ var import_path = To.Zig.str(path_value, &require_buf);
+ var resolve_result = try this.resolve(module, import_path);
+ }
+
+ threadlocal var eval_buf: WTFString = undefined;
+ threadlocal var eval_buf_loaded: bool = false;
+
+ pub fn evalUtf8(
+ this: *VirtualMachine,
+ path_text: string,
+ contents: string,
+ ) !js.JSValueRef {
+ if (!eval_buf_loaded) {
+ eval_buf = try WTFString.init(this.allocator, contents.len + path.text.len + 2);
+ } else {
+ eval_buf.reset();
+ try eval_buf.growIfNeeded(contents.len + path.text.len + 2);
+ }
+
+ try eval_buf.append(contents);
+ eval_buf.list.append(eval_buf.allocator, 0);
+ var script_len = eval_buf.list.items.len;
+ if (path_text.len > 0) {
+ try eval_buf.append(path_text);
+ eval_buf.list.append(eval_buf.allocator, 0);
+ }
+
+ var buf = eval_buf.toOwnedSliceLeaky();
+ var script = js.JSStringCreateWithCharactersNoCopy(buf[0..script_len].ptr, script_len - 1);
+ var sourceURL: js.JSStringRef = null;
+
+ if (path_text.len > 0) {
+ sourceURL = js.JSStringCreateWithCharactersNoCopy(
+ buf[script_len + 1 ..].ptr,
+ buf[script_len + 1 ..].len - 1,
+ );
+ }
+
+ return js.JSEvaluateScript(
+ this.ctx,
+ script,
+ js.JSValueMakeUndefined(this.ctx),
+ sourceURL,
+ 0,
+ null,
+ );
+ }
+};
+
+pub const BundleLoader = struct {
+ bundle: *const NodeModuleBundle,
+ allocator: *std.mem.Allocator,
+ vm: *VirtualMachine,
+ loaded: bool = false,
+ ref: js.JSObjectRef = null,
+
+ pub fn init(bundle: *const NodeModuleBundle, allocator: *std.mem.Allocator, vm: *VirtualMachine) BundleLoader {
+ return BundleLoader{
+ .bundle = bundle,
+ .allocator = allocator,
+ .vm = vm,
+ };
+ }
+
+ pub fn loadBundle(this: *BundleLoader) !void {}
+};
+
+pub const To = struct {
+ pub const JS = struct {
+ pub inline fn str(ref: anytype, val: anytype) js.JSStringRef {
+ return js.JSStringCreateWithUTF8CString(val[0.. :0]);
+ }
+
+ pub fn functionWithCallback(
+ comptime ZigContextType: type,
+ zig: *ZigContextType,
+ name: js.JSStringRef,
+ ctx: js.JSContextRef,
+ comptime callback: fn (
+ obj: *ZigContextType,
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
+ arguments: []js.JSValueRef,
+ exception: [*c]js.JSValueRef,
+ ) js.JSValueRef,
+ ) js.JSObjectRef {
+ var function = js.JSObjectMakeFunctionWithCallback(ctx, name, Callback(ZigContextType, callback));
+ js.JSObjectSetPrivate(function, @ptrCast(*c_void, zig));
+ return function;
+ }
+
+ pub fn Callback(
+ comptime ZigContextType: type,
+ comptime ctxfn: fn (
+ obj: *ZigContextType,
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
+ arguments: []js.JSValueRef,
+ exception: [*c]js.JSValueRef,
+ ) js.JSValueRef,
+ ) type {
+ return struct {
+ pub fn run(
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
+ argumentCount: usize,
+ arguments: [*c]const js.JSValueRef,
+ exception: [*c]js.JSValueRef,
+ ) callconv(.C) js.JSValueRef {
+ var object_ptr = js.JSObjectGetPrivate(function) orelse {
+ return js.JSValueMakeUndefined(ctx);
+ };
+
+ return ctxfn(
+ @intToPtr(ZigContextType, object_ptr),
+ ctx,
+ function,
+ thisObject,
+ arguments[0..argumentCount],
+ exception,
+ );
+ }
+ };
+ }
+ };
+
+ pub const Ref = struct {
+ pub inline fn str(ref: anytype) js.JSStringRef {
+ return @as(js.JSStringRef, ref);
+ }
+ };
+
+ pub const Zig = struct {
+ pub inline fn str(ref: anytype, buf: anytype) string {
+ return buf[0..js.JSStringGetUTF8CString(Ref.str(ref), buf.ptr, buf.len)];
+ }
+ };
+};
+
+pub const Properties = struct {
+ pub const UTF8 = struct {
+ pub const module = "module";
+ pub const globalThis = "globalThis";
+ pub const exports = "exports";
+ pub const log = "log";
+ pub const debug = "debug";
+ pub const info = "info";
+ pub const error_ = "error";
+ pub const warn = "warn";
+ pub const console = "console";
+ pub const require = "require";
+ pub const description = "description";
+ };
+
+ pub const UTF16 = struct {
+ pub const module = std.unicode.utf8ToUtf16LeStringLiteral("module");
+ pub const globalThis = std.unicode.utf8ToUtf16LeStringLiteral("globalThis");
+ pub const exports = std.unicode.utf8ToUtf16LeStringLiteral("exports");
+ pub const log = std.unicode.utf8ToUtf16LeStringLiteral("log");
+ pub const debug = std.unicode.utf8ToUtf16LeStringLiteral("debug");
+ pub const info = std.unicode.utf8ToUtf16LeStringLiteral("info");
+ pub const error_ = std.unicode.utf8ToUtf16LeStringLiteral("error");
+ pub const warn = std.unicode.utf8ToUtf16LeStringLiteral("warn");
+ pub const console = std.unicode.utf8ToUtf16LeStringLiteral("console");
+ pub const require = std.unicode.utf8ToUtf16LeStringLiteral("require");
+ pub const description = std.unicode.utf8ToUtf16LeStringLiteral("description");
+ };
+
+ pub const Refs = struct {
+ pub var module: js.JSStringRef = undefined;
+ pub var globalThis: js.JSStringRef = undefined;
+ pub var exports: js.JSStringRef = undefined;
+ pub var log: js.JSStringRef = undefined;
+ pub var debug: js.JSStringRef = undefined;
+ pub var info: js.JSStringRef = undefined;
+ pub var error_: js.JSStringRef = undefined;
+ pub var warn: js.JSStringRef = undefined;
+ pub var console: js.JSStringRef = undefined;
+ pub var require: js.JSStringRef = undefined;
+ pub var description: js.JSStringRef = undefined;
+ };
+
+ pub fn init() void {
+ inline for (std.meta.fieldNames(UTF8)) |name| {
+ @field(Refs, name) = js.JSStringCreateWithCharactersNoCopy(
+ &@field(StringStore.UTF16, name),
+ @field(StringStore.UTF16, name).len,
+ );
+ }
+ }
+};
+
+pub const Object = struct {
+ ref: js.jsObjectRef,
+};
+
+pub const String = struct {
+ ref: js.JSStringRef,
+ len: usize,
+
+ pub fn chars(this: *const String) []js.JSChar {
+ return js.JSStringGetCharactersPtr(this.ref)[0..js.JSStringGetLength(this.ref)];
+ }
+
+ pub fn eql(this: *const String, str: [*c]const u8) bool {
+ return str.len == this.len and js.JSStringIsEqualToUTF8CString(this, str);
+ }
+};
+
+pub const Module = struct {
+ path: Fs.PathName,
+
+ require: RequireObject,
+ hash: u64,
+ ref: js.JSObjectRef,
+
+ pub const RequireObject = struct {};
+
+ pub fn require(
+ this: *Module,
+ arguments: [*c]const js.JSValueRef,
+ arguments_len: usize,
+ exception: [*c]JSValueRef,
+ ) js.JSValueRef {}
+};
+
+pub const GlobalObject = struct {
+ ref: js.JSObjectRef = undefined,
+ vm: *VirtualMachine,
+ console: js.JSClassRef = undefined,
+ console_definition: js.JSClassDefinition = undefined,
+
+ pub const ConsoleClass = NewSingletonClass(
+ GlobalObject,
+ "Console",
+ .{
+ .@"log" = stdout,
+ .@"info" = stdout,
+ .@"debug" = stdout,
+ .@"verbose" = stdout,
+
+ .@"error" = stderr,
+ .@"warn" = stderr,
+ },
+ // people sometimes modify console.log, let them.
+ false,
+ );
+
+ pub fn load(global: *GlobalObject) !void {
+ global.console_definition = ConsoleClass.define(global, global.vm.ctx);
+ global.console = js.JSClassCreate(&global.console_definition);
+ }
+
+ fn valuePrinter(comptime ValueType: js.JSType, ctx: js.JSContextRef, arg: js.JSValueRef, writer: anytype) !void {
+ switch (ValueType) {
+ .kJSTypeUndefined => {
+ try writer.writeAll("undefined");
+ },
+ .kJSTypeNull => {
+ try writer.writeAll("null");
+ },
+ .kJSTypeBoolean => {
+ if (js.JSValueToBoolean(ctx, arg)) {
+ try writer.writeAll("true");
+ } else {
+ try writer.writeAll("false");
+ }
+ },
+ .kJSTypeNumber => {
+ try writer.print("{d}", js.JSValueToNumber(ctx, arg, null));
+ },
+ .kJSTypeString => {
+ var str = String{ .ref = @as(js.JSStringRef, arg) };
+ var chars = str.chars();
+ switch (chars.len) {
+ 0 => {
+ try writer.writeAll("\"\"");
+ },
+ else => {
+ for (chars) |c, i| {
+ switch (c) {
+ 0...127 => {
+ // Since we're writing character by character
+ // it will be really slow if we check for an error every time
+ _ = writer.write(@intCast(u8, c)) catch 0;
+ },
+ // TODO:
+ else => {},
+ }
+ }
+ },
+ }
+ },
+ .kJSTypeObject => {
+ // TODO:
+ try writer.writeAll("[Object object]");
+ },
+ .kJSTypeSymbol => {
+ var description = js.JSObjectGetPropertyForKey(ctx, arg, Properties.Refs.description, null);
+ return switch (js.JSValueGetType(ctx, description)) {
+ .kJSTypeString => try valuePrinter(.kJSTypeString, ctx, description, writer),
+ else => try valuePrinter(.kJSTypeUndefined, ctx, description, writer),
+ };
+ },
+ else => {},
+ }
+ }
+
+ fn output(
+ writer: anytype,
+ ctx: js.JSContextRef,
+ arguments: []js.JSValueRef,
+ ) !void {
+ defer Output.flush();
+ // console.log();
+ if (arguments.len == 0) {
+ return js.JSValueMakeUndefined(ctx);
+ }
+
+ const last = arguments.len - 1;
+
+ for (arguments) |arg, i| {
+ switch (js.JSValueGetType(ctx, arg)) {
+ .kJSTypeUndefined => {
+ try valuePrinter(.kJSTypeUndefined, ctx, arg, writer);
+ if (i != last) {
+ try writer.writeAll(" ");
+ }
+ },
+ .kJSTypeNull => {
+ try valuePrinter(.kJSTypeNull, ctx, arg, writer);
+ if (i != last) {
+ try writer.writeAll(" ");
+ }
+ },
+ .kJSTypeBoolean => {
+ try valuePrinter(.kJSTypeBoolean, ctx, arg, writer);
+ if (i != last) {
+ try writer.writeAll(" ");
+ }
+ },
+ .kJSTypeNumber => {
+ try valuePrinter(.kJSTypeNumber, ctx, arg, writer);
+ if (i != last) {
+ try writer.writeAll(" ");
+ }
+ },
+ .kJSTypeString => {
+ try valuePrinter(.kJSTypeString, ctx, arg, writer);
+ if (i != last) {
+ try writer.writeAll(" ");
+ }
+ },
+ .kJSTypeObject => {
+ try valuePrinter(.kJSTypeObject, ctx, arg, writer);
+ if (i != last) {
+ try writer.writeAll(" ");
+ }
+ },
+ .kJSTypeSymbol => {
+ try valuePrinter(.kJSTypeSymbol, ctx, arg, writer);
+ if (i != last) {
+ try writer.writeAll(" ");
+ }
+ },
+ else => {},
+ }
+ }
+
+ return js.JSValueMakeUndefined(ctx);
+ }
+
+ pub fn stdout(
+ obj: *GlobalObject,
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
+ arguments: []js.JSValueRef,
+ ) js.JSValueRef {
+ return try output(Output.writer(), ctx, arguments);
+ }
+
+ pub fn stderr(
+ obj: *GlobalObject,
+ ctx: js.JSContextRef,
+ function: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
+ arguments: []js.JSValueRef,
+ ) js.JSValueRef {
+ return try output(Output.errorWriter(), ctx, arguments);
+ // js.JSObjectMakeFunctionWithCallback(ctx: JSContextRef, name: JSStringRef, callAsFunction: JSObjectCallAsFunctionCallback)
+ }
+};
+
+pub fn NewSingletonClass(
+ comptime ZigType: type,
+ comptime name: string,
+ comptime functions: anytype,
+ comptime read_only: bool,
+) type {
+ return struct {
+ const ClassDefinitionCreator = @This();
+ const function_names = std.meta.fieldNames(functions);
+ const function_name_literals: [function_names.len][]js.JSChar = brk: {
+ var names = std.mem.zeroes([function_names.len][]js.JSChar);
+
+ for (function_names) |field, i| {
+ names[i] = std.unicode.utf8ToUtf16LeStringLiteral(field);
+ }
+ break :brk names;
+ };
+ var function_name_refs: [function_names.len]js.JSStringRef = undefined;
+
+ const class_name_literal = std.unicode.utf8ToUtf16LeStringLiteral(name);
+ var static_functions: [function_name_refs.len + 1:0]js.JSStaticFunction = undefined;
+
+ pub fn define(zig: *ZigType, ctx: js.JSContextRef) !js.JSClassDefinition {
+ var def = std.mem.zeroes(js.JSClassDefinition);
+
+ inline for (function_name_literals) |function_name, i| {
+ function_name_refs[i] = js.JSStringCreateWithCharactersNoCopy(&function_name, function_name.len);
+ static_functions[i] = js.JSStaticFunction{
+ .name = (function_names[i][0.. :0]).ptr,
+ .callAsFunction = To.JS.functionWithCallback(
+ ZigType,
+ zig,
+ function_name_refs[i],
+ ctx,
+ @field(functions, function_names[i]),
+ ),
+ .attributes = comptime if (read_only) js.JSPropertyAttributes.kJSPropertyAttributeReadOnly else js.JSPropertyAttributes.kJSPropertyAttributeNone,
+ };
+ }
+ static_functions[function_name_literals.len] = std.mem.zeroes(js.JSStaticFunction);
+ def.staticFunctions = static_functions[0.. :0].ptr;
+ def.className = name[0.. :0].ptr;
+
+ return def;
+ }
+ };
+}
diff --git a/src/js_lexer.zig b/src/js_lexer.zig
index c71b6b628..0e469122e 100644
--- a/src/js_lexer.zig
+++ b/src/js_lexer.zig
@@ -2625,31 +2625,28 @@ pub const CodepointIterator = struct {
width: u3 = 0,
c: CodePoint = 0,
- pub fn nextCodepointSlice(it: *CodepointIterator) ?[]const u8 {
- if (it.i >= it.bytes.len) {
- return null;
- }
+ pub fn nextCodepointSlice(it: *CodepointIterator) []const u8 {
+ @setRuntimeSafety(false);
- const cp_len = std
- .unicode.utf8ByteSequenceLength(it.bytes[it.i]) catch unreachable;
+ const cp_len = strings.utf8ByteSequenceLength(it.bytes[it.i]);
it.i += cp_len;
- return it.bytes[it.i - cp_len .. it.i];
+
+ return if (!(it.i > it.bytes.len)) it.bytes[it.i - cp_len .. it.i] else "";
}
pub fn nextCodepoint(it: *CodepointIterator) ?CodePoint {
- const slice = it.nextCodepointSlice() orelse return null;
- it.width = @intCast(u3, slice.len);
- @setRuntimeSafety(false);
+ const slice = it.nextCodepointSlice();
- it.c = switch (it.width) {
- 1 => @intCast(CodePoint, slice[0]),
- 2 => @intCast(CodePoint, std.unicode.utf8Decode2(slice) catch unreachable),
- 3 => @intCast(CodePoint, std.unicode.utf8Decode3(slice) catch unreachable),
- 4 => @intCast(CodePoint, std.unicode.utf8Decode4(slice) catch unreachable),
+ it.c = switch (slice.len) {
+ 0 => it.c,
+ 1 => @as(CodePoint, slice[0]),
+ 2 => @as(CodePoint, unicode.utf8Decode2(slice) catch unreachable),
+ 3 => @as(CodePoint, unicode.utf8Decode3(slice) catch unreachable),
+ 4 => @as(CodePoint, unicode.utf8Decode4(slice) catch unreachable),
else => unreachable,
};
- return it.c;
+ return if (slice.len > 0) it.c else null;
}
/// Look ahead at the next n codepoints without advancing the iterator.
diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig
index f8b565fe7..39c3af492 100644
--- a/src/js_parser/js_parser.zig
+++ b/src/js_parser/js_parser.zig
@@ -2259,7 +2259,6 @@ const ParserFeatures = struct {
//
//
//
-
react_fast_refresh: bool = false,
};
diff --git a/src/options.zig b/src/options.zig
index 54483e801..aca85ed31 100644
--- a/src/options.zig
+++ b/src/options.zig
@@ -244,9 +244,10 @@ pub const ModuleType = enum {
};
pub const Platform = enum {
- node,
- browser,
neutral,
+ browser,
+ speedy,
+ node,
pub const Extensions = struct {
pub const In = struct {
diff --git a/src/runtime.footer.js b/src/runtime.footer.js
index 94a358eb5..cad687e2d 100644
--- a/src/runtime.footer.js
+++ b/src/runtime.footer.js
@@ -1,6 +1,8 @@
// ---
// Public exports from runtime
-export var $$m = SPEEDY_RUNTIME.$$m;
+// Compatible with Speedy's Runtime Environment and web browsers.
+export var $$m =
+ "$primordials" in globalThis ? $primordials.require : SPEEDY_RUNTIME.$$m;
export var __HMRModule = SPEEDY_RUNTIME.__HMRModule;
export var __FastRefreshModule = SPEEDY_RUNTIME.__FastRefreshModule;
export var __HMRClient = SPEEDY_RUNTIME.__HMRClient;
@@ -9,6 +11,6 @@ export var $$lzy = SPEEDY_RUNTIME.$$lzy;
export var __toModule = SPEEDY_RUNTIME.__toModule;
export var __commonJS = SPEEDY_RUNTIME.__commonJS;
export var __require = SPEEDY_RUNTIME.__require;
-export var __name = SPEEDY_RUNTIME.__name;
-export var __export = SPEEDY_RUNTIME.__export;
-export var __reExport = SPEEDY_RUNTIME.__reExport;
+export var __name = PEEDY_RUNTIME.__name;
+export var __export = PEEDY_RUNTIME.__export;
+export var __reExport = PEEDY_RUNTIME.__reExport;
diff --git a/src/runtime.version b/src/runtime.version
index 38984f56a..eaedfa1e4 100644
--- a/src/runtime.version
+++ b/src/runtime.version
@@ -1 +1 @@
-2a14be7fb8890d70 \ No newline at end of file
+35bcb0f8b5e80d25 \ No newline at end of file
diff --git a/src/string_immutable.zig b/src/string_immutable.zig
index c97b0901e..546ba8a4f 100644
--- a/src/string_immutable.zig
+++ b/src/string_immutable.zig
@@ -305,12 +305,17 @@ pub fn encodeWTF8Rune(p: []u8, r: i32) u3 {
}
pub fn toUTF16Buf(in: string, out: []u16) usize {
- var utf8Iterator = std.unicode.Utf8Iterator{ .bytes = in, .i = 0 };
+ var utf8Iterator = CodepointIterator{ .bytes = in, .i = 0 };
var c: u21 = 0;
var i: usize = 0;
- while (utf8Iterator.nextCodepoint()) |code_point| {
+ while (true) {
+ const code_point = utf8Iterator.nextCodepoint();
+
switch (code_point) {
+ -1 => {
+ return i;
+ },
0...0xFFFF => {
out[i] = @intCast(u16, code_point);
i += 1;
@@ -329,7 +334,7 @@ pub fn toUTF16Buf(in: string, out: []u16) usize {
}
pub fn toUTF16Alloc(in: string, allocator: *std.mem.Allocator) !JavascriptString {
- var utf8Iterator = std.unicode.Utf8Iterator{ .bytes = in, .i = 0 };
+ var utf8Iterator = CodepointIterator{ .bytes = in, .i = 0 };
var out = try std.ArrayList(u16).initCapacity(allocator, in.len);
var c: u21 = 0;
diff --git a/src/wtf_string_mutable.zig b/src/wtf_string_mutable.zig
new file mode 100644
index 000000000..2c94dae22
--- /dev/null
+++ b/src/wtf_string_mutable.zig
@@ -0,0 +1,243 @@
+const std = @import("std");
+const expect = std.testing.expect;
+
+usingnamespace @import("string_types.zig");
+const strings = @import("string_immutable.zig");
+const js_lexer = @import("js_lexer.zig");
+const ListType = std.ArrayListUnmanaged(u16);
+pub const WTFStringMutable = struct {
+ allocator: *std.mem.Allocator,
+ list: ListType,
+
+ pub const Writer = std.io.Writer(*@This(), anyerror, WTFStringMutable.writeAll);
+ pub fn writer(self: *WTFStringMutable) Writer {
+ return Writer{
+ .context = self,
+ };
+ }
+
+ pub fn deinit(str: *WTFStringMutable) void {
+ str.list.deinit(str.allocator);
+ }
+
+ pub fn growIfNeeded(self: *WTFStringMutable, amount: usize) !void {
+ try self.list.ensureUnusedCapacity(self.allocator, amount);
+ }
+
+ pub fn write(self: *WTFStringMutable, bytes: anytype) !usize {
+ try self.list.appendSlice(self.allocator, bytes);
+ return bytes.len;
+ }
+
+ pub fn writeAll(self: *WTFStringMutable, bytes: string) !usize {
+ try self.list.appendSlice(self.allocator, bytes);
+ return self.list.items.len;
+ }
+
+ pub fn init(allocator: *std.mem.Allocator, capacity: usize) !WTFStringMutable {
+ return WTFStringMutable{ .allocator = allocator, .list = try ListType.initCapacity(allocator, capacity) };
+ }
+
+ pub fn initCopy(allocator: *std.mem.Allocator, str: anytype) !WTFStringMutable {
+ var mutable = try WTFStringMutable.init(allocator, std.mem.len(str));
+ try mutable.copy(str);
+ return mutable;
+ }
+
+ // Convert it to an ASCII identifier. Note: If you change this to a non-ASCII
+ // identifier, you're going to potentially cause trouble with non-BMP code
+ // points in target environments that don't support bracketed Unicode escapes.
+
+ pub fn ensureValidIdentifier(str: string, allocator: *std.mem.Allocator) !string {
+ if (str.len == 0) {
+ return "_";
+ }
+
+ var has_needed_gap = false;
+ var needs_gap = false;
+ var start_i: usize = 0;
+
+ // Common case: no gap necessary. No allocation necessary.
+ needs_gap = !js_lexer.isIdentifierStart(@intCast(js_lexer.CodePoint, str[0]));
+ if (!needs_gap) {
+ // Are there any non-alphanumeric chars at all?
+ for (str[1..str.len]) |c, i| {
+ if (!js_lexer.isIdentifierContinue(@intCast(js_lexer.CodePoint, c))) {
+ needs_gap = true;
+ start_i = 1 + i;
+ break;
+ }
+ }
+ }
+
+ if (needs_gap) {
+ var mutable = try WTFStringMutable.initCopy(allocator, str[0..start_i]);
+ needs_gap = false;
+
+ var i: usize = 0;
+
+ var slice = str[start_i..];
+
+ while (i < slice.len) : (i += 1) {
+ const c = @intCast(js_lexer.CodePoint, slice[i]);
+ if (js_lexer.isIdentifierContinue(c)) {
+ if (needs_gap) {
+ try mutable.appendChar('_');
+ needs_gap = false;
+ has_needed_gap = true;
+ }
+
+ try mutable.appendChar(slice[i]);
+ } else if (!needs_gap) {
+ needs_gap = true;
+ // skip the code point, replace it with a single _
+ i += std.math.max(strings.utf8ByteSequenceLength(slice[i]), 1) - 1;
+ }
+ }
+
+ // If it ends with an emoji
+ if (needs_gap) {
+ try mutable.appendChar('_');
+ needs_gap = false;
+ has_needed_gap = true;
+ }
+
+ return mutable.list.toOwnedSlice(allocator);
+ }
+
+ return str;
+ }
+
+ pub fn len(self: *const WTFStringMutable) usize {
+ return self.list.items.len;
+ }
+
+ pub fn copy(self: *WTFStringMutable, str: anytype) !void {
+ try self.list.ensureCapacity(self.allocator, std.mem.len(str[0..]));
+
+ if (self.list.items.len == 0) {
+ try self.list.insertSlice(self.allocator, 0, str);
+ } else {
+ try self.list.replaceRange(self.allocator, 0, std.mem.len(str[0..]), str[0..]);
+ }
+ }
+
+ pub inline fn growBy(self: *WTFStringMutable, amount: usize) !void {
+ try self.list.ensureUnusedCapacity(self.allocator, amount);
+ }
+
+ pub inline fn reset(
+ self: *WTFStringMutable,
+ ) void {
+ self.list.shrinkRetainingCapacity(0);
+ }
+
+ pub inline fn appendChar(self: *WTFStringMutable, char: u8) !void {
+ try self.list.append(self.allocator, char);
+ }
+ pub inline fn appendCharAssumeCapacity(self: *WTFStringMutable, char: u8) void {
+ self.list.appendAssumeCapacity(char);
+ }
+ pub inline fn append(self: *WTFStringMutable, str: []const u8) !void {
+ self.growIfNeeded(str.len);
+
+ var iter = strings.CodepointIterator{ .bytes = str, .i = 0 };
+ while (true) {
+ switch (iter.nextCodepoint()) {
+ -1 => {
+ return;
+ },
+ 0...0xFFFF => {
+ try self.list.append(@intCast(u16, iter.c));
+ },
+ else => {
+ const c = iter.c - 0x10000;
+ try self.list.append(@intCast(u16, 0xD800 + ((c >> 10) & 0x3FF)));
+ try self.list.append(@intCast(u16, 0xDC00 + (c & 0x3FF)));
+ },
+ }
+ }
+ }
+
+ pub inline fn appendComptimeConvert(self: *WTFStringMutable, comptime _str: []const u8) !void {
+ const str = std.unicode.utf8ToUtf16LeStringLiteral(_str);
+ try self.list.appendSlice(str);
+ }
+
+ pub inline fn appendAssumeCapacity(self: *WTFStringMutable, str: []const u8) void {
+ var iter = strings.CodepointIterator{ .bytes = str, .i = 0 };
+ while (true) {
+ switch (iter.nextCodepoint()) {
+ -1 => {
+ return;
+ },
+ 0...0xFFFF => {
+ self.list.appendAssumeCapacity(@intCast(u16, iter.c));
+ },
+ else => {
+ const c = iter.c - 0x10000;
+ self.list.appendAssumeCapacity(@intCast(u16, 0xD800 + ((c >> 10) & 0x3FF)));
+ self.list.appendAssumeCapacity(@intCast(u16, 0xDC00 + (c & 0x3FF)));
+ },
+ }
+ }
+ }
+ pub inline fn lenI(self: *WTFStringMutable) i32 {
+ return @intCast(i32, self.list.items.len);
+ }
+
+ pub fn toOwnedSlice(self: *WTFStringMutable) string {
+ return self.list.toOwnedSlice(self.allocator);
+ }
+
+ pub fn toOwnedSliceLeaky(self: *WTFStringMutable) string {
+ return self.list.items;
+ }
+
+ pub fn toOwnedSliceLength(self: *WTFStringMutable, length: usize) string {
+ self.list.shrinkAndFree(self.allocator, length);
+ return self.list.toOwnedSlice(self.allocator);
+ }
+
+ // pub fn deleteAt(self: *WTFStringMutable, i: usize) {
+ // self.list.swapRemove(i);
+ // }
+
+ pub fn containsChar(self: *WTFStringMutable, char: u8) bool {
+ return self.indexOfChar(char) != null;
+ }
+
+ pub fn indexOfChar(self: *WTFStringMutable, char: u8) ?usize {
+ return std.mem.indexOfScalar(@TypeOf(char), self.list.items, char);
+ }
+
+ pub fn lastIndexOfChar(self: *WTFStringMutable, char: u8) ?usize {
+ return std.mem.lastIndexOfScalar(@TypeOf(char), self.list.items, char);
+ }
+
+ pub fn lastIndexOf(self: *WTFStringMutable, str: u8) ?usize {
+ return std.mem.lastIndexOf(u8, self.list.items, str);
+ }
+
+ pub fn indexOf(self: *WTFStringMutable, str: u8) ?usize {
+ return std.mem.indexOf(u8, self.list.items, str);
+ }
+
+ pub fn eql(self: *WTFStringMutable, other: anytype) bool {
+ return std.mem.eql(u8, self.list.items, other);
+ }
+};
+
+test "WTFStringMutable" {
+ const alloc = std.heap.page_allocator;
+
+ var str = try WTFStringMutable.initCopy(alloc, "hello");
+ expect(str.eql("hello"));
+}
+
+test "WTFStringMutable.ensureValidIdentifier" {
+ const alloc = std.heap.page_allocator;
+
+ try std.testing.expectEqualStrings("jquery", try WTFStringMutable.ensureValidIdentifier("jquery", alloc));
+ try std.testing.expectEqualStrings("jquery_foo", try WTFStringMutable.ensureValidIdentifier("jquery😋foo", alloc));
+}