mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 04:16:51 +00:00
[dart2wasm] Generate the bulk of the JS runtime at compile time.
Change-Id: Ib5f9bdedcda4a4ba305d7eea2e6c127f815582ec Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/279640 Commit-Queue: Joshua Litt <joshualitt@google.com> Reviewed-by: Aske Simon Christensen <askesc@google.com>
This commit is contained in:
parent
45817fd9c7
commit
8a7dd221ad
|
@ -60,14 +60,6 @@ export const instantiate = async (modulePromise, importObjectPromise) => {
|
|||
return array;
|
||||
}
|
||||
|
||||
function dataViewFromDartByteData(byteData, byteLength) {
|
||||
const dataView = new DataView(new ArrayBuffer(byteLength));
|
||||
for (let i = 0; i < byteLength; i++) {
|
||||
dataView.setUint8(i, dartInstance.exports.$byteDataGetUint8(byteData, i));
|
||||
}
|
||||
return dataView;
|
||||
}
|
||||
|
||||
// A special symbol attached to functions that wrap Dart functions.
|
||||
const jsWrappedDartFunctionSymbol = Symbol("JSWrappedDartFunction");
|
||||
|
||||
|
@ -77,295 +69,8 @@ export const instantiate = async (modulePromise, importObjectPromise) => {
|
|||
return wrapped;
|
||||
}
|
||||
|
||||
// Calls a constructor with a variable number of arguments.
|
||||
function callConstructorVarArgs(constructor, args) {
|
||||
// Apply bind to the constructor. We pass `null` as the first argument
|
||||
// to `bind.apply` because this is `bind`'s unused context
|
||||
// argument(`new` will explicitly create a new context).
|
||||
const factoryFunction = constructor.bind.apply(constructor, [null, ...args]);
|
||||
return new factoryFunction();
|
||||
}
|
||||
|
||||
// Imports
|
||||
const dart2wasm = {
|
||||
printToConsole: function(string) {
|
||||
console.log(stringFromDartString(string))
|
||||
},
|
||||
scheduleCallback: function(milliseconds, closure) {
|
||||
setTimeout(function() {
|
||||
dartInstance.exports.$invokeCallback(closure);
|
||||
}, milliseconds);
|
||||
},
|
||||
futurePromise: new WebAssembly.Function(
|
||||
{parameters: ['externref', 'externref'], results: ['externref']},
|
||||
function(future) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
dartInstance.exports.$awaitCallback(future, resolve);
|
||||
});
|
||||
},
|
||||
{suspending: 'first'}),
|
||||
callResolve: function(resolve, result) {
|
||||
// This trampoline is needed because [resolve] is a JS function that
|
||||
// can't be called directly from Wasm.
|
||||
resolve(result);
|
||||
},
|
||||
callAsyncBridge: function(args, completer) {
|
||||
// This trampoline is needed because [asyncBridge] is a function wrapped
|
||||
// by `returnPromiseOnSuspend`, and the stack-switching functionality of
|
||||
// that wrapper is implemented as part of the export adapter.
|
||||
asyncBridge(args, completer);
|
||||
},
|
||||
getCurrentStackTrace: function() {
|
||||
// [Error] should be supported in most browsers.
|
||||
// A possible future optimization we could do is to just save the
|
||||
// `Error` object here, and stringify the stack trace when it is
|
||||
// actually used.
|
||||
let stackString = new Error().stack.toString();
|
||||
|
||||
// We remove the last three lines of the stack trace to prevent including
|
||||
// `Error`, `getCurrentStackTrace`, and `StackTrace.current` in the
|
||||
// stack trace.
|
||||
let userStackString = stackString.split('\n').slice(3).join('\n');
|
||||
return stringToDartString(userStackString);
|
||||
},
|
||||
int8ArrayFromDartInt8List: function(list) {
|
||||
return arrayFromDartList(Int8Array, list);
|
||||
},
|
||||
uint8ArrayFromDartUint8List: function(list) {
|
||||
return arrayFromDartList(Uint8Array, list);
|
||||
},
|
||||
uint8ClampedArrayFromDartUint8ClampedList: function(list) {
|
||||
return arrayFromDartList(Uint8ClampedArray, list);
|
||||
},
|
||||
int16ArrayFromDartInt16List: function(list) {
|
||||
return arrayFromDartList(Int16Array, list);
|
||||
},
|
||||
uint16ArrayFromDartUint16List: function(list) {
|
||||
return arrayFromDartList(Uint16Array, list);
|
||||
},
|
||||
int32ArrayFromDartInt32List: function(list) {
|
||||
return arrayFromDartList(Int32Array, list);
|
||||
},
|
||||
uint32ArrayFromDartUint32List: function(list) {
|
||||
return arrayFromDartList(Uint32Array, list);
|
||||
},
|
||||
float32ArrayFromDartFloat32List: function(list) {
|
||||
return arrayFromDartList(Float32Array, list);
|
||||
},
|
||||
float64ArrayFromDartFloat64List: function(list) {
|
||||
return arrayFromDartList(Float64Array, list);
|
||||
},
|
||||
dataViewFromDartByteData: function(byteData, byteLength) {
|
||||
return dataViewFromDartByteData(byteData, byteLength);
|
||||
},
|
||||
arrayFromDartList: function(list) {
|
||||
return arrayFromDartList(Array, list);
|
||||
},
|
||||
stringFromDartString: stringFromDartString,
|
||||
stringToDartString: stringToDartString,
|
||||
objectLength: function(o) {
|
||||
return o.length;
|
||||
},
|
||||
objectReadIndex: function(o, i) {
|
||||
return o[i];
|
||||
},
|
||||
objectKeys: function(o) {
|
||||
return Object.keys(o);
|
||||
},
|
||||
unwrapJSWrappedDartFunction: function(o) {
|
||||
return o.dartFunction;
|
||||
},
|
||||
isJSUndefined: function(o) {
|
||||
return o === undefined;
|
||||
},
|
||||
isJSBoolean: function(o) {
|
||||
return typeof o === "boolean";
|
||||
},
|
||||
isJSNumber: function(o) {
|
||||
return typeof o === "number";
|
||||
},
|
||||
isJSBigInt: function(o) {
|
||||
return typeof o === "bigint";
|
||||
},
|
||||
isJSString: function(o) {
|
||||
return typeof o === "string";
|
||||
},
|
||||
isJSSymbol: function(o) {
|
||||
return typeof o === "symbol";
|
||||
},
|
||||
isJSFunction: function(o) {
|
||||
return typeof o === "function";
|
||||
},
|
||||
isJSInt8Array: function(o) {
|
||||
return o instanceof Int8Array;
|
||||
},
|
||||
isJSUint8Array: function(o) {
|
||||
return o instanceof Uint8Array;
|
||||
},
|
||||
isJSUint8ClampedArray: function(o) {
|
||||
return o instanceof Uint8ClampedArray;
|
||||
},
|
||||
isJSInt16Array: function(o) {
|
||||
return o instanceof Int16Array;
|
||||
},
|
||||
isJSUint16Array: function(o) {
|
||||
return o instanceof Uint16Array;
|
||||
},
|
||||
isJSInt32Array: function(o) {
|
||||
return o instanceof Int32Array;
|
||||
},
|
||||
isJSUint32Array: function(o) {
|
||||
return o instanceof Uint32Array;
|
||||
},
|
||||
isJSFloat32Array: function(o) {
|
||||
return o instanceof Float32Array;
|
||||
},
|
||||
isJSFloat64Array: function(o) {
|
||||
return o instanceof Float64Array;
|
||||
},
|
||||
isJSArrayBuffer: function(o) {
|
||||
return o instanceof ArrayBuffer;
|
||||
},
|
||||
isJSDataView: function(o) {
|
||||
return o instanceof DataView;
|
||||
},
|
||||
isJSArray: function(o) {
|
||||
return o instanceof Array;
|
||||
},
|
||||
isJSWrappedDartFunction: function(o) {
|
||||
return typeof o === "function" &&
|
||||
o[jsWrappedDartFunctionSymbol] === true;
|
||||
},
|
||||
isJSObject: function(o) {
|
||||
return o instanceof Object;
|
||||
},
|
||||
isJSRegExp: function(o) {
|
||||
return o instanceof RegExp;
|
||||
},
|
||||
isJSSimpleObject: function(o) {
|
||||
const proto = Object.getPrototypeOf(o);
|
||||
return proto === Object.prototype || proto === null;
|
||||
},
|
||||
roundtrip: function(o) {
|
||||
// This function exists as a hook for the native JS -> Wasm type
|
||||
// conversion rules. The Dart runtime will overload variants of this
|
||||
// function with the necessary return type to trigger the desired
|
||||
// coercion.
|
||||
return o;
|
||||
},
|
||||
toJSBoolean: function(b) {
|
||||
return !!b;
|
||||
},
|
||||
newObject: function() {
|
||||
return {};
|
||||
},
|
||||
newArray: function() {
|
||||
return [];
|
||||
},
|
||||
globalThis: function() {
|
||||
return globalThis;
|
||||
},
|
||||
getProperty: function(object, name) {
|
||||
return object[name];
|
||||
},
|
||||
hasProperty: function(object, name) {
|
||||
return name in object;
|
||||
},
|
||||
setProperty: function(object, name, value) {
|
||||
return object[name] = value;
|
||||
},
|
||||
callMethodVarArgs: function(object, name, args) {
|
||||
return object[name].apply(object, args);
|
||||
},
|
||||
callConstructorVarArgs: callConstructorVarArgs,
|
||||
safeCallConstructorVarArgs: function(constructor, args) {
|
||||
try {
|
||||
return callConstructorVarArgs(constructor, args);
|
||||
} catch (e) {
|
||||
return String(e);
|
||||
}
|
||||
},
|
||||
getTimeZoneNameForSeconds: function(secondsSinceEpoch) {
|
||||
const date = new Date(secondsSinceEpoch * 1000);
|
||||
const match = /\((.*)\)/.exec(date.toString());
|
||||
if (match == null) {
|
||||
// This should never happen on any recent browser.
|
||||
return '';
|
||||
}
|
||||
return stringToDartString(match[1]);
|
||||
},
|
||||
getTimeZoneOffsetInSeconds: function(secondsSinceEpoch) {
|
||||
return new Date(secondsSinceEpoch * 1000).getTimezoneOffset() * 60;
|
||||
},
|
||||
jsonEncode: function(s) {
|
||||
return stringToDartString(JSON.stringify(stringFromDartString(s)));
|
||||
},
|
||||
toUpperCase: function(string) {
|
||||
return stringToDartString(stringFromDartString(string).toUpperCase());
|
||||
},
|
||||
toLowerCase: function(string) {
|
||||
return stringToDartString(stringFromDartString(string).toLowerCase());
|
||||
},
|
||||
isWindows: function() {
|
||||
return typeof process != undefined &&
|
||||
Object.prototype.toString.call(process) == "[object process]" &&
|
||||
process.platform == "win32";
|
||||
},
|
||||
getCurrentUri: function() {
|
||||
// On browsers return `globalThis.location.href`
|
||||
if (globalThis.location != null) {
|
||||
return stringToDartString(globalThis.location.href);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
stringify: function(o) {
|
||||
return stringToDartString(String(o));
|
||||
},
|
||||
doubleToString: function(v) {
|
||||
return stringToDartString(v.toString());
|
||||
},
|
||||
toFixed: function(double, digits) {
|
||||
return stringToDartString(double.toFixed(digits));
|
||||
},
|
||||
toExponential: function(double, fractionDigits) {
|
||||
return stringToDartString(double.toExponential(fractionDigits));
|
||||
},
|
||||
toPrecision: function(double, precision) {
|
||||
return stringToDartString(double.toPrecision(precision));
|
||||
},
|
||||
parseDouble: function(source) {
|
||||
// Notice that JS parseFloat accepts garbage at the end of the string.
|
||||
// Accept only:
|
||||
// - [+/-]NaN
|
||||
// - [+/-]Infinity
|
||||
// - a Dart double literal
|
||||
// We do allow leading or trailing whitespace.
|
||||
const jsSource = stringFromDartString(source);
|
||||
if (!/^\s*[+-]?(?:Infinity|NaN|(?:\.\d+|\d+(?:\.\d*)?)(?:[eE][+-]?\d+)?)\s*$/.test(jsSource)) {
|
||||
return NaN;
|
||||
}
|
||||
return parseFloat(jsSource);
|
||||
},
|
||||
quoteStringForRegExp: function(string) {
|
||||
// We specialize this method in the runtime to avoid the overhead of
|
||||
// jumping back and forth between JS and Dart. This method is optimized
|
||||
// to test before replacement, which should be much faster. This might
|
||||
// be worth measuring in real world use cases though.
|
||||
let jsString = stringFromDartString(string);
|
||||
if (/[[\]{}()*+?.\\^$|]/.test(jsString)) {
|
||||
jsString = jsString.replace(/[[\]{}()*+?.\\^$|]/g, '\\$&');
|
||||
}
|
||||
return stringToDartString(jsString);
|
||||
},
|
||||
areEqualInJS: function(l, r) {
|
||||
return l === r;
|
||||
},
|
||||
promiseThen: function(promise, successFunc, failureFunc) {
|
||||
promise.then(successFunc, failureFunc);
|
||||
},
|
||||
performanceNow: function() {
|
||||
return performance.now();
|
||||
},
|
||||
''';
|
||||
|
||||
// We break inside the 'dart2wasm' object to enable injection of methods. We
|
||||
|
|
|
@ -624,9 +624,12 @@ class _JSLowerer extends Transformer {
|
|||
}
|
||||
}
|
||||
|
||||
Procedure _getEnclosingProcedure(TreeNode node) {
|
||||
Procedure? _tryGetEnclosingProcedure(TreeNode? node) {
|
||||
while (node is! Procedure) {
|
||||
node = node.parent!;
|
||||
node = node?.parent;
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
@ -638,7 +641,10 @@ class _JSLowerer extends Transformer {
|
|||
/// 3) All of the arguments to `inlineJS` are [VariableGet]s. (this is
|
||||
/// checked by [_expandInlineJS]).
|
||||
bool _shouldReplaceEnclosingProcedure(StaticInvocation node) {
|
||||
Procedure enclosingProcedure = _getEnclosingProcedure(node);
|
||||
Procedure? enclosingProcedure = _tryGetEnclosingProcedure(node);
|
||||
if (enclosingProcedure == null) {
|
||||
return false;
|
||||
}
|
||||
Statement enclosingBody = enclosingProcedure.function.body!;
|
||||
Expression? expression;
|
||||
if (enclosingBody is ReturnStatement) {
|
||||
|
@ -686,7 +692,7 @@ class _JSLowerer extends Transformer {
|
|||
Procedure dartProcedure;
|
||||
Expression result;
|
||||
if (_replaceProcedureWithInlineJS) {
|
||||
dartProcedure = _getEnclosingProcedure(node);
|
||||
dartProcedure = _tryGetEnclosingProcedure(node)!;
|
||||
result = InvalidExpression("Unreachable");
|
||||
} else {
|
||||
dartProcedure = _addInteropProcedure(
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
// Resolving the `Promise` causes the suspended execution to resume.
|
||||
|
||||
import 'dart:_internal' show patch, scheduleCallback, unsafeCastOpaque;
|
||||
import 'dart:_js_helper' show JS;
|
||||
|
||||
import 'dart:wasm';
|
||||
|
||||
|
@ -61,9 +62,12 @@ Future<T> _asyncHelper<T>(WasmStructRef args) {
|
|||
return completer.future;
|
||||
}
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.callAsyncBridge")
|
||||
external void _callAsyncBridge(
|
||||
WasmStructRef args, Completer<Object?> completer);
|
||||
void _callAsyncBridge(WasmStructRef args, Completer<Object?> completer) =>
|
||||
// This trampoline is needed because [asyncBridge] is a function wrapped
|
||||
// by `returnPromiseOnSuspend`, and the stack-switching functionality of
|
||||
// that wrapper is implemented as part of the export adapter.
|
||||
JS<void>(
|
||||
"(args, completer) => asyncBridge(args, completer)", args, completer);
|
||||
|
||||
@pragma("wasm:export", "\$asyncBridge")
|
||||
WasmAnyRef? _asyncBridge(
|
||||
|
@ -106,8 +110,15 @@ Object? _awaitHelper(Object? operand, WasmExternRef? stack) {
|
|||
return result;
|
||||
}
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.futurePromise")
|
||||
external Object? _futurePromise(WasmExternRef? stack, Future<Object?> future);
|
||||
Object? _futurePromise(WasmExternRef? stack, Future<Object?> future) =>
|
||||
JS<Object?>("""new WebAssembly.Function(
|
||||
{parameters: ['externref', 'externref'], results: ['externref']},
|
||||
function(future) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
dartInstance.exports.\$awaitCallback(future, resolve);
|
||||
});
|
||||
},
|
||||
{suspending: 'first'})""", stack, future);
|
||||
|
||||
@pragma("wasm:export", "\$awaitCallback")
|
||||
void _awaitCallback(Future<Object?> future, WasmExternRef? resolve) {
|
||||
|
@ -118,5 +129,7 @@ void _awaitCallback(Future<Object?> future, WasmExternRef? resolve) {
|
|||
});
|
||||
}
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.callResolve")
|
||||
external void _callResolve(WasmExternRef? resolve, Object? result);
|
||||
void _callResolve(WasmExternRef? resolve, Object? result) =>
|
||||
// This trampoline is needed because [resolve] is a JS function that
|
||||
// can't be called directly from Wasm.
|
||||
JS<void>("(resolve, result) => resolve(result)", resolve, result);
|
||||
|
|
|
@ -4,9 +4,6 @@
|
|||
|
||||
import "dart:_internal" show patch;
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.parseDouble")
|
||||
external double _parseDoubleJS(String source);
|
||||
|
||||
@patch
|
||||
double _parseDouble(String source, int start, int end) =>
|
||||
_parseDoubleJS(source.substring(start, end));
|
||||
double.parse(source.substring(start, end));
|
||||
|
|
|
@ -30,7 +30,7 @@ import "dart:_internal"
|
|||
|
||||
import "dart:_internal" as _internal show Symbol;
|
||||
|
||||
import 'dart:_js_helper' show JSSyntaxRegExp, quoteStringForRegExp;
|
||||
import 'dart:_js_helper' show JS, JSSyntaxRegExp, quoteStringForRegExp;
|
||||
|
||||
import "dart:collection"
|
||||
show
|
||||
|
|
|
@ -20,16 +20,24 @@ class DateTime {
|
|||
static int _getCurrentMicros() =>
|
||||
(_jsDateNow() * Duration.microsecondsPerMillisecond).toInt();
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.getTimeZoneNameForSeconds")
|
||||
external static String _timeZoneNameForClampedSecondsRaw(
|
||||
double secondsSinceEpoch);
|
||||
static String _timeZoneNameForClampedSecondsRaw(double secondsSinceEpoch) =>
|
||||
JS<String>(r"""secondsSinceEpoch => {
|
||||
const date = new Date(secondsSinceEpoch * 1000);
|
||||
const match = /\((.*)\)/.exec(date.toString());
|
||||
if (match == null) {
|
||||
// This should never happen on any recent browser.
|
||||
return '';
|
||||
}
|
||||
return stringToDartString(match[1]);
|
||||
}""", secondsSinceEpoch);
|
||||
|
||||
static String _timeZoneNameForClampedSeconds(int secondsSinceEpoch) =>
|
||||
_timeZoneNameForClampedSecondsRaw(secondsSinceEpoch.toDouble());
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.getTimeZoneOffsetInSeconds")
|
||||
external static double _timeZoneOffsetInSecondsForClampedSeconds(
|
||||
double secondsSinceEpoch);
|
||||
static double _timeZoneOffsetInSecondsForClampedSeconds(
|
||||
double secondsSinceEpoch) =>
|
||||
JS<double>("s => new Date(s * 1000).getTimezoneOffset() * 60 ",
|
||||
secondsSinceEpoch);
|
||||
|
||||
static const _MICROSECOND_INDEX = 0;
|
||||
static const _MILLISECOND_INDEX = 1;
|
||||
|
|
|
@ -4,24 +4,6 @@
|
|||
|
||||
part of "core_patch.dart";
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.doubleToString")
|
||||
external String _doubleToString(double v);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.toFixed")
|
||||
external String _toFixed(double d, double digits);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.toExponential")
|
||||
external String _toExponential1(double d);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.toExponential")
|
||||
external String _toExponential2(double d, double fractionDigits);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.toPrecision")
|
||||
external String _toPrecision(double d, double precision);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.parseDouble")
|
||||
external double _parseDouble(String doubleString);
|
||||
|
||||
@patch
|
||||
class double {
|
||||
@patch
|
||||
|
@ -40,7 +22,19 @@ class double {
|
|||
|
||||
@patch
|
||||
static double? tryParse(String source) {
|
||||
double result = _parseDouble(source);
|
||||
// Notice that JS parseFloat accepts garbage at the end of the string.
|
||||
// Accept only:
|
||||
// - [+/-]NaN
|
||||
// - [+/-]Infinity
|
||||
// - a Dart double literal
|
||||
// We do allow leading or trailing whitespace.
|
||||
double result = JS<double>(r"""s => {
|
||||
const jsSource = stringFromDartString(s);
|
||||
if (!/^\s*[+-]?(?:Infinity|NaN|(?:\.\d+|\d+(?:\.\d*)?)(?:[eE][+-]?\d+)?)\s*$/.test(jsSource)) {
|
||||
return NaN;
|
||||
}
|
||||
return parseFloat(jsSource);
|
||||
}""", source);
|
||||
if (result.isNaN) {
|
||||
String trimmed = source.trim();
|
||||
if (!(trimmed == 'NaN' || trimmed == '+NaN' || trimmed == '-NaN')) {
|
||||
|
@ -285,7 +279,7 @@ class _BoxedDouble extends double {
|
|||
return "0.0";
|
||||
}
|
||||
}
|
||||
String result = _doubleToString(value);
|
||||
String result = JS<String>("v => stringToDartString(v.toString())", value);
|
||||
if (this % 1.0 == 0.0 && result.indexOf('e') == -1) {
|
||||
result = '$result.0';
|
||||
}
|
||||
|
@ -324,8 +318,10 @@ class _BoxedDouble extends double {
|
|||
return result;
|
||||
}
|
||||
|
||||
String _toStringAsFixed(int fractionDigits) =>
|
||||
_toFixed(value, fractionDigits.toDouble());
|
||||
String _toStringAsFixed(int fractionDigits) => JS<String>(
|
||||
"(d, digits) => stringToDartString(d.toFixed(digits))",
|
||||
value,
|
||||
fractionDigits.toDouble());
|
||||
|
||||
String toStringAsExponential([int? fractionDigits]) {
|
||||
// See ECMAScript-262, 15.7.4.6 for details.
|
||||
|
@ -352,9 +348,10 @@ class _BoxedDouble extends double {
|
|||
|
||||
String _toStringAsExponential(int? fractionDigits) {
|
||||
if (fractionDigits == null) {
|
||||
return _toExponential1(value);
|
||||
return JS<String>("d => stringToDartString(d.toExponential())", value);
|
||||
} else {
|
||||
return _toExponential2(value, fractionDigits.toDouble());
|
||||
return JS<String>("(d, f) => stringToDartString(d.toExponential(f))",
|
||||
value, fractionDigits.toDouble());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,8 +376,10 @@ class _BoxedDouble extends double {
|
|||
return result;
|
||||
}
|
||||
|
||||
String _toStringAsPrecision(int fractionDigits) =>
|
||||
_toPrecision(value, fractionDigits.toDouble());
|
||||
String _toStringAsPrecision(int fractionDigits) => JS<String>(
|
||||
"(d, precision) => stringToDartString(d.toPrecision(precision))",
|
||||
value,
|
||||
fractionDigits.toDouble());
|
||||
|
||||
// Order is: NaN > Infinity > ... > 0.0 > -0.0 > ... > -Infinity.
|
||||
int compareTo(num other) {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import "dart:_js_helper" show JS;
|
||||
import "dart:typed_data" show Uint8List;
|
||||
|
||||
part "class_id.dart";
|
||||
|
@ -164,8 +165,12 @@ void _invokeMain(Function main) {
|
|||
}
|
||||
|
||||
// Schedule a callback from JS via setTimeout.
|
||||
@pragma("wasm:import", "dart2wasm.scheduleCallback")
|
||||
external void scheduleCallback(double millis, dynamic Function() callback);
|
||||
void scheduleCallback(double millis, dynamic Function() callback) {
|
||||
JS<void>(r"""(ms, c) =>
|
||||
setTimeout(
|
||||
() => dartInstance.exports.$invokeCallback(c),ms)""", millis,
|
||||
callback);
|
||||
}
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.jsonEncode")
|
||||
external String jsonEncode(String object);
|
||||
String jsonEncode(String object) => JS<String>(
|
||||
"s => stringToDartString(JSON.stringify(stringFromDartString(s)))", object);
|
||||
|
|
|
@ -146,186 +146,175 @@ Object jsObjectToDartObject(WasmExternRef? ref) =>
|
|||
WasmExternRef jsObjectFromDartObject(Object object) =>
|
||||
unsafeCastOpaque<WasmAnyRef>(object).externalize();
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSUndefined")
|
||||
external bool isJSUndefined(WasmExternRef? o);
|
||||
bool isJSUndefined(WasmExternRef? o) => JS<bool>('o => o === undefined', o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSBoolean")
|
||||
external bool isJSBoolean(WasmExternRef? o);
|
||||
bool isJSBoolean(WasmExternRef? o) =>
|
||||
JS<bool>("o => typeof o === 'boolean'", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSNumber")
|
||||
external bool isJSNumber(WasmExternRef? o);
|
||||
bool isJSNumber(WasmExternRef? o) => JS<bool>("o => typeof o === 'number'", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSBigInt")
|
||||
external bool isJSBigInt(WasmExternRef? o);
|
||||
bool isJSBigInt(WasmExternRef? o) => JS<bool>("o => typeof o === 'bigint'", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSString")
|
||||
external bool isJSString(WasmExternRef? o);
|
||||
bool isJSString(WasmExternRef? o) => JS<bool>("o => typeof o === 'string'", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSSymbol")
|
||||
external bool isJSSymbol(WasmExternRef? o);
|
||||
bool isJSSymbol(WasmExternRef? o) => JS<bool>("o => typeof o === 'symbol'", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSFunction")
|
||||
external bool isJSFunction(WasmExternRef? o);
|
||||
bool isJSFunction(WasmExternRef? o) =>
|
||||
JS<bool>("o => typeof o === 'function'", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSInt8Array")
|
||||
external bool isJSInt8Array(WasmExternRef? object);
|
||||
bool isJSInt8Array(WasmExternRef? o) =>
|
||||
JS<bool>("o => o instanceof Int8Array", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSUint8Array")
|
||||
external bool isJSUint8Array(WasmExternRef? object);
|
||||
bool isJSUint8Array(WasmExternRef? o) =>
|
||||
JS<bool>("o => o instanceof Uint8Array", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSUint8ClampedArray")
|
||||
external bool isJSUint8ClampedArray(WasmExternRef? object);
|
||||
bool isJSUint8ClampedArray(WasmExternRef? o) =>
|
||||
JS<bool>("o => o instanceof Uint8ClampedArray", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSInt16Array")
|
||||
external bool isJSInt16Array(WasmExternRef? object);
|
||||
bool isJSInt16Array(WasmExternRef? o) =>
|
||||
JS<bool>("o => o instanceof Int16Array", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSUint16Array")
|
||||
external bool isJSUint16Array(WasmExternRef? object);
|
||||
bool isJSUint16Array(WasmExternRef? o) =>
|
||||
JS<bool>("o => o instanceof Uint16Array", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSInt32Array")
|
||||
external bool isJSInt32Array(WasmExternRef? object);
|
||||
bool isJSInt32Array(WasmExternRef? o) =>
|
||||
JS<bool>("o => o instanceof Int32Array", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSUint32Array")
|
||||
external bool isJSUint32Array(WasmExternRef? object);
|
||||
bool isJSUint32Array(WasmExternRef? o) =>
|
||||
JS<bool>("o => o instanceof Uint32Array", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSFloat32Array")
|
||||
external bool isJSFloat32Array(WasmExternRef? object);
|
||||
bool isJSFloat32Array(WasmExternRef? o) =>
|
||||
JS<bool>("o => o instanceof Float32Array", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSFloat64Array")
|
||||
external bool isJSFloat64Array(WasmExternRef? object);
|
||||
bool isJSFloat64Array(WasmExternRef? o) =>
|
||||
JS<bool>("o => o instanceof Float64Array", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSArrayBuffer")
|
||||
external bool isJSArrayBuffer(WasmExternRef? object);
|
||||
bool isJSArrayBuffer(WasmExternRef? o) =>
|
||||
JS<bool>("o => o instanceof ArrayBuffer", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSDataView")
|
||||
external bool isJSDataView(WasmExternRef? object);
|
||||
bool isJSDataView(WasmExternRef? o) =>
|
||||
JS<bool>("o => o instanceof DataView", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSArray")
|
||||
external bool isJSArray(WasmExternRef? o);
|
||||
bool isJSArray(WasmExternRef? o) => JS<bool>("o => o instanceof Array", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSWrappedDartFunction")
|
||||
external bool isJSWrappedDartFunction(WasmExternRef? o);
|
||||
bool isJSWrappedDartFunction(WasmExternRef? o) => JS<bool>(
|
||||
"o => typeof o === 'function' && o[jsWrappedDartFunctionSymbol] === true",
|
||||
o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSObject")
|
||||
external bool isJSObject(WasmExternRef? o);
|
||||
bool isJSObject(WasmExternRef? o) => JS<bool>("o => o instanceof Object", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSSimpleObject")
|
||||
external bool isJSSimpleObject(WasmExternRef? o);
|
||||
bool isJSSimpleObject(WasmExternRef? o) => JS<bool>("""o => {
|
||||
const proto = Object.getPrototypeOf(o);
|
||||
return proto === Object.prototype || proto === null;
|
||||
}""", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isJSRegExp")
|
||||
external bool isJSRegExp(WasmExternRef? object);
|
||||
bool isJSRegExp(WasmExternRef? o) => JS<bool>("o => o instanceof RegExp", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.areEqualInJS")
|
||||
external bool areEqualInJS(WasmExternRef? l, WasmExternRef? r);
|
||||
bool areEqualInJS(WasmExternRef? l, WasmExternRef? r) =>
|
||||
JS<bool>("(l, r) => l === r", l, r);
|
||||
|
||||
// The JS runtime will run helpful conversion routines between refs and bool /
|
||||
// double. In the longer term hopefully we can find a way to avoid the round
|
||||
// trip.
|
||||
@pragma("wasm:import", "dart2wasm.roundtrip")
|
||||
external double toDartNumber(WasmExternRef? ref);
|
||||
double toDartNumber(WasmExternRef? o) => JS<double>("o => o", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.roundtrip")
|
||||
external WasmExternRef? toJSNumber(double d);
|
||||
WasmExternRef? toJSNumber(double o) => JS<WasmExternRef?>("o => o", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.roundtrip")
|
||||
external bool toDartBool(WasmExternRef? ref);
|
||||
bool toDartBool(WasmExternRef? o) => JS<bool>("o => o", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.toJSBoolean")
|
||||
external WasmExternRef? toJSBoolean(bool b);
|
||||
WasmExternRef? toJSBoolean(bool b) => JS<WasmExternRef?>("b => !!b", b);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.objectLength")
|
||||
external double objectLength(WasmExternRef? ref);
|
||||
double objectLength(WasmExternRef? o) => JS<double>("o => o.length", o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.objectReadIndex")
|
||||
external WasmExternRef? objectReadIndex(WasmExternRef? ref, int index);
|
||||
WasmExternRef? objectReadIndex(WasmExternRef? o, double index) =>
|
||||
JS<WasmExternRef?>("(o, i) => o[i]", o, index);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.unwrapJSWrappedDartFunction")
|
||||
external Object? unwrapJSWrappedDartFunction(WasmExternRef? f);
|
||||
Object? unwrapJSWrappedDartFunction(WasmExternRef? f) =>
|
||||
JS<Object?>("f => f.dartFunction", f);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.int8ArrayFromDartInt8List")
|
||||
external WasmExternRef? jsInt8ArrayFromDartInt8List(Int8List list);
|
||||
WasmExternRef? jsInt8ArrayFromDartInt8List(Int8List l) =>
|
||||
JS<WasmExternRef?>('l => arrayFromDartList(Int8Array, l)', l);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.uint8ArrayFromDartUint8List")
|
||||
external WasmExternRef? jsUint8ArrayFromDartUint8List(Uint8List list);
|
||||
WasmExternRef? jsUint8ArrayFromDartUint8List(Uint8List l) =>
|
||||
JS<WasmExternRef?>('l => arrayFromDartList(Uint8Array, l)', l);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.uint8ClampedArrayFromDartUint8ClampedList")
|
||||
external WasmExternRef? jsUint8ClampedArrayFromDartUint8ClampedList(
|
||||
Uint8ClampedList list);
|
||||
WasmExternRef? jsUint8ClampedArrayFromDartUint8ClampedList(
|
||||
Uint8ClampedList l) =>
|
||||
JS<WasmExternRef?>('l => arrayFromDartList(Uint8ClampedArray, l)', l);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.int16ArrayFromDartInt16List")
|
||||
external WasmExternRef? jsInt16ArrayFromDartInt16List(Int16List list);
|
||||
WasmExternRef? jsInt16ArrayFromDartInt16List(Int16List l) =>
|
||||
JS<WasmExternRef?>('l => arrayFromDartList(Int16Array, l)', l);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.uint16ArrayFromDartUint16List")
|
||||
external WasmExternRef? jsUint16ArrayFromDartUint16List(Uint16List list);
|
||||
WasmExternRef? jsUint16ArrayFromDartUint16List(Uint16List l) =>
|
||||
JS<WasmExternRef?>('l => arrayFromDartList(Uint16Array, l)', l);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.int32ArrayFromDartInt32List")
|
||||
external WasmExternRef? jsInt32ArrayFromDartInt32List(Int32List list);
|
||||
WasmExternRef? jsInt32ArrayFromDartInt32List(Int32List l) =>
|
||||
JS<WasmExternRef?>('l => arrayFromDartList(Int32Array, l)', l);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.uint32ArrayFromDartUint32List")
|
||||
external WasmExternRef? jsUint32ArrayFromDartUint32List(Uint32List list);
|
||||
WasmExternRef? jsUint32ArrayFromDartUint32List(Uint32List l) =>
|
||||
JS<WasmExternRef?>('l => arrayFromDartList(Uint32Array, l)', l);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.float32ArrayFromDartFloat32List")
|
||||
external WasmExternRef? jsFloat32ArrayFromDartFloat32List(Float32List list);
|
||||
WasmExternRef? jsFloat32ArrayFromDartFloat32List(Float32List l) =>
|
||||
JS<WasmExternRef?>('l => arrayFromDartList(Float32Array, l)', l);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.float64ArrayFromDartFloat64List")
|
||||
external WasmExternRef? jsFloat64ArrayFromDartFloat64List(Float64List list);
|
||||
WasmExternRef? jsFloat64ArrayFromDartFloat64List(Float64List l) =>
|
||||
JS<WasmExternRef?>('l => arrayFromDartList(Float64Array, l)', l);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.dataViewFromDartByteData")
|
||||
external WasmExternRef? jsDataViewFromDartByteData(
|
||||
ByteData data, double byteLength);
|
||||
WasmExternRef? jsDataViewFromDartByteData(ByteData data, double length) =>
|
||||
JS<WasmExternRef?>("""(data, length) => {
|
||||
const view = new DataView(new ArrayBuffer(length));
|
||||
for (let i = 0; i < length; i++) {
|
||||
view.setUint8(i, dartInstance.exports.\$byteDataGetUint8(data, i));
|
||||
}
|
||||
return view;
|
||||
}""", data, length);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.arrayFromDartList")
|
||||
external WasmExternRef? jsArrayFromDartList(List<Object?> list);
|
||||
WasmExternRef? jsArrayFromDartList(List<Object?> l) =>
|
||||
JS<WasmExternRef?>('l => arrayFromDartList(Array, l)', l);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.stringFromDartString")
|
||||
external WasmExternRef? jsStringFromDartString(String string);
|
||||
WasmExternRef? jsStringFromDartString(String s) =>
|
||||
JS<WasmExternRef?>('stringFromDartString', s);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.stringToDartString")
|
||||
external String jsStringToDartString(WasmExternRef? string);
|
||||
String jsStringToDartString(WasmExternRef? s) =>
|
||||
JS<String>('stringToDartString', s);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.eval")
|
||||
external void evalRaw(WasmExternRef? code);
|
||||
WasmExternRef? newObjectRaw() => JS<WasmExternRef?>('() => ({})');
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.newObject")
|
||||
external WasmExternRef? newObjectRaw();
|
||||
WasmExternRef? newArrayRaw() => JS<WasmExternRef?>('() => []');
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.newArray")
|
||||
external WasmExternRef? newArrayRaw();
|
||||
WasmExternRef? globalThisRaw() => JS<WasmExternRef?>('() => globalThis');
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.globalThis")
|
||||
external WasmExternRef? globalThisRaw();
|
||||
WasmExternRef? callConstructorVarArgsRaw(
|
||||
WasmExternRef? o, WasmExternRef? args) =>
|
||||
// Apply bind to the constructor. We pass `null` as the first argument
|
||||
// to `bind.apply` because this is `bind`'s unused context
|
||||
// argument(`new` will explicitly create a new context).
|
||||
JS<WasmExternRef?>("""(constructor, args) => {
|
||||
const factoryFunction = constructor.bind.apply(
|
||||
constructor, [null, ...args]);
|
||||
return new factoryFunction();
|
||||
}""", o, args);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.callConstructorVarArgs")
|
||||
external WasmExternRef? callConstructorVarArgsRaw(
|
||||
WasmExternRef? o, WasmExternRef? args);
|
||||
bool hasPropertyRaw(WasmExternRef? o, WasmExternRef? p) =>
|
||||
JS<bool>("(o, p) => p in o", o, p);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.safeCallConstructorVarArgs")
|
||||
external WasmExternRef? safeCallConstructorVarArgsRaw(
|
||||
WasmExternRef? o, WasmExternRef? args);
|
||||
WasmExternRef? getPropertyRaw(WasmExternRef? o, WasmExternRef? p) =>
|
||||
JS<WasmExternRef?>("(o, p) => o[p]", o, p);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.hasProperty")
|
||||
external bool hasPropertyRaw(WasmExternRef? o, WasmExternRef? name);
|
||||
WasmExternRef? setPropertyRaw(
|
||||
WasmExternRef? o, WasmExternRef? p, WasmExternRef? v) =>
|
||||
JS<WasmExternRef?>("(o, p, v) => o[p] = v", o, p, v);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.getProperty")
|
||||
external WasmExternRef? getPropertyRaw(WasmExternRef? o, WasmExternRef? name);
|
||||
WasmExternRef? callMethodVarArgsRaw(
|
||||
WasmExternRef? o, WasmExternRef? method, WasmExternRef? args) =>
|
||||
JS<WasmExternRef?>("(o, m, a) => o[m].apply(o, a)", o, method, args);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.setProperty")
|
||||
external WasmExternRef? setPropertyRaw(
|
||||
WasmExternRef? o, WasmExternRef? name, WasmExternRef? value);
|
||||
String stringify(WasmExternRef? object) =>
|
||||
JS<String>("o => stringToDartString(String(o))", object);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.callMethodVarArgs")
|
||||
external WasmExternRef? callMethodVarArgsRaw(
|
||||
WasmExternRef? o, WasmExternRef? method, WasmExternRef? args);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.stringify")
|
||||
external String stringify(WasmExternRef? object);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.objectKeys")
|
||||
external WasmExternRef? objectKeysRaw(WasmExternRef? o);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.promiseThen")
|
||||
external void promiseThen(WasmExternRef? promise, WasmExternRef? successFunc,
|
||||
WasmExternRef? failureFunc);
|
||||
void promiseThen(WasmExternRef? promise, WasmExternRef? successFunc,
|
||||
WasmExternRef? failureFunc) =>
|
||||
JS<void>("(p, s, f) => p.then(s, f)", promise, successFunc, failureFunc);
|
||||
|
||||
// Currently, `allowInterop` returns a Function type. This is unfortunate for
|
||||
// Dart2wasm because it means arbitrary Dart functions can flow to JS util
|
||||
|
@ -493,7 +482,7 @@ List<double> jsFloatTypedArrayToDartFloatTypedData(
|
|||
int length = objectLength(ref).toInt();
|
||||
List<double> list = makeTypedData(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
list[i] = toDartNumber(objectReadIndex(ref, i));
|
||||
list[i] = toDartNumber(objectReadIndex(ref, i.toDouble()));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
@ -503,13 +492,14 @@ List<int> jsIntTypedArrayToDartIntTypedData(
|
|||
int length = objectLength(ref).toInt();
|
||||
List<int> list = makeTypedData(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
list[i] = toDartNumber(objectReadIndex(ref, i)).toInt();
|
||||
list[i] = toDartNumber(objectReadIndex(ref, i.toDouble())).toInt();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
List<Object?> toDartList(WasmExternRef? ref) => List<Object?>.generate(
|
||||
objectLength(ref).round(), (int n) => dartifyRaw(objectReadIndex(ref, n)));
|
||||
objectLength(ref).round(),
|
||||
(int n) => dartifyRaw(objectReadIndex(ref, n.toDouble())));
|
||||
|
||||
// These two trivial helpers are needed to work around an issue with tearing off
|
||||
// functions that take / return [WasmExternRef].
|
||||
|
|
|
@ -176,8 +176,9 @@ Object? objectGetPrototypeOf(Object? object) => throw 'unimplemented';
|
|||
Object? get objectPrototype => throw 'unimplemented';
|
||||
|
||||
@patch
|
||||
List<Object?> objectKeys(Object? object) =>
|
||||
dartifyRaw(objectKeysRaw(jsifyRaw(object))) as List<Object?>;
|
||||
List<Object?> objectKeys(Object? o) =>
|
||||
dartifyRaw(JS<WasmExternRef?>('o => Object.keys(o)', jsifyRaw(o)))
|
||||
as List<Object?>;
|
||||
|
||||
@patch
|
||||
Object? dartify(Object? object) {
|
||||
|
@ -245,7 +246,7 @@ Object? dartify(Object? object) {
|
|||
convertedObjects[o] = dartList;
|
||||
int length = getProperty<double>(o, 'length').toInt();
|
||||
for (int i = 0; i < length; i++) {
|
||||
dartList.add(convert(JSValue.box(objectReadIndex(ref, i))));
|
||||
dartList.add(convert(JSValue.box(objectReadIndex(ref, i.toDouble()))));
|
||||
}
|
||||
return dartList;
|
||||
} else {
|
||||
|
|
|
@ -5,5 +5,5 @@
|
|||
part of "internal_patch.dart";
|
||||
|
||||
@patch
|
||||
@pragma("wasm:import", "dart2wasm.printToConsole")
|
||||
external void printToConsole(String line);
|
||||
void printToConsole(String line) =>
|
||||
JS<void>('s => console.log(stringFromDartString(s))');
|
||||
|
|
|
@ -11,8 +11,17 @@ part of dart._js_helper;
|
|||
|
||||
/// Returns a string for a RegExp pattern that matches [string]. This is done by
|
||||
/// escaping all RegExp metacharacters.
|
||||
@pragma('wasm:import', 'dart2wasm.quoteStringForRegExp')
|
||||
external String quoteStringForRegExp(String string);
|
||||
String quoteStringForRegExp(String string) =>
|
||||
// This method is optimized to test before replacement, which should be
|
||||
// much faster. This might be worth measuring in real world use cases
|
||||
// though.
|
||||
JS<String>(r"""s => {
|
||||
let jsString = stringFromDartString(s);
|
||||
if (/[[\]{}()*+?.\\^$|]/.test(jsString)) {
|
||||
jsString = jsString.replace(/[[\]{}()*+?.\\^$|]/g, '\\$&');
|
||||
}
|
||||
return stringToDartString(jsString);
|
||||
}""", string);
|
||||
|
||||
class JSNativeMatch extends JSArray {
|
||||
JSNativeMatch(WasmExternRef ref) : super(ref);
|
||||
|
@ -99,8 +108,13 @@ class JSSyntaxRegExp implements RegExp {
|
|||
String modifiers = '$m$i$u$s$g';
|
||||
// The call to create the regexp is wrapped in a try catch so we can
|
||||
// reformat the exception if need be.
|
||||
WasmExternRef? result = safeCallConstructorVarArgsRaw(
|
||||
getConstructorRaw('RegExp'), [source, modifiers].toExternRef());
|
||||
WasmExternRef? result = JS<WasmExternRef?>("""(s, m) => {
|
||||
try {
|
||||
return new RegExp(s, m);
|
||||
} catch (e) {
|
||||
return String(e);
|
||||
}
|
||||
}""", source.toExternRef(), modifiers.toExternRef());
|
||||
if (isJSRegExp(result)) return JSNativeRegExp(result!);
|
||||
// The returned value is the stringified JavaScript exception. Turn it into
|
||||
// a Dart exception.
|
||||
|
|
|
@ -4,14 +4,22 @@
|
|||
|
||||
part of "core_patch.dart";
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.getCurrentStackTrace")
|
||||
external String _getCurrentStackTrace();
|
||||
|
||||
@patch
|
||||
class StackTrace {
|
||||
@patch
|
||||
@pragma("wasm:entry-point")
|
||||
static StackTrace get current {
|
||||
return _StringStackTrace(_getCurrentStackTrace());
|
||||
// `Error` should be supported in most browsers. A possible future
|
||||
// optimization we could do is to just save the `Error` object here, and
|
||||
// stringify the stack trace when it is actually used
|
||||
//
|
||||
// Note: We remove the last three lines of the stack trace to prevent
|
||||
// including `Error`, `getCurrentStackTrace`, and `StackTrace.current` in
|
||||
// the stack trace.
|
||||
return _StringStackTrace(JS<String>(r"""() => {
|
||||
let stackString = new Error().stack.toString();
|
||||
let userStackString = stackString.split('\n').slice(3).join('\n');
|
||||
return stringToDartString(userStackString);
|
||||
}"""));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
|
||||
part of "core_patch.dart";
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.performanceNow")
|
||||
external double _performanceNow();
|
||||
double _performanceNow() => JS<double>("performance.now");
|
||||
|
||||
@patch
|
||||
class Stopwatch {
|
||||
|
|
|
@ -13,11 +13,11 @@ const int _maxLatin1 = 0xff;
|
|||
const int _maxUtf16 = 0xffff;
|
||||
const int _maxUnicode = 0x10ffff;
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.toUpperCase")
|
||||
external String _toUpperCase(String string);
|
||||
String _toUpperCase(String string) => JS<String>(
|
||||
"s => stringToDartString(stringFromDartString(s).toUpperCase())", string);
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.toLowerCase")
|
||||
external String _toLowerCase(String string);
|
||||
String _toLowerCase(String string) => JS<String>(
|
||||
"s => stringToDartString(stringFromDartString(s).toLowerCase())", string);
|
||||
|
||||
@patch
|
||||
class String {
|
||||
|
|
|
@ -4,17 +4,17 @@
|
|||
|
||||
part of "core_patch.dart";
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.isWindows")
|
||||
external bool _isWindowsRaw();
|
||||
|
||||
@pragma("wasm:import", "dart2wasm.getCurrentUri")
|
||||
external String? _currentUriRaw();
|
||||
|
||||
@patch
|
||||
class Uri {
|
||||
@patch
|
||||
static Uri get base {
|
||||
String? currentUri = _currentUriRaw();
|
||||
String? currentUri = JS<String?>("""() => {
|
||||
// On browsers return `globalThis.location.href`
|
||||
if (globalThis.location != null) {
|
||||
return stringToDartString(globalThis.location.href);
|
||||
}
|
||||
return null;
|
||||
}""");
|
||||
if (currentUri != null) {
|
||||
return Uri.parse(currentUri);
|
||||
}
|
||||
|
@ -27,7 +27,11 @@ class _Uri {
|
|||
@patch
|
||||
static bool get _isWindows => _isWindowsCached;
|
||||
|
||||
static final bool _isWindowsCached = _isWindowsRaw();
|
||||
static final bool _isWindowsCached = JS<bool>("""() => {
|
||||
return typeof process != undefined &&
|
||||
Object.prototype.toString.call(process) == "[object process]" &&
|
||||
process.platform == "win32"
|
||||
}""");
|
||||
|
||||
// Matches a String that _uriEncodes to itself regardless of the kind of
|
||||
// component. This corresponds to [_unreservedTable], i.e. characters that
|
||||
|
|
Loading…
Reference in a new issue