diff options
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | quickjs.c | 175 | ||||
-rw-r--r-- | test262_errors.txt | 2 | ||||
-rw-r--r-- | tests/test_builtin.js | 2 | ||||
-rw-r--r-- | tests/test_std.js | 2 |
5 files changed, 152 insertions, 31 deletions
@@ -62,5 +62,5 @@ Optimization ideas: Test262o: 0/11262 errors, 463 excluded Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch) -Result: 60/79202 errors, 1610 excluded, 6738 skipped +Result: 58/79202 errors, 1610 excluded, 6738 skipped Test262 commit: 27622d764767dcb3778784884022c2c7de5769b8 @@ -12127,7 +12127,7 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, case ATOD_TYPE_FLOAT64: { double d; - d = js_atod(buf,NULL, radix, is_float ? 0 : JS_ATOD_INT_ONLY, + d = js_atod(buf, NULL, radix, is_float ? 0 : JS_ATOD_INT_ONLY, &atod_mem); /* return int or float64 */ val = JS_NewFloat64(ctx, d); @@ -21031,11 +21031,6 @@ static __exception int js_parse_string(JSParseState *s, int sep, goto invalid_char; c = *p; if (c < 0x20) { - if (!s->cur_func) { - if (do_throw) - js_parse_error_pos(s, p, "invalid character in a JSON string"); - goto fail; - } if (sep == '`') { if (c == '\r') { if (p[1] == '\n') @@ -21081,8 +21076,6 @@ static __exception int js_parse_string(JSParseState *s, int sep, continue; default: if (c >= '0' && c <= '9') { - if (!s->cur_func) - goto invalid_escape; /* JSON case */ if (!(s->cur_func->js_mode & JS_MODE_STRICT) && sep != '`') goto parse_escape; if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) { @@ -21851,6 +21844,150 @@ static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c) return atom; } +static int json_parse_string(JSParseState *s, const uint8_t **pp, int sep) +{ + const uint8_t *p, *p_next; + int i; + uint32_t c; + StringBuffer b_s, *b = &b_s; + + if (string_buffer_init(s->ctx, b, 32)) + goto fail; + + p = *pp; + for(;;) { + if (p >= s->buf_end) { + goto end_of_input; + } + c = *p++; + if (c == sep) + break; + if (c < 0x20) { + js_parse_error_pos(s, p - 1, "Bad control character in string literal"); + goto fail; + } + if (c == '\\') { + c = *p++; + switch(c) { + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case '\\': break; + case '/': break; + case 'u': + c = 0; + for(i = 0; i < 4; i++) { + int h = from_hex(*p++); + if (h < 0) { + js_parse_error_pos(s, p - 1, "Bad Unicode escape"); + goto fail; + } + c = (c << 4) | h; + } + break; + default: + if (c == sep) + break; + if (p > s->buf_end) + goto end_of_input; + js_parse_error_pos(s, p - 1, "Bad escaped character"); + goto fail; + } + } else + if (c >= 0x80) { + c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); + if (c > 0x10FFFF) { + js_parse_error_pos(s, p - 1, "Bad UTF-8 sequence"); + goto fail; + } + p = p_next; + } + if (string_buffer_putc(b, c)) + goto fail; + } + s->token.val = TOK_STRING; + s->token.u.str.sep = sep; + s->token.u.str.str = string_buffer_end(b); + *pp = p; + return 0; + + end_of_input: + js_parse_error(s, "Unexpected end of JSON input"); + fail: + string_buffer_free(b); + return -1; +} + +static int json_parse_number(JSParseState *s, const uint8_t **pp) +{ + const uint8_t *p = *pp; + const uint8_t *p_start = p; + int radix; + double d; + JSATODTempMem atod_mem; + + if (*p == '+' || *p == '-') + p++; + + if (!is_digit(*p)) + return js_parse_error_pos(s, p, "Unexpected token '%c'", *p_start); + + if (p[0] == '0') { + if (s->ext_json) { + /* also accepts base 16, 8 and 2 prefix for integers */ + radix = 10; + if (p[1] == 'x' || p[1] == 'X') { + p += 2; + radix = 16; + } else if ((p[1] == 'o' || p[1] == 'O')) { + p += 2; + radix = 8; + } else if ((p[1] == 'b' || p[1] == 'B')) { + p += 2; + radix = 2; + } + if (radix != 10) { + /* prefix is present */ + if (to_digit(*p) >= radix) + return js_parse_error_pos(s, p, "Unexpected token '%c'", *p); + d = js_atod((const char *)p_start, (const char **)&p, 0, + JS_ATOD_INT_ONLY | JS_ATOD_ACCEPT_BIN_OCT, &atod_mem); + goto done; + } + } + if (is_digit(p[1])) + return js_parse_error_pos(s, p, "Unexpected number"); + } + + while (is_digit(*p)) + p++; + + if (*p == '.') { + p++; + if (!is_digit(*p)) + return js_parse_error_pos(s, p, "Unterminated fractional number"); + while (is_digit(*p)) + p++; + } + if (*p == 'e' || *p == 'E') { + p++; + if (*p == '+' || *p == '-') + p++; + if (!is_digit(*p)) + return js_parse_error_pos(s, p, "Exponent part is missing a number"); + while (is_digit(*p)) + p++; + } + d = js_atod((const char *)p_start, NULL, 10, 0, &atod_mem); + done: + s->token.val = TOK_NUMBER; + s->token.u.num.val = JS_NewFloat64(s->ctx, d); + *pp = p; + return 0; +} + static __exception int json_next_token(JSParseState *s) { const uint8_t *p; @@ -21882,7 +22019,8 @@ static __exception int json_next_token(JSParseState *s) } /* fall through */ case '\"': - if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p)) + p++; + if (json_parse_string(s, &p, c)) goto fail; break; case '\r': /* accept DOS and MAC newline sequences */ @@ -21999,23 +22137,8 @@ static __exception int json_next_token(JSParseState *s) case '9': /* number */ parse_number: - { - JSValue ret; - int flags, radix; - if (!s->ext_json) { - flags = 0; - radix = 10; - } else { - flags = ATOD_ACCEPT_BIN_OCT; - radix = 0; - } - ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix, - flags); - if (JS_IsException(ret)) - goto fail; - s->token.val = TOK_NUMBER; - s->token.u.num.val = ret; - } + if (json_parse_number(s, &p)) + goto fail; break; default: if (c >= 128) { diff --git a/test262_errors.txt b/test262_errors.txt index e8cd853..d3f06c3 100644 --- a/test262_errors.txt +++ b/test262_errors.txt @@ -12,8 +12,6 @@ test262/test/staging/sm/Function/function-toString-builtin.js:14: Test262Error: }' Expected SameValue(«null», «null») to be false test262/test/staging/sm/Function/implicit-this-in-parameter-expression.js:13: Test262Error: Expected SameValue(«[object Object]», «undefined») to be true test262/test/staging/sm/Function/invalid-parameter-list.js:35: Error: Assertion failed: expected exception SyntaxError, no exception thrown -test262/test/staging/sm/JSON/parse-number-syntax.js:39: Test262Error: parsing string <1.> threw a non-SyntaxError exception: Test262Error: string <1.> shouldn't have parsed as JSON Expected SameValue(«false», «true») to be true Expected SameValue(«true», «false») to be true -test262/test/staging/sm/JSON/parse-syntax-errors-02.js:51: Test262Error: parsing string <["Illegal backslash escape: \x15"]> threw a non-SyntaxError exception: Test262Error: string <["Illegal backslash escape: \x15"]> shouldn't have parsed as JSON Expected SameValue(«false», «true») to be true Expected SameValue(«true», «false») to be true test262/test/staging/sm/Math/cbrt-approx.js:26: Error: got 1.39561242508609, expected a number near 1.3956124250860895 (relative error: 2) test262/test/staging/sm/RegExp/constructor-ordering-2.js:15: Test262Error: Expected SameValue(«false», «true») to be true test262/test/staging/sm/RegExp/regress-613820-1.js:13: Test262Error: Expected SameValue(«"aaa"», «"aa"») to be true diff --git a/tests/test_builtin.js b/tests/test_builtin.js index ff376ec..a541c19 100644 --- a/tests/test_builtin.js +++ b/tests/test_builtin.js @@ -596,7 +596,7 @@ function test_json() ] ]`); - assert_json_error('\n" @\\x"'); + assert_json_error('\n" \\@x"'); assert_json_error('\n{ "a": @x }"'); } diff --git a/tests/test_std.js b/tests/test_std.js index bb942d6..df02f92 100644 --- a/tests/test_std.js +++ b/tests/test_std.js @@ -134,7 +134,7 @@ function test_ext_json() "y":true, // also a comment z2:null, // unquoted property names "a":[+1,0o10,0xa0,], // plus prefix, octal, hexadecimal - "s":"str",} // trailing comma in objects and arrays + "s":'str',} // trailing comma in objects and arrays, single quoted string `; obj = std.parseExtJSON(input); assert(JSON.stringify(obj), expected); |