mirror of
https://github.com/dart-lang/sdk
synced 2024-10-03 06:21:30 +00:00
Improve invalid string literal error recovery
Change-Id: Ic7d5d3f19e97a0004254377170bcc91efc7bfb08 Reviewed-on: https://dart-review.googlesource.com/60360 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Dan Rubel <danrubel@google.com>
This commit is contained in:
parent
84f077842b
commit
c015e8d303
|
@ -206,7 +206,7 @@ class AstBuilder extends StackListener {
|
|||
|
||||
if (interpolationCount == 0) {
|
||||
Token token = pop();
|
||||
String value = unescapeString(token.lexeme);
|
||||
String value = unescapeString(token.lexeme, token, this);
|
||||
push(ast.simpleStringLiteral(token, value));
|
||||
} else {
|
||||
List<Object> parts = popTypedList(1 + interpolationCount * 2);
|
||||
|
|
|
@ -7,6 +7,13 @@ import 'package:analyzer/dart/ast/token.dart' show Token;
|
|||
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
|
||||
import 'package:front_end/src/api_prototype/compilation_message.dart';
|
||||
import 'package:front_end/src/fasta/messages.dart' show Code, Message;
|
||||
import 'package:front_end/src/fasta/quote.dart'
|
||||
show
|
||||
incompleteHexSequence,
|
||||
incompleteUnicodeSequence,
|
||||
invalidCodePoint,
|
||||
invalidHexSequenceCharacter,
|
||||
invalidUnicodeCharacter;
|
||||
|
||||
/// An error reporter that knows how to convert a Fasta error into an analyzer
|
||||
/// error.
|
||||
|
@ -183,6 +190,23 @@ class FastaErrorReporter {
|
|||
offset,
|
||||
length);
|
||||
return;
|
||||
case "ERROR_IN_STRING_LITERAL":
|
||||
String stringError = arguments['string'];
|
||||
if (stringError == invalidCodePoint) {
|
||||
errorReporter?.reportErrorForOffset(
|
||||
ParserErrorCode.INVALID_CODE_POINT, offset, length, ['\\u{...}']);
|
||||
} else if (stringError == invalidHexSequenceCharacter ||
|
||||
stringError == incompleteHexSequence) {
|
||||
errorReporter?.reportErrorForOffset(
|
||||
ParserErrorCode.INVALID_HEX_ESCAPE, offset, length);
|
||||
} else if (stringError == invalidUnicodeCharacter ||
|
||||
stringError == incompleteUnicodeSequence) {
|
||||
errorReporter?.reportErrorForOffset(
|
||||
ParserErrorCode.INVALID_UNICODE_ESCAPE, offset, length);
|
||||
} else {
|
||||
throw 'Unhandled error in string literal: ${arguments['string']}';
|
||||
}
|
||||
return;
|
||||
case "EXPECTED_CLASS_MEMBER":
|
||||
errorReporter?.reportErrorForOffset(
|
||||
ParserErrorCode.EXPECTED_CLASS_MEMBER, offset, length);
|
||||
|
|
|
@ -125,249 +125,6 @@ class ErrorParserTest_Fasta extends FastaParserTestCase
|
|||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@failingTest
|
||||
void test_invalidCodePoint() {
|
||||
// TODO(brianwilkerson) Does not recover.
|
||||
// Internal problem: Compiler cannot run without a compiler context.
|
||||
// Tip: Are calls to the compiler wrapped in CompilerContext.runInContext?
|
||||
// package:front_end/src/fasta/compiler_context.dart 81:7 CompilerContext.current
|
||||
// package:front_end/src/fasta/command_line_reporting.dart 112:30 shouldThrowOn
|
||||
// package:front_end/src/fasta/deprecated_problems.dart 41:7 deprecated_inputError
|
||||
// package:front_end/src/fasta/quote.dart 181:5 unescapeCodeUnits.error
|
||||
// package:front_end/src/fasta/quote.dart 251:40 unescapeCodeUnits
|
||||
// package:front_end/src/fasta/quote.dart 147:13 unescape
|
||||
// package:front_end/src/fasta/quote.dart 135:10 unescapeString
|
||||
// package:analyzer/src/fasta/ast_builder.dart 159:22 AstBuilder.endLiteralString
|
||||
// test/generated/parser_fasta_listener.dart 896:14 ForwardingTestListener.endLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3497:14 Parser.parseSingleLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3434:13 Parser.parseLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3133:14 Parser.parsePrimary
|
||||
// package:front_end/src/fasta/parser/parser.dart 3097:14 Parser.parseUnaryExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2968:13 Parser.parsePrecedenceExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2942:11 Parser.parseExpression
|
||||
// test/generated/parser_fasta_test.dart 3196:39 ParserProxy._run
|
||||
super.test_invalidCodePoint();
|
||||
}
|
||||
|
||||
@override
|
||||
@failingTest
|
||||
void test_invalidHexEscape_invalidDigit() {
|
||||
// TODO(brianwilkerson) Does not recover.
|
||||
// Internal problem: Compiler cannot run without a compiler context.
|
||||
// Tip: Are calls to the compiler wrapped in CompilerContext.runInContext?
|
||||
// package:front_end/src/fasta/compiler_context.dart 81:7 CompilerContext.current
|
||||
// package:front_end/src/fasta/command_line_reporting.dart 112:30 shouldThrowOn
|
||||
// package:front_end/src/fasta/deprecated_problems.dart 41:7 deprecated_inputError
|
||||
// package:front_end/src/fasta/quote.dart 181:5 unescapeCodeUnits.error
|
||||
// package:front_end/src/fasta/quote.dart 221:47 unescapeCodeUnits
|
||||
// package:front_end/src/fasta/quote.dart 147:13 unescape
|
||||
// package:front_end/src/fasta/quote.dart 135:10 unescapeString
|
||||
// package:analyzer/src/fasta/ast_builder.dart 159:22 AstBuilder.endLiteralString
|
||||
// test/generated/parser_fasta_listener.dart 896:14 ForwardingTestListener.endLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3497:14 Parser.parseSingleLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3434:13 Parser.parseLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3133:14 Parser.parsePrimary
|
||||
// package:front_end/src/fasta/parser/parser.dart 3097:14 Parser.parseUnaryExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2968:13 Parser.parsePrecedenceExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2942:11 Parser.parseExpression
|
||||
// test/generated/parser_fasta_test.dart 3196:39 ParserProxy._run
|
||||
super.test_invalidHexEscape_invalidDigit();
|
||||
}
|
||||
|
||||
@override
|
||||
@failingTest
|
||||
void test_invalidHexEscape_tooFewDigits() {
|
||||
// TODO(brianwilkerson) Does not recover.
|
||||
// Internal problem: Compiler cannot run without a compiler context.
|
||||
// Tip: Are calls to the compiler wrapped in CompilerContext.runInContext?
|
||||
// package:front_end/src/fasta/compiler_context.dart 81:7 CompilerContext.current
|
||||
// package:front_end/src/fasta/command_line_reporting.dart 112:30 shouldThrowOn
|
||||
// package:front_end/src/fasta/deprecated_problems.dart 41:7 deprecated_inputError
|
||||
// package:front_end/src/fasta/quote.dart 181:5 unescapeCodeUnits.error
|
||||
// package:front_end/src/fasta/quote.dart 217:52 unescapeCodeUnits
|
||||
// package:front_end/src/fasta/quote.dart 147:13 unescape
|
||||
// package:front_end/src/fasta/quote.dart 135:10 unescapeString
|
||||
// package:analyzer/src/fasta/ast_builder.dart 159:22 AstBuilder.endLiteralString
|
||||
// test/generated/parser_fasta_listener.dart 896:14 ForwardingTestListener.endLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3497:14 Parser.parseSingleLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3434:13 Parser.parseLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3133:14 Parser.parsePrimary
|
||||
// package:front_end/src/fasta/parser/parser.dart 3097:14 Parser.parseUnaryExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2968:13 Parser.parsePrecedenceExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2942:11 Parser.parseExpression
|
||||
// test/generated/parser_fasta_test.dart 3196:39 ParserProxy._run
|
||||
super.test_invalidHexEscape_tooFewDigits();
|
||||
}
|
||||
|
||||
@override
|
||||
@failingTest
|
||||
void test_invalidUnicodeEscape_incomplete_noDigits() {
|
||||
// TODO(brianwilkerson) Does not recover.
|
||||
// Internal problem: Compiler cannot run without a compiler context.
|
||||
// Tip: Are calls to the compiler wrapped in CompilerContext.runInContext?
|
||||
// package:front_end/src/fasta/compiler_context.dart 81:7 CompilerContext.current
|
||||
// package:front_end/src/fasta/command_line_reporting.dart 112:30 shouldThrowOn
|
||||
// package:front_end/src/fasta/deprecated_problems.dart 41:7 deprecated_inputError
|
||||
// package:front_end/src/fasta/quote.dart 181:5 unescapeCodeUnits.error
|
||||
// package:front_end/src/fasta/quote.dart 232:54 unescapeCodeUnits
|
||||
// package:front_end/src/fasta/quote.dart 147:13 unescape
|
||||
// package:front_end/src/fasta/quote.dart 135:10 unescapeString
|
||||
// package:analyzer/src/fasta/ast_builder.dart 159:22 AstBuilder.endLiteralString
|
||||
// test/generated/parser_fasta_listener.dart 896:14 ForwardingTestListener.endLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3497:14 Parser.parseSingleLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3434:13 Parser.parseLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3133:14 Parser.parsePrimary
|
||||
// package:front_end/src/fasta/parser/parser.dart 3097:14 Parser.parseUnaryExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2968:13 Parser.parsePrecedenceExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2942:11 Parser.parseExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2862:13 Parser.parseExpressionStatement
|
||||
// package:front_end/src/fasta/parser/parser.dart 2790:14 Parser.parseStatementX
|
||||
// package:front_end/src/fasta/parser/parser.dart 2722:20 Parser.parseStatement
|
||||
// test/generated/parser_fasta_test.dart 3287:39 ParserProxy._run
|
||||
super.test_invalidUnicodeEscape_incomplete_noDigits();
|
||||
}
|
||||
|
||||
@override
|
||||
@failingTest
|
||||
void test_invalidUnicodeEscape_incomplete_someDigits() {
|
||||
// TODO(brianwilkerson) Does not recover.
|
||||
// Internal problem: Compiler cannot run without a compiler context.
|
||||
// Tip: Are calls to the compiler wrapped in CompilerContext.runInContext?
|
||||
// package:front_end/src/fasta/compiler_context.dart 81:7 CompilerContext.current
|
||||
// package:front_end/src/fasta/command_line_reporting.dart 112:30 shouldThrowOn
|
||||
// package:front_end/src/fasta/deprecated_problems.dart 41:7 deprecated_inputError
|
||||
// package:front_end/src/fasta/quote.dart 181:5 unescapeCodeUnits.error
|
||||
// package:front_end/src/fasta/quote.dart 232:54 unescapeCodeUnits
|
||||
// package:front_end/src/fasta/quote.dart 147:13 unescape
|
||||
// package:front_end/src/fasta/quote.dart 135:10 unescapeString
|
||||
// package:analyzer/src/fasta/ast_builder.dart 159:22 AstBuilder.endLiteralString
|
||||
// test/generated/parser_fasta_listener.dart 896:14 ForwardingTestListener.endLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3497:14 Parser.parseSingleLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3434:13 Parser.parseLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3133:14 Parser.parsePrimary
|
||||
// package:front_end/src/fasta/parser/parser.dart 3097:14 Parser.parseUnaryExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2968:13 Parser.parsePrecedenceExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2942:11 Parser.parseExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2862:13 Parser.parseExpressionStatement
|
||||
// package:front_end/src/fasta/parser/parser.dart 2790:14 Parser.parseStatementX
|
||||
// package:front_end/src/fasta/parser/parser.dart 2722:20 Parser.parseStatement
|
||||
// test/generated/parser_fasta_test.dart 3287:39 ParserProxy._run
|
||||
super.test_invalidUnicodeEscape_incomplete_someDigits();
|
||||
}
|
||||
|
||||
@override
|
||||
@failingTest
|
||||
void test_invalidUnicodeEscape_invalidDigit() {
|
||||
// TODO(brianwilkerson) Does not recover.
|
||||
// Internal problem: Compiler cannot run without a compiler context.
|
||||
// Tip: Are calls to the compiler wrapped in CompilerContext.runInContext?
|
||||
// package:front_end/src/fasta/compiler_context.dart 81:7 CompilerContext.current
|
||||
// package:front_end/src/fasta/command_line_reporting.dart 112:30 shouldThrowOn
|
||||
// package:front_end/src/fasta/deprecated_problems.dart 41:7 deprecated_inputError
|
||||
// package:front_end/src/fasta/quote.dart 181:5 unescapeCodeUnits.error
|
||||
// package:front_end/src/fasta/quote.dart 240:54 unescapeCodeUnits
|
||||
// package:front_end/src/fasta/quote.dart 147:13 unescape
|
||||
// package:front_end/src/fasta/quote.dart 135:10 unescapeString
|
||||
// package:analyzer/src/fasta/ast_builder.dart 159:22 AstBuilder.endLiteralString
|
||||
// test/generated/parser_fasta_listener.dart 896:14 ForwardingTestListener.endLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3497:14 Parser.parseSingleLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3434:13 Parser.parseLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3133:14 Parser.parsePrimary
|
||||
// package:front_end/src/fasta/parser/parser.dart 3097:14 Parser.parseUnaryExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2968:13 Parser.parsePrecedenceExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2942:11 Parser.parseExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2862:13 Parser.parseExpressionStatement
|
||||
// package:front_end/src/fasta/parser/parser.dart 2790:14 Parser.parseStatementX
|
||||
// package:front_end/src/fasta/parser/parser.dart 2722:20 Parser.parseStatement
|
||||
// test/generated/parser_fasta_test.dart 3287:39 ParserProxy._run
|
||||
super.test_invalidUnicodeEscape_invalidDigit();
|
||||
}
|
||||
|
||||
@override
|
||||
@failingTest
|
||||
void test_invalidUnicodeEscape_tooFewDigits_fixed() {
|
||||
// TODO(brianwilkerson) Does not recover.
|
||||
// Internal problem: Compiler cannot run without a compiler context.
|
||||
// Tip: Are calls to the compiler wrapped in CompilerContext.runInContext?
|
||||
// package:front_end/src/fasta/compiler_context.dart 81:7 CompilerContext.current
|
||||
// package:front_end/src/fasta/command_line_reporting.dart 112:30 shouldThrowOn
|
||||
// package:front_end/src/fasta/deprecated_problems.dart 41:7 deprecated_inputError
|
||||
// package:front_end/src/fasta/quote.dart 181:5 unescapeCodeUnits.error
|
||||
// package:front_end/src/fasta/quote.dart 240:54 unescapeCodeUnits
|
||||
// package:front_end/src/fasta/quote.dart 147:13 unescape
|
||||
// package:front_end/src/fasta/quote.dart 135:10 unescapeString
|
||||
// package:analyzer/src/fasta/ast_builder.dart 159:22 AstBuilder.endLiteralString
|
||||
// test/generated/parser_fasta_listener.dart 896:14 ForwardingTestListener.endLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3497:14 Parser.parseSingleLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3434:13 Parser.parseLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3133:14 Parser.parsePrimary
|
||||
// package:front_end/src/fasta/parser/parser.dart 3097:14 Parser.parseUnaryExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2968:13 Parser.parsePrecedenceExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2942:11 Parser.parseExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2862:13 Parser.parseExpressionStatement
|
||||
// package:front_end/src/fasta/parser/parser.dart 2790:14 Parser.parseStatementX
|
||||
// package:front_end/src/fasta/parser/parser.dart 2722:20 Parser.parseStatement
|
||||
// test/generated/parser_fasta_test.dart 3287:39 ParserProxy._run
|
||||
super.test_invalidUnicodeEscape_tooFewDigits_fixed();
|
||||
}
|
||||
|
||||
@override
|
||||
@failingTest
|
||||
void test_invalidUnicodeEscape_tooFewDigits_variable() {
|
||||
// TODO(brianwilkerson) Does not recover.
|
||||
// Internal problem: Compiler cannot run without a compiler context.
|
||||
// Tip: Are calls to the compiler wrapped in CompilerContext.runInContext?
|
||||
// package:front_end/src/fasta/compiler_context.dart 81:7 CompilerContext.current
|
||||
// package:front_end/src/fasta/command_line_reporting.dart 112:30 shouldThrowOn
|
||||
// package:front_end/src/fasta/deprecated_problems.dart 41:7 deprecated_inputError
|
||||
// package:front_end/src/fasta/quote.dart 181:5 unescapeCodeUnits.error
|
||||
// package:front_end/src/fasta/quote.dart 235:49 unescapeCodeUnits
|
||||
// package:front_end/src/fasta/quote.dart 147:13 unescape
|
||||
// package:front_end/src/fasta/quote.dart 135:10 unescapeString
|
||||
// package:analyzer/src/fasta/ast_builder.dart 159:22 AstBuilder.endLiteralString
|
||||
// test/generated/parser_fasta_listener.dart 896:14 ForwardingTestListener.endLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3497:14 Parser.parseSingleLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3434:13 Parser.parseLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3133:14 Parser.parsePrimary
|
||||
// package:front_end/src/fasta/parser/parser.dart 3097:14 Parser.parseUnaryExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2968:13 Parser.parsePrecedenceExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2942:11 Parser.parseExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2862:13 Parser.parseExpressionStatement
|
||||
// package:front_end/src/fasta/parser/parser.dart 2790:14 Parser.parseStatementX
|
||||
// package:front_end/src/fasta/parser/parser.dart 2722:20 Parser.parseStatement
|
||||
// test/generated/parser_fasta_test.dart 3287:39 ParserProxy._run
|
||||
super.test_invalidUnicodeEscape_tooFewDigits_variable();
|
||||
}
|
||||
|
||||
@override
|
||||
@failingTest
|
||||
void test_invalidUnicodeEscape_tooManyDigits_variable() {
|
||||
// TODO(brianwilkerson) Does not recover.
|
||||
// Internal problem: Compiler cannot run without a compiler context.
|
||||
// Tip: Are calls to the compiler wrapped in CompilerContext.runInContext?
|
||||
// package:front_end/src/fasta/compiler_context.dart 81:7 CompilerContext.current
|
||||
// package:front_end/src/fasta/command_line_reporting.dart 112:30 shouldThrowOn
|
||||
// package:front_end/src/fasta/deprecated_problems.dart 41:7 deprecated_inputError
|
||||
// package:front_end/src/fasta/quote.dart 181:5 unescapeCodeUnits.error
|
||||
// package:front_end/src/fasta/quote.dart 251:40 unescapeCodeUnits
|
||||
// package:front_end/src/fasta/quote.dart 147:13 unescape
|
||||
// package:front_end/src/fasta/quote.dart 135:10 unescapeString
|
||||
// package:analyzer/src/fasta/ast_builder.dart 159:22 AstBuilder.endLiteralString
|
||||
// test/generated/parser_fasta_listener.dart 896:14 ForwardingTestListener.endLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3497:14 Parser.parseSingleLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3434:13 Parser.parseLiteralString
|
||||
// package:front_end/src/fasta/parser/parser.dart 3133:14 Parser.parsePrimary
|
||||
// package:front_end/src/fasta/parser/parser.dart 3097:14 Parser.parseUnaryExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2968:13 Parser.parsePrecedenceExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2942:11 Parser.parseExpression
|
||||
// package:front_end/src/fasta/parser/parser.dart 2862:13 Parser.parseExpressionStatement
|
||||
// package:front_end/src/fasta/parser/parser.dart 2790:14 Parser.parseStatementX
|
||||
// package:front_end/src/fasta/parser/parser.dart 2722:20 Parser.parseStatement
|
||||
// test/generated/parser_fasta_test.dart 3287:39 ParserProxy._run
|
||||
super.test_invalidUnicodeEscape_tooManyDigits_variable();
|
||||
}
|
||||
|
||||
@override
|
||||
void test_method_invalidTypeParameterComments() {
|
||||
// Ignored: Fasta does not support the generic comment syntax.
|
||||
|
|
|
@ -3998,8 +3998,8 @@ class Wrong<T> {
|
|||
}
|
||||
|
||||
void test_invalidCodePoint() {
|
||||
StringLiteral literal = parseExpression("'\\u{110000}'",
|
||||
errors: [expectedError(ParserErrorCode.INVALID_CODE_POINT, 0, 10)]);
|
||||
StringLiteral literal = parseExpression("'begin \\u{110000}'",
|
||||
errors: [expectedError(ParserErrorCode.INVALID_CODE_POINT, 7, 9)]);
|
||||
expectNotNullIfNoErrors(literal);
|
||||
}
|
||||
|
||||
|
@ -4065,8 +4065,8 @@ class Wrong<T> {
|
|||
}
|
||||
|
||||
void test_invalidHexEscape_invalidDigit() {
|
||||
StringLiteral literal = parseExpression("'\\x0 a'",
|
||||
errors: [expectedError(ParserErrorCode.INVALID_HEX_ESCAPE, 1, 3)]);
|
||||
StringLiteral literal = parseExpression("'not \\x0 a'",
|
||||
errors: [expectedError(ParserErrorCode.INVALID_HEX_ESCAPE, 5, 3)]);
|
||||
expectNotNullIfNoErrors(literal);
|
||||
}
|
||||
|
||||
|
@ -4248,7 +4248,7 @@ class Wrong<T> {
|
|||
}
|
||||
|
||||
void test_invalidUnicodeEscape_invalidDigit() {
|
||||
Expression expression = parseStringLiteral("'\\u0 a'");
|
||||
Expression expression = parseStringLiteral("'\\u0 and some more'");
|
||||
expectNotNullIfNoErrors(expression);
|
||||
listener.assertErrors(
|
||||
[expectedError(ParserErrorCode.INVALID_UNICODE_ESCAPE, 1, 3)]);
|
||||
|
@ -4271,10 +4271,12 @@ class Wrong<T> {
|
|||
void test_invalidUnicodeEscape_tooManyDigits_variable() {
|
||||
Expression expression = parseStringLiteral("'\\u{12345678}'");
|
||||
expectNotNullIfNoErrors(expression);
|
||||
listener.assertErrors([
|
||||
expectedError(ParserErrorCode.INVALID_UNICODE_ESCAPE, 1, 12),
|
||||
expectedError(ParserErrorCode.INVALID_CODE_POINT, 1, 12)
|
||||
]);
|
||||
listener.assertErrors(usingFastaParser
|
||||
? [expectedError(ParserErrorCode.INVALID_CODE_POINT, 1, 9)]
|
||||
: [
|
||||
expectedError(ParserErrorCode.INVALID_UNICODE_ESCAPE, 1, 12),
|
||||
expectedError(ParserErrorCode.INVALID_CODE_POINT, 1, 12)
|
||||
]);
|
||||
}
|
||||
|
||||
void test_libraryDirectiveNotFirst() {
|
||||
|
|
|
@ -5421,6 +5421,26 @@ const MessageCode messageStaticOperator = const MessageCode("StaticOperator",
|
|||
message: r"""Operators can't be static.""",
|
||||
tip: r"""Try removing the keyword 'static'.""");
|
||||
|
||||
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
||||
const Template<Message Function(String string, int count)>
|
||||
templateStringLiteralError =
|
||||
const Template<Message Function(String string, int count)>(
|
||||
messageTemplate: r"""#string at offset #count""",
|
||||
withArguments: _withArgumentsStringLiteralError);
|
||||
|
||||
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
||||
const Code<Message Function(String string, int count)> codeStringLiteralError =
|
||||
const Code<Message Function(String string, int count)>(
|
||||
"StringLiteralError", templateStringLiteralError,
|
||||
analyzerCode: "ERROR_IN_STRING_LITERAL", dart2jsCode: "*fatal*");
|
||||
|
||||
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
||||
Message _withArgumentsStringLiteralError(String string, int count) {
|
||||
return new Message(codeStringLiteralError,
|
||||
message: """${string} at offset ${count}""",
|
||||
arguments: {'string': string, 'count': count});
|
||||
}
|
||||
|
||||
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
||||
const Code<Null> codeSuperAsExpression = messageSuperAsExpression;
|
||||
|
||||
|
|
|
@ -1248,6 +1248,12 @@ class ForwardingListener implements Listener {
|
|||
listener?.handleStringJuxtaposition(literalCount);
|
||||
}
|
||||
|
||||
@override
|
||||
void handleUnescapeError(
|
||||
String error, Token location, int offset, int length) {
|
||||
listener?.handleUnescapeError(error, location, offset, length);
|
||||
}
|
||||
|
||||
@override
|
||||
void handleStringPart(Token token) {
|
||||
listener?.handleStringPart(token);
|
||||
|
|
|
@ -7,7 +7,12 @@ library fasta.parser.listener;
|
|||
import '../../scanner/token.dart' show Token, TokenType;
|
||||
|
||||
import '../fasta_codes.dart'
|
||||
show Message, messageNativeClauseShouldBeAnnotation;
|
||||
show
|
||||
Message,
|
||||
messageNativeClauseShouldBeAnnotation,
|
||||
templateStringLiteralError;
|
||||
|
||||
import '../quote.dart' show UnescapeErrorListener;
|
||||
|
||||
import 'assert.dart' show Assert;
|
||||
|
||||
|
@ -30,7 +35,7 @@ import 'parser_error.dart' show ParserError;
|
|||
///
|
||||
/// Events starting with `handle` are used when isn't possible to have a begin
|
||||
/// event.
|
||||
class Listener {
|
||||
class Listener implements UnescapeErrorListener {
|
||||
final List<ParserError> recoverableErrors = <ParserError>[];
|
||||
|
||||
Uri get uri => null;
|
||||
|
@ -1232,6 +1237,15 @@ class Listener {
|
|||
.add(new ParserError.fromTokens(startToken, endToken, message));
|
||||
}
|
||||
|
||||
@override
|
||||
void handleUnescapeError(
|
||||
String error, Token location, int stringOffset, int length) {
|
||||
handleRecoverableError(
|
||||
templateStringLiteralError.withArguments(error, stringOffset),
|
||||
location,
|
||||
location);
|
||||
}
|
||||
|
||||
/// Signals to the listener that the previous statement contained a semantic
|
||||
/// error (described by the given [message]). This method can also be called
|
||||
/// after [handleExpressionFunctionBody], in which case it signals that the
|
||||
|
|
|
@ -130,27 +130,31 @@ String unescapeLastStringPart(String last, Quote quote) {
|
|||
last.substring(0, last.length - lastQuoteLength(quote)), quote);
|
||||
}
|
||||
|
||||
String unescapeString(String string) {
|
||||
String unescapeString(String string,
|
||||
[Object token, UnescapeErrorListener listener]) {
|
||||
Quote quote = analyzeQuote(string);
|
||||
return unescape(
|
||||
string.substring(firstQuoteLength(string, quote),
|
||||
string.length - lastQuoteLength(quote)),
|
||||
quote);
|
||||
quote,
|
||||
token,
|
||||
listener);
|
||||
}
|
||||
|
||||
String unescape(String string, Quote quote) {
|
||||
String unescape(String string, Quote quote,
|
||||
[Object token, UnescapeErrorListener listener]) {
|
||||
switch (quote) {
|
||||
case Quote.Single:
|
||||
case Quote.Double:
|
||||
return !string.contains("\\")
|
||||
? string
|
||||
: unescapeCodeUnits(string.codeUnits, false);
|
||||
: unescapeCodeUnits(string.codeUnits, false, token, listener);
|
||||
|
||||
case Quote.MultiLineSingle:
|
||||
case Quote.MultiLineDouble:
|
||||
return !string.contains("\\") && !string.contains("\r")
|
||||
? string
|
||||
: unescapeCodeUnits(string.codeUnits, false);
|
||||
: unescapeCodeUnits(string.codeUnits, false, token, listener);
|
||||
|
||||
case Quote.RawSingle:
|
||||
case Quote.RawDouble:
|
||||
|
@ -160,24 +164,38 @@ String unescape(String string, Quote quote) {
|
|||
case Quote.RawMultiLineDouble:
|
||||
return !string.contains("\r")
|
||||
? string
|
||||
: unescapeCodeUnits(string.codeUnits, true);
|
||||
: unescapeCodeUnits(string.codeUnits, true, token, listener);
|
||||
}
|
||||
return unhandled("$quote", "unescape", -1, null);
|
||||
}
|
||||
|
||||
const String incompleteSequence = "Incomplete escape sequence.";
|
||||
const String incompleteHexSequence = "Incomplete hex escape sequence.";
|
||||
|
||||
const String invalidCharacter = "Invalid character in escape sequence.";
|
||||
const String invalidHexSequenceCharacter =
|
||||
"Invalid character in hex escape sequence.";
|
||||
|
||||
const String invalidCodePoint = "Invalid code point.";
|
||||
|
||||
const String incompleteUnicodeSequence = "Incomplete unicode escape sequence.";
|
||||
|
||||
const String invalidUnicodeCharacter =
|
||||
"Invalid character in unicode escape sequence.";
|
||||
|
||||
// Note: based on
|
||||
// [StringValidator.validateString](pkg/compiler/lib/src/string_validator.dart).
|
||||
String unescapeCodeUnits(List<int> codeUnits, bool isRaw) {
|
||||
String unescapeCodeUnits(List<int> codeUnits, bool isRaw,
|
||||
// TODO(danrubel): Update remaining call sites
|
||||
// and make these parameters required.
|
||||
[Object location,
|
||||
UnescapeErrorListener listener]) {
|
||||
// Can't use Uint8List or Uint16List here, the code units may be larger.
|
||||
List<int> result = new List<int>(codeUnits.length);
|
||||
int resultOffset = 0;
|
||||
error(int offset, String message) {
|
||||
error(String message, int offset, int length) {
|
||||
if (location != null && listener != null && length != null) {
|
||||
listener.handleUnescapeError(message, location, offset, length);
|
||||
return new String.fromCharCodes(codeUnits);
|
||||
}
|
||||
deprecated_inputError(null, null, message);
|
||||
}
|
||||
|
||||
|
@ -189,7 +207,9 @@ String unescapeCodeUnits(List<int> codeUnits, bool isRaw) {
|
|||
}
|
||||
code = $LF;
|
||||
} else if (!isRaw && code == $BACKSLASH) {
|
||||
if (codeUnits.length == ++i) return error(i, incompleteSequence);
|
||||
if (codeUnits.length == ++i) {
|
||||
return error(incompleteUnicodeSequence, i, 1);
|
||||
}
|
||||
code = codeUnits[i];
|
||||
|
||||
/// `\n` for newline, equivalent to `\x0A`.
|
||||
|
@ -214,43 +234,71 @@ String unescapeCodeUnits(List<int> codeUnits, bool isRaw) {
|
|||
code = $VTAB;
|
||||
} else if (code == $x) {
|
||||
// Expect exactly 2 hex digits.
|
||||
if (codeUnits.length <= i + 2) return error(i, incompleteSequence);
|
||||
int begin = i;
|
||||
if (codeUnits.length <= i + 2) {
|
||||
return error(
|
||||
incompleteHexSequence, begin, codeUnits.length + 1 - begin);
|
||||
}
|
||||
code = 0;
|
||||
for (int j = 0; j < 2; j++) {
|
||||
int digit = codeUnits[++i];
|
||||
if (!isHexDigit(digit)) return error(i, invalidCharacter);
|
||||
if (!isHexDigit(digit)) {
|
||||
return error(invalidHexSequenceCharacter, begin, i + 1 - begin);
|
||||
}
|
||||
code = (code << 4) + hexDigitValue(digit);
|
||||
}
|
||||
} else if (code == $u) {
|
||||
if (codeUnits.length == i + 1) return error(i, incompleteSequence);
|
||||
int begin = i;
|
||||
if (codeUnits.length == i + 1) {
|
||||
return error(
|
||||
incompleteUnicodeSequence, begin, codeUnits.length + 1 - begin);
|
||||
}
|
||||
code = codeUnits[i + 1];
|
||||
if (code == $OPEN_CURLY_BRACKET) {
|
||||
// Expect 1-6 hex digits followed by '}'.
|
||||
if (codeUnits.length == ++i) return error(i, incompleteSequence);
|
||||
if (codeUnits.length == ++i) {
|
||||
return error(incompleteUnicodeSequence, begin, i + 1 - begin);
|
||||
}
|
||||
code = 0;
|
||||
for (int j = 0; j < 7; j++) {
|
||||
if (codeUnits.length == ++i) return error(i, incompleteSequence);
|
||||
if (codeUnits.length == ++i) {
|
||||
return error(incompleteUnicodeSequence, begin, i + 1 - begin);
|
||||
}
|
||||
int digit = codeUnits[i];
|
||||
if (j != 0 && digit == $CLOSE_CURLY_BRACKET) break;
|
||||
if (!isHexDigit(digit)) return error(i, invalidCharacter);
|
||||
if (!isHexDigit(digit)) {
|
||||
return error(invalidUnicodeCharacter, begin, i + 2 - begin);
|
||||
}
|
||||
code = (code << 4) + hexDigitValue(digit);
|
||||
}
|
||||
} else {
|
||||
// Expect exactly 4 hex digits.
|
||||
if (codeUnits.length <= i + 4) return error(i, incompleteSequence);
|
||||
if (codeUnits.length <= i + 4) {
|
||||
return error(
|
||||
incompleteUnicodeSequence, begin, codeUnits.length + 1 - begin);
|
||||
}
|
||||
code = 0;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
int digit = codeUnits[++i];
|
||||
if (!isHexDigit(digit)) return error(i, invalidCharacter);
|
||||
if (!isHexDigit(digit)) {
|
||||
return error(invalidUnicodeCharacter, begin, i + 1 - begin);
|
||||
}
|
||||
code = (code << 4) + hexDigitValue(digit);
|
||||
}
|
||||
}
|
||||
if (code > 0x10FFFF) {
|
||||
return error(invalidCodePoint, begin, i + 1 - begin);
|
||||
}
|
||||
} else {
|
||||
// Nothing, escaped character is passed through;
|
||||
}
|
||||
if (code > 0x10FFFF) return error(i, invalidCodePoint);
|
||||
}
|
||||
result[resultOffset++] = code;
|
||||
}
|
||||
return new String.fromCharCodes(result, 0, resultOffset);
|
||||
}
|
||||
|
||||
abstract class UnescapeErrorListener {
|
||||
void handleUnescapeError(
|
||||
String error, covariant location, int offset, int length);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,8 @@ import '../fasta_codes.dart'
|
|||
show
|
||||
Message,
|
||||
messageNativeClauseShouldBeAnnotation,
|
||||
templateInternalProblemStackNotEmpty;
|
||||
templateInternalProblemStackNotEmpty,
|
||||
templateStringLiteralError;
|
||||
|
||||
import '../parser.dart' show Listener, MemberKind, Parser;
|
||||
|
||||
|
@ -356,6 +357,15 @@ abstract class StackListener extends Listener {
|
|||
throw deprecated_inputError(uri, token.charOffset, message.message);
|
||||
}
|
||||
|
||||
@override
|
||||
void handleUnescapeError(
|
||||
String error, Token token, int stringOffset, int length) {
|
||||
addCompileTimeError(
|
||||
templateStringLiteralError.withArguments(error, stringOffset),
|
||||
token.charOffset + stringOffset,
|
||||
length);
|
||||
}
|
||||
|
||||
void addCompileTimeError(Message message, int charOffset, int length);
|
||||
}
|
||||
|
||||
|
|
|
@ -341,6 +341,7 @@ SourceOutlineSummary/analyzerCode: Fail
|
|||
SourceOutlineSummary/example: Fail
|
||||
StackOverflow/example: Fail
|
||||
StaticAfterConst/script1: Fail
|
||||
StringLiteralError/expression: Fail
|
||||
SuperAsExpression/analyzerCode: Fail
|
||||
SuperAsExpression/example: Fail
|
||||
SuperAsIdentifier/analyzerCode: Fail
|
||||
|
|
|
@ -766,6 +766,12 @@ StackOverflow:
|
|||
analyzerCode: STACK_OVERFLOW
|
||||
dart2jsCode: GENERIC
|
||||
|
||||
StringLiteralError:
|
||||
template: "#string at offset #count"
|
||||
analyzerCode: ERROR_IN_STRING_LITERAL
|
||||
dart2jsCode: "*fatal*"
|
||||
expression: "'\\u{110000'"
|
||||
|
||||
UnexpectedDollarInString:
|
||||
template: "A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({})."
|
||||
tip: "Try adding a backslash (\\) to escape the '$'."
|
||||
|
|
Loading…
Reference in a new issue