commit 3a7bef6e06279aaee4ac56c22f9c4136d3c88cff
parent 7bae89a42b206c5aa5d29e7c1d262ebd8ec95e7e
Author: Fabrice Bellard <fabrice@bellard.org>
Date: Wed, 27 Dec 2023 17:16:47 +0100
added String.prototype.isWellFormed and String.prototype.toWellFormed
Diffstat:
3 files changed, 83 insertions(+), 3 deletions(-)
diff --git a/quickjs/TODO b/quickjs/TODO
@@ -63,5 +63,5 @@ Optimization ideas:
Test262o: 0/11262 errors, 463 excluded
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
-Result: 16/76387 errors, 1497 excluded, 8397 skipped
+Result: 16/76419 errors, 1497 excluded, 8381 skipped
Test262 commit: 31126581e7290f9233c29cefd93f66c6ac78f1c9
diff --git a/quickjs/quickjs.c b/quickjs/quickjs.c
@@ -41042,6 +41042,84 @@ static int64_t string_advance_index(JSString *p, int64_t index, BOOL unicode)
return index;
}
+/* return the position of the first invalid character in the string or
+ -1 if none */
+static int js_string_find_invalid_codepoint(JSString *p)
+{
+ int i, c;
+ if (!p->is_wide_char)
+ return -1;
+ for(i = 0; i < p->len; i++) {
+ c = p->u.str16[i];
+ if (c >= 0xD800 && c <= 0xDFFF) {
+ if (c >= 0xDC00 || (i + 1) >= p->len)
+ return i;
+ c = p->u.str16[i + 1];
+ if (c < 0xDC00 || c > 0xDFFF)
+ return i;
+ i++;
+ }
+ }
+ return -1;
+}
+
+static JSValue js_string_isWellFormed(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue str;
+ JSString *p;
+ BOOL ret;
+
+ str = JS_ToStringCheckObject(ctx, this_val);
+ if (JS_IsException(str))
+ return JS_EXCEPTION;
+ p = JS_VALUE_GET_STRING(str);
+ ret = (js_string_find_invalid_codepoint(p) < 0);
+ JS_FreeValue(ctx, str);
+ return JS_NewBool(ctx, ret);
+}
+
+static JSValue js_string_toWellFormed(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue str, ret;
+ JSString *p;
+ int c, i;
+
+ str = JS_ToStringCheckObject(ctx, this_val);
+ if (JS_IsException(str))
+ return JS_EXCEPTION;
+
+ p = JS_VALUE_GET_STRING(str);
+ /* avoid reallocating the string if it is well-formed */
+ i = js_string_find_invalid_codepoint(p);
+ if (i < 0)
+ return str;
+
+ ret = js_new_string16(ctx, p->u.str16, p->len);
+ JS_FreeValue(ctx, str);
+ if (JS_IsException(ret))
+ return JS_EXCEPTION;
+
+ p = JS_VALUE_GET_STRING(ret);
+ for (; i < p->len; i++) {
+ c = p->u.str16[i];
+ if (c >= 0xD800 && c <= 0xDFFF) {
+ if (c >= 0xDC00 || (i + 1) >= p->len) {
+ p->u.str16[i] = 0xFFFD;
+ } else {
+ c = p->u.str16[i + 1];
+ if (c < 0xDC00 || c > 0xDFFF) {
+ p->u.str16[i] = 0xFFFD;
+ } else {
+ i++;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
static JSValue js_string_indexOf(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int lastIndexOf)
{
@@ -42262,6 +42340,8 @@ static const JSCFunctionListEntry js_string_proto_funcs[] = {
JS_CFUNC_MAGIC_DEF("charAt", 1, js_string_charAt, 0 ),
JS_CFUNC_DEF("concat", 1, js_string_concat ),
JS_CFUNC_DEF("codePointAt", 1, js_string_codePointAt ),
+ JS_CFUNC_DEF("isWellFormed", 0, js_string_isWellFormed ),
+ JS_CFUNC_DEF("toWellFormed", 0, js_string_toWellFormed ),
JS_CFUNC_MAGIC_DEF("indexOf", 1, js_string_indexOf, 0 ),
JS_CFUNC_MAGIC_DEF("lastIndexOf", 1, js_string_indexOf, 1 ),
JS_CFUNC_MAGIC_DEF("includes", 1, js_string_includes, 0 ),
diff --git a/quickjs/test262.conf b/quickjs/test262.conf
@@ -169,10 +169,10 @@ String.fromCodePoint
String.prototype.at
String.prototype.endsWith
String.prototype.includes
-String.prototype.isWellFormed=skip
+String.prototype.isWellFormed
String.prototype.matchAll
String.prototype.replaceAll
-String.prototype.toWellFormed=skip
+String.prototype.toWellFormed
String.prototype.trimEnd
String.prototype.trimStart
super