Commit 718f7437 authored by Issack John's avatar Issack John Committed by V8 LUCI CQ

JSON.parse errors made user-friendly

Part of the improve error messages initiative.

Based on a resource of JSON.parse() errors found at
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/JSON_bad_parse

Previously JSON.parse(NaN) would output:
SyntaxError: Unexpected token N in JSON at position 0
Now the output is:
SyntaxError: "NaN" is not valid JSON

Previously JSON.parse("{a:1}") would output:
SyntaxError: Unexpected token a in JSON at position 1
Now the output is:
SyntaxError: Expected property name or '}' in JSON at position 1

Bug: v8:6551
Change-Id: Ic9fad1fdbd295e1302805b81e6603fc526121960
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3513684Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Commit-Queue: Issack John <issackjohn@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#80567}
parent b9420be7
...@@ -481,9 +481,40 @@ namespace internal { ...@@ -481,9 +481,40 @@ namespace internal {
T(InvalidUnusedPrivateStaticMethodAccessedByDebugger, \ T(InvalidUnusedPrivateStaticMethodAccessedByDebugger, \
"Unused static private method '%' cannot be accessed at debug time") \ "Unused static private method '%' cannot be accessed at debug time") \
T(JsonParseUnexpectedEOS, "Unexpected end of JSON input") \ T(JsonParseUnexpectedEOS, "Unexpected end of JSON input") \
T(JsonParseUnexpectedToken, "Unexpected token % in JSON at position %") \
T(JsonParseUnexpectedTokenNumber, "Unexpected number in JSON at position %") \ T(JsonParseUnexpectedTokenNumber, "Unexpected number in JSON at position %") \
T(JsonParseUnexpectedTokenString, "Unexpected string in JSON at position %") \ T(JsonParseUnexpectedTokenString, "Unexpected string in JSON at position %") \
T(JsonParseUnterminatedString, "Unterminated string in JSON at position %") \
T(JsonParseExpectedPropNameOrRBrace, \
"Expected property name or '}' in JSON at position %") \
T(JsonParseExpectedCommaOrRBrack, \
"Expected ',' or ']' after array element in JSON at position %") \
T(JsonParseExpectedCommaOrRBrace, \
"Expected ',' or '}' after property value in JSON at position " \
"%") \
T(JsonParseExpectedDoubleQuotedPropertyName, \
"Expected double-quoted property name in JSON at position %") \
T(JsonParseExponentPartMissingNumber, \
"Exponent part is missing a number in JSON at position %") \
T(JsonParseExpectedColonAfterPropertyName, \
"Expected ':' after property name in JSON at position %") \
T(JsonParseUnterminatedFractionalNumber, \
"Unterminated fractional number in JSON at position %") \
T(JsonParseUnexpectedNonWhiteSpaceCharacter, \
"Unexpected non-whitespace character after JSON at position " \
"%") \
T(JsonParseBadEscapedCharacter, \
"Bad escaped character in JSON at position %") \
T(JsonParseNoNumberAfterMinusSign, \
"No number after minus sign in JSON at position %") \
T(JsonParseShortString, "\"%\" is not valid JSON") \
T(JsonParseUnexpectedTokenShortString, \
"Unexpected token '%', \"%\" is not valid JSON") \
T(JsonParseUnexpectedTokenSurroundStringWithContext, \
"Unexpected token '%', ...\"%\"... is not valid JSON") \
T(JsonParseUnexpectedTokenEndStringWithContext, \
"Unexpected token '%', ...\"%\" is not valid JSON") \
T(JsonParseUnexpectedTokenStartStringWithContext, \
"Unexpected token '%', \"%\"... is not valid JSON") \
T(LabelRedeclaration, "Label '%' has already been declared") \ T(LabelRedeclaration, "Label '%' has already been declared") \
T(LabelledFunctionDeclaration, \ T(LabelledFunctionDeclaration, \
"Labelled function declaration not allowed as the body of a control flow " \ "Labelled function declaration not allowed as the body of a control flow " \
......
...@@ -240,20 +240,75 @@ JsonParser<Char>::JsonParser(Isolate* isolate, Handle<String> source) ...@@ -240,20 +240,75 @@ JsonParser<Char>::JsonParser(Isolate* isolate, Handle<String> source)
} }
template <typename Char> template <typename Char>
void JsonParser<Char>::ReportUnexpectedToken(JsonToken token) { bool JsonParser<Char>::IsSpecialString() {
// Some exception (for example stack overflow) is already pending. // The special cases are undefined, NaN, Infinity, and {} being passed to the
if (isolate_->has_pending_exception()) return; // parse method
// Parse failed. Current character is the unexpected token.
Factory* factory = this->factory();
MessageTemplate message;
int offset = original_source_->IsSlicedString() int offset = original_source_->IsSlicedString()
? SlicedString::cast(*original_source_).offset() ? SlicedString::cast(*original_source_).offset()
: 0; : 0;
int pos = position() - offset; size_t length = original_source_->length();
Handle<Object> arg1 = Handle<Smi>(Smi::FromInt(pos), isolate()); #define CASES(V) \
Handle<Object> arg2; V("[object Object]") \
V("undefined") \
V("Infinity") \
V("NaN")
switch (length) {
#define CASE(n) \
case arraysize(n) - 1: \
return CompareCharsEqual(chars_ + offset, n, arraysize(n) - 1);
CASES(CASE)
default:
return false;
}
#undef CASE
#undef CASES
}
template <typename Char>
MessageTemplate JsonParser<Char>::GetErrorMessageWithEllipses(
Handle<Object>& arg, Handle<Object>& arg2, int pos) {
MessageTemplate message;
Factory* factory = this->factory();
arg = factory->LookupSingleCharacterStringFromCode(*cursor_);
int origin_source_length = original_source_->length();
// only provide context for strings with at least
// kMinOriginalSourceLengthForContext charcacters in length
if (origin_source_length >= kMinOriginalSourceLengthForContext) {
int substring_start = 0;
int substring_end = origin_source_length;
if (pos < kMaxContextCharacters) {
message =
MessageTemplate::kJsonParseUnexpectedTokenStartStringWithContext;
// Output the string followed by elipses
substring_end = pos + kMaxContextCharacters;
} else if (pos >= kMaxContextCharacters &&
pos < origin_source_length - kMaxContextCharacters) {
message =
MessageTemplate::kJsonParseUnexpectedTokenSurroundStringWithContext;
// Add context before and after position of bad token surrounded by
// elipses
substring_start = pos - kMaxContextCharacters;
substring_end = pos + kMaxContextCharacters;
} else {
message = MessageTemplate::kJsonParseUnexpectedTokenEndStringWithContext;
// Add ellipses followed by some context before bad token
substring_start = pos - kMaxContextCharacters;
}
arg2 =
factory->NewSubString(original_source_, substring_start, substring_end);
} else {
arg2 = original_source_;
// Output the entire string without ellipses but provide the token which
// was unexpected
message = MessageTemplate::kJsonParseUnexpectedTokenShortString;
}
return message;
}
template <typename Char>
MessageTemplate JsonParser<Char>::LookUpErrorMessageForJsonToken(
JsonToken token, Handle<Object>& arg, Handle<Object>& arg2, int pos) {
MessageTemplate message;
switch (token) { switch (token) {
case JsonToken::EOS: case JsonToken::EOS:
message = MessageTemplate::kJsonParseUnexpectedEOS; message = MessageTemplate::kJsonParseUnexpectedEOS;
...@@ -265,11 +320,36 @@ void JsonParser<Char>::ReportUnexpectedToken(JsonToken token) { ...@@ -265,11 +320,36 @@ void JsonParser<Char>::ReportUnexpectedToken(JsonToken token) {
message = MessageTemplate::kJsonParseUnexpectedTokenString; message = MessageTemplate::kJsonParseUnexpectedTokenString;
break; break;
default: default:
message = MessageTemplate::kJsonParseUnexpectedToken; // Output entire string without ellipses and don't provide the token
arg2 = arg1; // that was unexpected because it makes the error messages more confusing
arg1 = factory->LookupSingleCharacterStringFromCode(*cursor_); if (IsSpecialString()) {
break; arg = original_source_;
message = MessageTemplate::kJsonParseShortString;
} else {
message = GetErrorMessageWithEllipses(arg, arg2, pos);
}
} }
return message;
}
template <typename Char>
void JsonParser<Char>::ReportUnexpectedToken(
JsonToken token, base::Optional<MessageTemplate> errorMessage) {
// Some exception (for example stack overflow) is already pending.
if (isolate_->has_pending_exception()) return;
// Parse failed. Current character is the unexpected token.
Factory* factory = this->factory();
int offset = original_source_->IsSlicedString()
? SlicedString::cast(*original_source_).offset()
: 0;
int pos = position() - offset;
Handle<Object> arg(Smi::FromInt(pos), isolate());
Handle<Object> arg2;
MessageTemplate message =
errorMessage ? errorMessage.value()
: LookUpErrorMessageForJsonToken(token, arg, arg2, pos);
Handle<Script> script(factory->NewScript(original_source_)); Handle<Script> script(factory->NewScript(original_source_));
if (isolate()->NeedsSourcePositionsForProfiling()) { if (isolate()->NeedsSourcePositionsForProfiling()) {
...@@ -290,7 +370,7 @@ void JsonParser<Char>::ReportUnexpectedToken(JsonToken token) { ...@@ -290,7 +370,7 @@ void JsonParser<Char>::ReportUnexpectedToken(JsonToken token) {
// separated source file. // separated source file.
isolate()->debug()->OnCompileError(script); isolate()->debug()->OnCompileError(script);
MessageLocation location(script, pos, pos + 1); MessageLocation location(script, pos, pos + 1);
isolate()->ThrowAt(factory->NewSyntaxError(message, arg1, arg2), &location); isolate()->ThrowAt(factory->NewSyntaxError(message, arg, arg2), &location);
// Move the cursor to the end so we won't be able to proceed parsing. // Move the cursor to the end so we won't be able to proceed parsing.
cursor_ = end_; cursor_ = end_;
...@@ -325,7 +405,9 @@ JsonParser<Char>::~JsonParser() { ...@@ -325,7 +405,9 @@ JsonParser<Char>::~JsonParser() {
template <typename Char> template <typename Char>
MaybeHandle<Object> JsonParser<Char>::ParseJson() { MaybeHandle<Object> JsonParser<Char>::ParseJson() {
MaybeHandle<Object> result = ParseJsonValue(); MaybeHandle<Object> result = ParseJsonValue();
if (!Check(JsonToken::EOS)) ReportUnexpectedToken(peek()); if (!Check(JsonToken::EOS))
ReportUnexpectedToken(
peek(), MessageTemplate::kJsonParseUnexpectedNonWhiteSpaceCharacter);
if (isolate_->has_pending_exception()) return MaybeHandle<Object>(); if (isolate_->has_pending_exception()) return MaybeHandle<Object>();
return result; return result;
} }
...@@ -751,10 +833,12 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { ...@@ -751,10 +833,12 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() {
property_stack.size()); property_stack.size());
// Parse the property key. // Parse the property key.
ExpectNext(JsonToken::STRING); ExpectNext(JsonToken::STRING,
MessageTemplate::kJsonParseExpectedPropNameOrRBrace);
property_stack.emplace_back(ScanJsonPropertyKey(&cont)); property_stack.emplace_back(ScanJsonPropertyKey(&cont));
ExpectNext(JsonToken::COLON); ExpectNext(JsonToken::COLON,
MessageTemplate::kJsonParseExpectedColonAfterPropertyName);
// Continue to start producing the first property value. // Continue to start producing the first property value.
continue; continue;
...@@ -829,7 +913,9 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { ...@@ -829,7 +913,9 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() {
if (V8_LIKELY(Check(JsonToken::COMMA))) { if (V8_LIKELY(Check(JsonToken::COMMA))) {
// Parse the property key. // Parse the property key.
ExpectNext(JsonToken::STRING); ExpectNext(
JsonToken::STRING,
MessageTemplate::kJsonParseExpectedDoubleQuotedPropertyName);
property_stack.emplace_back(ScanJsonPropertyKey(&cont)); property_stack.emplace_back(ScanJsonPropertyKey(&cont));
ExpectNext(JsonToken::COLON); ExpectNext(JsonToken::COLON);
...@@ -855,7 +941,8 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { ...@@ -855,7 +941,8 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() {
} }
value = BuildJsonObject(cont, property_stack, feedback); value = BuildJsonObject(cont, property_stack, feedback);
property_stack.resize_no_init(cont.index); property_stack.resize_no_init(cont.index);
Expect(JsonToken::RBRACE); Expect(JsonToken::RBRACE,
MessageTemplate::kJsonParseExpectedCommaOrRBrace);
// Return the object. // Return the object.
value = cont.scope.CloseAndEscape(value); value = cont.scope.CloseAndEscape(value);
...@@ -874,7 +961,8 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() { ...@@ -874,7 +961,8 @@ MaybeHandle<Object> JsonParser<Char>::ParseJsonValue() {
value = BuildJsonArray(cont, element_stack); value = BuildJsonArray(cont, element_stack);
element_stack.resize_no_init(cont.index); element_stack.resize_no_init(cont.index);
Expect(JsonToken::RBRACK); Expect(JsonToken::RBRACK,
MessageTemplate::kJsonParseExpectedCommaOrRBrack);
// Return the array. // Return the array.
value = cont.scope.CloseAndEscape(value); value = cont.scope.CloseAndEscape(value);
...@@ -933,7 +1021,9 @@ Handle<Object> JsonParser<Char>::ParseJsonNumber() { ...@@ -933,7 +1021,9 @@ Handle<Object> JsonParser<Char>::ParseJsonNumber() {
AdvanceToNonDecimal(); AdvanceToNonDecimal();
if (V8_UNLIKELY(smi_start == cursor_)) { if (V8_UNLIKELY(smi_start == cursor_)) {
AllowGarbageCollection allow_before_exception; AllowGarbageCollection allow_before_exception;
ReportUnexpectedCharacter(CurrentCharacter()); ReportUnexpectedToken(
JsonToken::ILLEGAL,
MessageTemplate::kJsonParseNoNumberAfterMinusSign);
return handle(Smi::FromInt(0), isolate_); return handle(Smi::FromInt(0), isolate_);
} }
c = CurrentCharacter(); c = CurrentCharacter();
...@@ -959,7 +1049,9 @@ Handle<Object> JsonParser<Char>::ParseJsonNumber() { ...@@ -959,7 +1049,9 @@ Handle<Object> JsonParser<Char>::ParseJsonNumber() {
c = NextCharacter(); c = NextCharacter();
if (!IsDecimalDigit(c)) { if (!IsDecimalDigit(c)) {
AllowGarbageCollection allow_before_exception; AllowGarbageCollection allow_before_exception;
ReportUnexpectedCharacter(c); ReportUnexpectedToken(
JsonToken::ILLEGAL,
MessageTemplate::kJsonParseUnterminatedFractionalNumber);
return handle(Smi::FromInt(0), isolate_); return handle(Smi::FromInt(0), isolate_);
} }
AdvanceToNonDecimal(); AdvanceToNonDecimal();
...@@ -970,7 +1062,9 @@ Handle<Object> JsonParser<Char>::ParseJsonNumber() { ...@@ -970,7 +1062,9 @@ Handle<Object> JsonParser<Char>::ParseJsonNumber() {
if (c == '-' || c == '+') c = NextCharacter(); if (c == '-' || c == '+') c = NextCharacter();
if (!IsDecimalDigit(c)) { if (!IsDecimalDigit(c)) {
AllowGarbageCollection allow_before_exception; AllowGarbageCollection allow_before_exception;
ReportUnexpectedCharacter(c); ReportUnexpectedToken(
JsonToken::ILLEGAL,
MessageTemplate::kJsonParseExponentPartMissingNumber);
return handle(Smi::FromInt(0), isolate_); return handle(Smi::FromInt(0), isolate_);
} }
AdvanceToNonDecimal(); AdvanceToNonDecimal();
...@@ -1137,7 +1231,8 @@ JsonString JsonParser<Char>::ScanJsonString(bool needs_internalization) { ...@@ -1137,7 +1231,8 @@ JsonString JsonParser<Char>::ScanJsonString(bool needs_internalization) {
if (V8_UNLIKELY(is_at_end())) { if (V8_UNLIKELY(is_at_end())) {
AllowGarbageCollection allow_before_exception; AllowGarbageCollection allow_before_exception;
ReportUnexpectedCharacter(kEndOfString); ReportUnexpectedToken(JsonToken::ILLEGAL,
MessageTemplate::kJsonParseUnterminatedString);
break; break;
} }
...@@ -1188,7 +1283,8 @@ JsonString JsonParser<Char>::ScanJsonString(bool needs_internalization) { ...@@ -1188,7 +1283,8 @@ JsonString JsonParser<Char>::ScanJsonString(bool needs_internalization) {
case EscapeKind::kIllegal: case EscapeKind::kIllegal:
AllowGarbageCollection allow_before_exception; AllowGarbageCollection allow_before_exception;
ReportUnexpectedCharacter(c); ReportUnexpectedToken(JsonToken::ILLEGAL,
MessageTemplate::kJsonParseBadEscapedCharacter);
return JsonString(); return JsonString();
} }
......
...@@ -211,17 +211,21 @@ class JsonParser final { ...@@ -211,17 +211,21 @@ class JsonParser final {
advance(); advance();
} }
void Expect(JsonToken token) { void Expect(JsonToken token,
base::Optional<MessageTemplate> errorMessage = base::nullopt) {
if (V8_LIKELY(peek() == token)) { if (V8_LIKELY(peek() == token)) {
advance(); advance();
} else { } else {
ReportUnexpectedToken(peek()); errorMessage ? ReportUnexpectedToken(peek(), errorMessage.value())
: ReportUnexpectedToken(peek());
} }
} }
void ExpectNext(JsonToken token) { void ExpectNext(
JsonToken token,
base::Optional<MessageTemplate> errorMessage = base::nullopt) {
SkipWhitespace(); SkipWhitespace();
Expect(token); errorMessage ? Expect(token, errorMessage.value()) : Expect(token);
} }
bool Check(JsonToken token) { bool Check(JsonToken token) {
...@@ -301,10 +305,22 @@ class JsonParser final { ...@@ -301,10 +305,22 @@ class JsonParser final {
const JsonContinuation& cont, const JsonContinuation& cont,
const SmallVector<Handle<Object>>& element_stack); const SmallVector<Handle<Object>>& element_stack);
static const int kMaxContextCharacters = 10;
static const int kMinOriginalSourceLengthForContext =
(kMaxContextCharacters * 2) + 1;
// Mark that a parsing error has happened at the current character. // Mark that a parsing error has happened at the current character.
void ReportUnexpectedCharacter(base::uc32 c); void ReportUnexpectedCharacter(base::uc32 c);
bool IsSpecialString();
MessageTemplate GetErrorMessageWithEllipses(Handle<Object>& arg,
Handle<Object>& arg2, int pos);
MessageTemplate LookUpErrorMessageForJsonToken(JsonToken token,
Handle<Object>& arg,
Handle<Object>& arg2, int pos);
// Mark that a parsing error has happened at the current token. // Mark that a parsing error has happened at the current token.
void ReportUnexpectedToken(JsonToken token); void ReportUnexpectedToken(
JsonToken token,
base::Optional<MessageTemplate> errorMessage = base::nullopt);
inline Isolate* isolate() { return isolate_; } inline Isolate* isolate() { return isolate_; }
inline Factory* factory() { return isolate_->factory(); } inline Factory* factory() { return isolate_->factory(); }
......
...@@ -6,7 +6,7 @@ Test malformed sourceURL magic comment. ...@@ -6,7 +6,7 @@ Test malformed sourceURL magic comment.
columnNumber : 0 columnNumber : 0
exception : { exception : {
className : SyntaxError className : SyntaxError
description : SyntaxError: Unexpected token / in JSON at position 0 at JSON.parse (<anonymous>) at <anonymous>:1:6 description : SyntaxError: Unexpected token '/', "//" is not valid JSON at JSON.parse (<anonymous>) at <anonymous>:1:6
objectId : <objectId> objectId : <objectId>
subtype : error subtype : error
type : object type : object
...@@ -18,7 +18,7 @@ Test malformed sourceURL magic comment. ...@@ -18,7 +18,7 @@ Test malformed sourceURL magic comment.
} }
result : { result : {
className : SyntaxError className : SyntaxError
description : SyntaxError: Unexpected token / in JSON at position 0 at JSON.parse (<anonymous>) at <anonymous>:1:6 description : SyntaxError: Unexpected token '/', "//" is not valid JSON at JSON.parse (<anonymous>) at <anonymous>:1:6
objectId : <objectId> objectId : <objectId>
subtype : error subtype : error
type : object type : object
...@@ -32,7 +32,7 @@ Test malformed sourceURL magic comment. ...@@ -32,7 +32,7 @@ Test malformed sourceURL magic comment.
columnNumber : 0 columnNumber : 0
exception : { exception : {
className : SyntaxError className : SyntaxError
description : SyntaxError: Unexpected token / in JSON at position 0 at JSON.parse (<anonymous>) at <anonymous>:1:6 description : SyntaxError: Unexpected token '/', "//#" is not valid JSON at JSON.parse (<anonymous>) at <anonymous>:1:6
objectId : <objectId> objectId : <objectId>
subtype : error subtype : error
type : object type : object
...@@ -44,7 +44,7 @@ Test malformed sourceURL magic comment. ...@@ -44,7 +44,7 @@ Test malformed sourceURL magic comment.
} }
result : { result : {
className : SyntaxError className : SyntaxError
description : SyntaxError: Unexpected token / in JSON at position 0 at JSON.parse (<anonymous>) at <anonymous>:1:6 description : SyntaxError: Unexpected token '/', "//#" is not valid JSON at JSON.parse (<anonymous>) at <anonymous>:1:6
objectId : <objectId> objectId : <objectId>
subtype : error subtype : error
type : object type : object
...@@ -58,7 +58,7 @@ Test malformed sourceURL magic comment. ...@@ -58,7 +58,7 @@ Test malformed sourceURL magic comment.
columnNumber : 0 columnNumber : 0
exception : { exception : {
className : SyntaxError className : SyntaxError
description : SyntaxError: Unexpected token / in JSON at position 0 at JSON.parse (<anonymous>) at <anonymous>:1:6 description : SyntaxError: Unexpected token '/', "//# " is not valid JSON at JSON.parse (<anonymous>) at <anonymous>:1:6
objectId : <objectId> objectId : <objectId>
subtype : error subtype : error
type : object type : object
...@@ -70,7 +70,7 @@ Test malformed sourceURL magic comment. ...@@ -70,7 +70,7 @@ Test malformed sourceURL magic comment.
} }
result : { result : {
className : SyntaxError className : SyntaxError
description : SyntaxError: Unexpected token / in JSON at position 0 at JSON.parse (<anonymous>) at <anonymous>:1:6 description : SyntaxError: Unexpected token '/', "//# " is not valid JSON at JSON.parse (<anonymous>) at <anonymous>:1:6
objectId : <objectId> objectId : <objectId>
subtype : error subtype : error
type : object type : object
...@@ -84,7 +84,7 @@ Test malformed sourceURL magic comment. ...@@ -84,7 +84,7 @@ Test malformed sourceURL magic comment.
columnNumber : 0 columnNumber : 0
exception : { exception : {
className : SyntaxError className : SyntaxError
description : SyntaxError: Unexpected token / in JSON at position 0 at JSON.parse (<anonymous>) at <anonymous>:1:6 description : SyntaxError: Unexpected token '/', "//# sourceURL" is not valid JSON at JSON.parse (<anonymous>) at <anonymous>:1:6
objectId : <objectId> objectId : <objectId>
subtype : error subtype : error
type : object type : object
...@@ -96,7 +96,7 @@ Test malformed sourceURL magic comment. ...@@ -96,7 +96,7 @@ Test malformed sourceURL magic comment.
} }
result : { result : {
className : SyntaxError className : SyntaxError
description : SyntaxError: Unexpected token / in JSON at position 0 at JSON.parse (<anonymous>) at <anonymous>:1:6 description : SyntaxError: Unexpected token '/', "//# sourceURL" is not valid JSON at JSON.parse (<anonymous>) at <anonymous>:1:6
objectId : <objectId> objectId : <objectId>
subtype : error subtype : error
type : object type : object
...@@ -110,7 +110,7 @@ Test malformed sourceURL magic comment. ...@@ -110,7 +110,7 @@ Test malformed sourceURL magic comment.
columnNumber : 0 columnNumber : 0
exception : { exception : {
className : SyntaxError className : SyntaxError
description : SyntaxError: Unexpected token / in JSON at position 0 at JSON.parse (<anonymous>) at <anonymous>:1:6 description : SyntaxError: Unexpected token '/', "//# sourceURL=" is not valid JSON at JSON.parse (<anonymous>) at <anonymous>:1:6
objectId : <objectId> objectId : <objectId>
subtype : error subtype : error
type : object type : object
...@@ -122,7 +122,7 @@ Test malformed sourceURL magic comment. ...@@ -122,7 +122,7 @@ Test malformed sourceURL magic comment.
} }
result : { result : {
className : SyntaxError className : SyntaxError
description : SyntaxError: Unexpected token / in JSON at position 0 at JSON.parse (<anonymous>) at <anonymous>:1:6 description : SyntaxError: Unexpected token '/', "//# sourceURL=" is not valid JSON at JSON.parse (<anonymous>) at <anonymous>:1:6
objectId : <objectId> objectId : <objectId>
subtype : error subtype : error
type : object type : object
...@@ -136,7 +136,7 @@ Test malformed sourceURL magic comment. ...@@ -136,7 +136,7 @@ Test malformed sourceURL magic comment.
columnNumber : 0 columnNumber : 0
exception : { exception : {
className : SyntaxError className : SyntaxError
description : SyntaxError: Unexpected token / in JSON at position 0 at JSON.parse (<anonymous>) at <anonymous>:1:6 description : SyntaxError: Unexpected token '/', "//# sourceURL="" is not valid JSON at JSON.parse (<anonymous>) at <anonymous>:1:6
objectId : <objectId> objectId : <objectId>
subtype : error subtype : error
type : object type : object
...@@ -148,7 +148,7 @@ Test malformed sourceURL magic comment. ...@@ -148,7 +148,7 @@ Test malformed sourceURL magic comment.
} }
result : { result : {
className : SyntaxError className : SyntaxError
description : SyntaxError: Unexpected token / in JSON at position 0 at JSON.parse (<anonymous>) at <anonymous>:1:6 description : SyntaxError: Unexpected token '/', "//# sourceURL="" is not valid JSON at JSON.parse (<anonymous>) at <anonymous>:1:6
objectId : <objectId> objectId : <objectId>
subtype : error subtype : error
type : object type : object
......
undefined:1: SyntaxError: Unexpected token / in JSON at position 0 undefined:1: SyntaxError: Unexpected token '/', "// Copyrig"... is not valid JSON
// Copyright 2021 the V8 project authors. All rights reserved. // Copyright 2021 the V8 project authors. All rights reserved.
^ ^
SyntaxError: Unexpected token / in JSON at position 0 SyntaxError: Unexpected token '/', "// Copyrig"... is not valid JSON
\ No newline at end of file \ No newline at end of file
...@@ -12,19 +12,19 @@ function TryParse(s, message) { ...@@ -12,19 +12,19 @@ function TryParse(s, message) {
} }
var s = `{"a\\\\b `; var s = `{"a\\\\b `;
TryParse(s, "Unexpected end of JSON input"); TryParse(s, "Unterminated string in JSON at position 7");
var s = `{"a\\\\\u03A9 `; var s = `{"a\\\\\u03A9 `;
TryParse(s, "Unexpected end of JSON input"); TryParse(s, "Unterminated string in JSON at position 7");
var s = `{"ab `; var s = `{"ab `;
TryParse(s, "Unexpected end of JSON input"); TryParse(s, "Unterminated string in JSON at position 5");
var s = `{"a\u03A9 `; var s = `{"a\u03A9 `;
TryParse(s, "Unexpected end of JSON input"); TryParse(s, "Unterminated string in JSON at position 5");
var s = `{"a\nb":"b"}`; var s = `{"a\nb":"b"}`;
TryParse(s, "Unexpected token \n in JSON at position 3"); TryParse(s, "Unexpected token '\n', \"{\"a\nb\":\"b\"}\" is not valid JSON");
var s = `{"a\nb":"b\u03A9"}`; var s = `{"a\nb":"b\u03A9"}`;
TryParse(s, "Unexpected token \n in JSON at position 3"); TryParse(s, "Unexpected token '\n', \"{\"a\nb\":\"b\u03A9\"}\" is not valid JSON");
...@@ -474,25 +474,129 @@ test(function() { ...@@ -474,25 +474,129 @@ test(function() {
eval("'\n'"); eval("'\n'");
}, "Invalid or unexpected token", SyntaxError); }, "Invalid or unexpected token", SyntaxError);
//kJsonParseUnexpectedEOS // kJsonParseUnterminatedString
test(function() {
JSON.parse('{"a" : "}')
}, "Unterminated string in JSON at position 9", SyntaxError);
// kJsonParseExpectedPropNameOrRBrace
test(function() { test(function() {
JSON.parse("{") JSON.parse("{")
}, "Unexpected end of JSON input", SyntaxError); }, "Expected property name or '}' in JSON at position 1", SyntaxError);
// kJsonParseExpectedDoubleQuotedPropertyName
test(function() {
JSON.parse('{"foo" : 1, }');
}, "Expected double-quoted property name in JSON at position 12", SyntaxError);
// kJsonParseExpectedCommaNameOrRBrack
test(function() {
JSON.parse("{'foo': 1}");
}, "Expected property name or '}' in JSON at position 1", SyntaxError);
// kJsonParseExpectedCommaNameOrRBrace
test(function() {
JSON.parse('[1, 2, 3, 4');
}, "Expected ',' or ']' after array element in JSON at position 11", SyntaxError);
test(function() {
JSON.parse('[1, 2, 3, 4g');
}, "Expected ',' or ']' after array element in JSON at position 11", SyntaxError);
// kJsonParseUnexpectedTokenAt // kJsonParseExponentPartMissingNumber
test(function() {
JSON.parse('[1e]');
}, "Exponent part is missing a number in JSON at position 3", SyntaxError);
// kJsonParseExpectedColonAfterPropertyName
test(function() {
JSON.parse('{"a"}');
}, "Expected ':' after property name in JSON at position 4", SyntaxError);
// kJsonParseUnterminatedFractionNumber
test(function() {
JSON.parse('{"a": 0.bs}');
}, "Unterminated fractional number in JSON at position 8", SyntaxError);
// kJsonParseUnexpectedNonWhiteSpaceCharacter
test(function() {
JSON.parse('{"a": 3}a');
}, "Unexpected non-whitespace character after JSON at position 8", SyntaxError);
// kJsonParseBadEscapedCharacter
test(function() {
JSON.parse('{"b" : "\\a"}');
}, "Bad escaped character in JSON at position 9", SyntaxError);
// kJsonParseNoNumberAfterMinusSign
test(function() {
JSON.parse('-');
}, "No number after minus sign in JSON at position 1", SyntaxError);
// kJsonParseUnexpectedTokenShortString
test(function () {
JSON.parse(NaN)
}, "\"NaN\" is not valid JSON", SyntaxError);
// kJsonParseUnexpectedTokenShortString
test(function() { test(function() {
JSON.parse("/") JSON.parse("/")
}, "Unexpected token / in JSON at position 0", SyntaxError); }, "Unexpected token '/', \"/\" is not valid JSON", SyntaxError);
// kJsonParseUnexpectedTokenShortString
test(function () {
JSON.parse(undefined)
}, "\"undefined\" is not valid JSON", SyntaxError);
// kJsonParseUnexpectedTokenNumberAt // kJsonParseUnexpectedTokenShortString
test(function () {
JSON.parse(Infinity)
}, "\"Infinity\" is not valid JSON", SyntaxError);
// kJsonParseUnexpectedTokenShortString
test(function () {
JSON.parse('Bad string')
}, "Unexpected token 'B', \"Bad string\" is not valid JSON", SyntaxError);
// kJsonParseUnexpectedTokenShortString
test(function () {
JSON.parse({})
}, "\"[object Object]\" is not valid JSON", SyntaxError);
// kJsonParseExpectedPropNameOrRBrace
test(function() { test(function() {
JSON.parse("{ 1") JSON.parse("{ 1")
}, "Unexpected number in JSON at position 2", SyntaxError); }, "Expected property name or '}' in JSON at position 2", SyntaxError);
// kJsonParseUnexpectedTokenStringAt // kJsonParseUnexpectedNonWhiteSpaceCharacter
test(function() { test(function() {
JSON.parse('"""') JSON.parse('"""')
}, "Unexpected string in JSON at position 2", SyntaxError); }, "Unexpected non-whitespace character after JSON at position 2", SyntaxError);
// kJsonParseUnexpectedTokenStringShortString
test(function() {
JSON.parse('[1, 2,]');
}, "Unexpected token ']', \"[1, 2,]\" is not valid JSON", SyntaxError);
// kJsonParseUnexpectedTokenStringShortString
test(function() {
JSON.parse('[1, 2, 3, 4, ]');
}, "Unexpected token ']', \"[1, 2, 3, 4, ]\" is not valid JSON", SyntaxError);
// kJsonParseUnexpectedTokenStringSurroundWithContext
test(function() {
JSON.parse('[1, 2, 3, 4, 5, , 7, 8, 9, 10]');
}, "Unexpected token ',', ...\" 3, 4, 5, , 7, 8, 9,\"... is not valid JSON", SyntaxError);
// kJsonParseUnexpectedTokenStringStartWithContext
test(function() {
JSON.parse('[, 2, 3, 4, 5, 6, 7, 8, 9, 10]');
}, "Unexpected token ',', \"[, 2, 3, 4,\"... is not valid JSON", SyntaxError);
// kJsonParseUnexpectedTokenStringEndWithContext
test(function() {
JSON.parse('[1, 2, 3, 4, 5, 6, 7, ]');
}, "Unexpected token ']', ...\" 5, 6, 7, ]\" is not valid JSON", SyntaxError);
// kMalformedRegExp // kMalformedRegExp
test(function() { test(function() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment