Report error on unsupported operators

Change-Id: Iea1469e1252c89c630e8bf646caf37051d78c84c
Reviewed-on: https://dart-review.googlesource.com/67401
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Dan Rubel <danrubel@google.com>
This commit is contained in:
danrubel 2018-07-31 18:23:10 +00:00 committed by commit-bot@chromium.org
parent 00e3109368
commit 4734c55882
9 changed files with 103 additions and 22 deletions

View file

@ -538,6 +538,7 @@ const List<ErrorCode> errorCodeValues = const [
ScannerErrorCode.MISSING_QUOTE,
ScannerErrorCode.UNABLE_GET_CONTENT,
ScannerErrorCode.UNEXPECTED_DOLLAR_IN_STRING,
ScannerErrorCode.UNSUPPORTED_OPERATOR,
ScannerErrorCode.UNTERMINATED_MULTI_LINE_COMMENT,
ScannerErrorCode.UNTERMINATED_STRING_LITERAL,
StaticTypeWarningCode.EXPECTED_ONE_LIST_TYPE_ARGUMENTS,

View file

@ -4103,11 +4103,15 @@ class Wrong<T> {
}
void test_invalidOperator() {
createParser('void operator ===(x) {}');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
listener
.assertErrors([expectedError(ParserErrorCode.INVALID_OPERATOR, 14, 3)]);
CompilationUnit unit =
parseCompilationUnit('class C { void operator ===(x) { } }',
errors: usingFastaParser
? [expectedError(ScannerErrorCode.UNSUPPORTED_OPERATOR, 24, 1)]
: [
expectedError(ScannerErrorCode.UNSUPPORTED_OPERATOR, 24, 1),
expectedError(ParserErrorCode.INVALID_OPERATOR, 24, 3)
]);
expect(unit, isNotNull);
}
void test_invalidOperator_unary() {

View file

@ -7168,6 +7168,26 @@ Message _withArgumentsUnspecified(String string) {
message: """${string}""", arguments: {'string': string});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(Token token)> templateUnsupportedOperator =
const Template<Message Function(Token token)>(
messageTemplate: r"""The '#lexeme' operator is not supported.""",
withArguments: _withArgumentsUnsupportedOperator);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Message Function(Token token)> codeUnsupportedOperator =
const Code<Message Function(Token token)>(
"UnsupportedOperator", templateUnsupportedOperator,
analyzerCode: "UNSUPPORTED_OPERATOR", dart2jsCode: "*ignored*");
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
Message _withArgumentsUnsupportedOperator(Token token) {
String lexeme = token.lexeme;
return new Message(codeUnsupportedOperator,
message: """The '${lexeme}' operator is not supported.""",
arguments: {'token': token});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeUnsupportedPrefixPlus = messageUnsupportedPrefixPlus;

View file

@ -2700,6 +2700,7 @@ class Parser {
listener.endMember();
return token;
} else if (optional('===', next2) ||
optional('!==', next2) ||
(next2.isOperator &&
!optional('=', next2) &&
!optional('<', next2))) {
@ -2976,9 +2977,13 @@ class Parser {
return next;
} else {
// Recovery
// The user has specified an invalid operator name.
// Report the error, accept the invalid operator name, and move on.
reportRecoverableErrorWithToken(next, fasta.templateInvalidOperator);
// Scanner reports an error for `===` and `!==`.
if (next.type != TokenType.EQ_EQ_EQ &&
next.type != TokenType.BANG_EQ_EQ) {
// The user has specified an invalid operator name.
// Report the error, accept the invalid operator name, and move on.
reportRecoverableErrorWithToken(next, fasta.templateInvalidOperator);
}
listener.handleInvalidOperatorName(token, next);
return next;
}
@ -5595,7 +5600,9 @@ class Parser {
beforeName, new SyntheticToken(Keyword.OPERATOR, next.offset));
}
assert((next.isOperator && next.endGroup == null) || optional('===', next));
assert((next.isOperator && next.endGroup == null) ||
optional('===', next) ||
optional('!==', next));
Token token = parseMethod(
beforeStart,

View file

@ -21,7 +21,8 @@ import '../fasta_codes.dart'
import '../scanner.dart'
show ErrorToken, Keyword, Scanner, buildUnexpectedCharacterToken;
import 'error_token.dart' show UnterminatedString, UnterminatedToken;
import 'error_token.dart'
show UnsupportedOperator, UnterminatedString, UnterminatedToken;
import 'keyword_state.dart' show KeywordState;
@ -599,7 +600,16 @@ abstract class AbstractScanner implements Scanner {
next = advance();
if (identical(next, $EQ)) {
return select($EQ, TokenType.BANG_EQ_EQ, TokenType.BANG_EQ);
//was `return select($EQ, TokenType.BANG_EQ_EQ, TokenType.BANG_EQ);`
int next = advance();
if (identical(next, $EQ)) {
appendPrecedenceToken(TokenType.BANG_EQ_EQ);
appendErrorToken(new UnsupportedOperator(tail, tokenStart));
return advance();
} else {
appendPrecedenceToken(TokenType.BANG_EQ);
return next;
}
}
appendPrecedenceToken(TokenType.BANG);
return next;
@ -615,7 +625,16 @@ abstract class AbstractScanner implements Scanner {
next = advance();
if (identical(next, $EQ)) {
return select($EQ, TokenType.EQ_EQ_EQ, TokenType.EQ_EQ);
// was `return select($EQ, TokenType.EQ_EQ_EQ, TokenType.EQ_EQ);`
int next = advance();
if (identical(next, $EQ)) {
appendPrecedenceToken(TokenType.EQ_EQ_EQ);
appendErrorToken(new UnsupportedOperator(tail, tokenStart));
return advance();
} else {
appendPrecedenceToken(TokenType.EQ_EQ);
return next;
}
} else if (identical(next, $GT)) {
appendPrecedenceToken(TokenType.FUNCTION);
return advance();

View file

@ -15,6 +15,7 @@ import '../fasta_codes.dart'
templateNonAsciiIdentifier,
templateNonAsciiWhitespace,
templateUnmatchedToken,
templateUnsupportedOperator,
templateUnterminatedString;
import '../scanner.dart' show Token, unicodeReplacementCharacter;
@ -137,6 +138,20 @@ class AsciiControlCharacterToken extends ErrorToken {
templateAsciiControlCharacter.withArguments(character);
}
/// Denotes an operator that is not supported in the Dart language.
class UnsupportedOperator extends ErrorToken {
Token token;
UnsupportedOperator(this.token, int charOffset) : super(charOffset);
@override
Message get assertionMessage =>
templateUnsupportedOperator.withArguments(token);
@override
String toString() => "UnsupportedOperator(${token.lexeme})";
}
/// Represents an unterminated string.
class UnterminatedString extends ErrorToken {
final String start;
@ -149,8 +164,8 @@ class UnterminatedString extends ErrorToken {
int get charCount => endOffset - charOffset;
Message get assertionMessage => templateUnterminatedString.withArguments(
start, closeQuoteFor(start));
Message get assertionMessage =>
templateUnterminatedString.withArguments(start, closeQuoteFor(start));
}
/// Represents an unterminated token.
@ -179,6 +194,6 @@ class UnmatchedToken extends ErrorToken {
String toString() => "UnmatchedToken(${begin.lexeme})";
Message get assertionMessage => templateUnmatchedToken.withArguments(
closeBraceFor(begin.lexeme), begin);
Message get assertionMessage =>
templateUnmatchedToken.withArguments(closeBraceFor(begin.lexeme), begin);
}

View file

@ -52,6 +52,13 @@ class ScannerErrorCode extends ErrorCode {
"an identifier or an expression in curly braces ({}).",
correction: "Try adding a backslash (\\) to escape the '\$'.");
/**
* Parameters:
* 0: the unsupported operator
*/
static const ScannerErrorCode UNSUPPORTED_OPERATOR = const ScannerErrorCode(
'UNSUPPORTED_OPERATOR', "The '{0}' operator is not supported.");
static const ScannerErrorCode UNTERMINATED_MULTI_LINE_COMMENT =
const ScannerErrorCode(
'UNTERMINATED_MULTI_LINE_COMMENT', "Unterminated multi-line comment.",
@ -135,6 +142,10 @@ void translateErrorToken(ErrorToken token, ReportError reportError) {
case "ILLEGAL_CHARACTER":
return _makeError(ScannerErrorCode.ILLEGAL_CHARACTER, [token.character]);
case "UNSUPPORTED_OPERATOR":
return _makeError(ScannerErrorCode.UNSUPPORTED_OPERATOR,
[(token as UnsupportedOperator).token.lexeme]);
default:
if (errorCode == codeUnmatchedToken) {
charOffset = token.begin.endToken.charOffset;
@ -155,7 +166,7 @@ void translateErrorToken(ErrorToken token, ReportError reportError) {
} else if (errorCode == codeUnexpectedDollarInString) {
return _makeError(ScannerErrorCode.MISSING_IDENTIFIER, null);
}
throw new UnimplementedError('$errorCode');
throw new UnimplementedError('$errorCode "${errorCode.analyzerCode}"');
}
}

View file

@ -948,6 +948,14 @@ UnmatchedToken:
- "main(){"
- "main(){[}"
UnsupportedOperator:
template: "The '#lexeme' operator is not supported."
analyzerCode: UNSUPPORTED_OPERATOR
dart2jsCode: "*ignored*"
script:
- "class C { void operator ===(x) {} }"
- "class C { void operator !==(x) {} }"
UnsupportedPrefixPlus:
template: "'+' is not a prefix operator."
tip: "Try removing '+'."
@ -2130,7 +2138,7 @@ InvalidOperator:
analyzerCode: INVALID_OPERATOR
dart2jsCode: "*fatal*"
script:
- "class C { void operator ===(x) {} }"
- "class C { void operator %=(x) {} }"
OperatorParameterMismatch0:
template: "Operator '#name' shouldn't have any parameters."

View file

@ -18,10 +18,6 @@ multiline_newline_test/04r: Pass
multiline_newline_test/05: Pass
multiline_newline_test/05r: Pass
regress_29349_test: Pass
unsupported_operators_test/01: MissingCompileTimeError
unsupported_operators_test/02: MissingCompileTimeError
unsupported_operators_test/03: MissingCompileTimeError
unsupported_operators_test/04: MissingCompileTimeError
void_type_function_types_test/04: MissingCompileTimeError
void_type_function_types_test/06: MissingCompileTimeError
void_type_function_types_test/08: MissingCompileTimeError