Skip to content

Commit 44036a0

Browse files
stereotype441Commit Queue
authored andcommitted
[messages] Move translateErrorToken into analyzer.
Moves the function `translateErrorToken`, and the other code it refers to, from `package:_fe_analyzer_shared` to `package:analyzer`. The only use of this code in `package:front_end` is in tests, and it's ok for `package:front_end` tests to refer to `package:analyzer`, so it didn't need to be shared. Moving it into `package:analyzer` paves the way for a follow-up CL in which I plan to move all of the analyzer scanner error codes into `package:analyzer`. Change-Id: I6a6a6964a155886a4e8fcd2b22b6da38598ce250 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/455262 Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Paul Berry <[email protected]>
1 parent 6c228bf commit 44036a0

File tree

7 files changed

+137
-134
lines changed

7 files changed

+137
-134
lines changed

pkg/_fe_analyzer_shared/lib/src/messages/codes.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
/// @docImport 'package:analyzer/src/fasta/ast_builder.dart';
77
/// @docImport 'package:analyzer/src/fasta/error_converter.dart';
88
/// @docImport 'package:analyzer/src/diagnostic/diagnostic_code_values.dart';
9+
/// @docImport 'package:analyzer/src/dart/scanner/translate_error_token.dart';
910
library _fe_analyzer_shared.messages.codes;
1011

1112
import 'dart:convert' show JsonEncoder, json;

pkg/_fe_analyzer_shared/lib/src/scanner/errors.dart

Lines changed: 0 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -3,134 +3,5 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import '../base/errors.dart';
6-
import '../messages/codes.dart';
7-
import 'error_token.dart';
8-
import 'token.dart' show Token, TokenType;
9-
import 'token_constants.dart';
106

117
part 'errors.g.dart';
12-
13-
/**
14-
* Translates the given error [token] into an analyzer error and reports it
15-
* using [reportError].
16-
*/
17-
void translateErrorToken(ErrorToken token, ReportError reportError) {
18-
int charOffset = token.charOffset;
19-
// TODO(paulberry,ahe): why is endOffset sometimes null?
20-
int endOffset = token.endOffset ?? charOffset;
21-
void _makeError(ScannerErrorCode errorCode, List<Object>? arguments) {
22-
if (_isAtEnd(token, charOffset)) {
23-
// Analyzer never generates an error message past the end of the input,
24-
// since such an error would not be visible in an editor.
25-
// TODO(paulberry,ahe): would it make sense to replicate this behavior
26-
// in cfe, or move it elsewhere in analyzer?
27-
charOffset--;
28-
}
29-
reportError(errorCode, charOffset, arguments);
30-
}
31-
32-
Code errorCode = token.errorCode;
33-
switch (errorCode.pseudoSharedCode) {
34-
case PseudoSharedCode.encoding:
35-
reportError(ScannerErrorCode.encoding, charOffset, null);
36-
return;
37-
38-
case PseudoSharedCode.unterminatedStringLiteral:
39-
// TODO(paulberry,ahe): Fasta reports the error location as the entire
40-
// string; analyzer expects the end of the string.
41-
reportError(
42-
ScannerErrorCode.unterminatedStringLiteral,
43-
endOffset - 1,
44-
null,
45-
);
46-
return;
47-
48-
case PseudoSharedCode.unterminatedMultiLineComment:
49-
// TODO(paulberry,ahe): Fasta reports the error location as the entire
50-
// comment; analyzer expects the end of the comment.
51-
reportError(
52-
ScannerErrorCode.unterminatedMultiLineComment,
53-
endOffset - 1,
54-
null,
55-
);
56-
return;
57-
58-
case PseudoSharedCode.missingDigit:
59-
// TODO(paulberry,ahe): Fasta reports the error location as the entire
60-
// number; analyzer expects the end of the number.
61-
charOffset = endOffset - 1;
62-
return _makeError(ScannerErrorCode.missingDigit, null);
63-
64-
case PseudoSharedCode.missingHexDigit:
65-
// TODO(paulberry,ahe): Fasta reports the error location as the entire
66-
// number; analyzer expects the end of the number.
67-
charOffset = endOffset - 1;
68-
return _makeError(ScannerErrorCode.missingHexDigit, null);
69-
70-
case PseudoSharedCode.illegalCharacter:
71-
// We can safely assume `token.character` is non-`null` because this error
72-
// is only reported when there is a character associated with the token.
73-
return _makeError(ScannerErrorCode.illegalCharacter, [token.character!]);
74-
75-
case PseudoSharedCode.unexpectedSeparatorInNumber:
76-
return _makeError(ScannerErrorCode.unexpectedSeparatorInNumber, null);
77-
78-
case PseudoSharedCode.unsupportedOperator:
79-
return _makeError(ScannerErrorCode.unsupportedOperator, [
80-
(token as UnsupportedOperator).token.lexeme,
81-
]);
82-
83-
default:
84-
if (errorCode == codeUnmatchedToken) {
85-
charOffset = token.begin!.endToken!.charOffset;
86-
TokenType type = token.begin!.type;
87-
if (type == TokenType.OPEN_CURLY_BRACKET ||
88-
type == TokenType.STRING_INTERPOLATION_EXPRESSION) {
89-
return _makeError(ScannerErrorCode.expectedToken, ['}']);
90-
}
91-
if (type == TokenType.OPEN_SQUARE_BRACKET) {
92-
return _makeError(ScannerErrorCode.expectedToken, [']']);
93-
}
94-
if (type == TokenType.OPEN_PAREN) {
95-
return _makeError(ScannerErrorCode.expectedToken, [')']);
96-
}
97-
if (type == TokenType.LT) {
98-
return _makeError(ScannerErrorCode.expectedToken, ['>']);
99-
}
100-
} else if (errorCode == codeUnexpectedDollarInString) {
101-
return _makeError(ScannerErrorCode.missingIdentifier, null);
102-
}
103-
throw new UnimplementedError(
104-
'$errorCode "${errorCode.pseudoSharedCode}"',
105-
);
106-
}
107-
}
108-
109-
/**
110-
* Determines whether the given [charOffset], which came from the non-EOF token
111-
* [token], represents the end of the input.
112-
*/
113-
bool _isAtEnd(Token token, int charOffset) {
114-
while (true) {
115-
// Skip to the next token.
116-
token = token.next!;
117-
// If we've found an EOF token, its charOffset indicates where the end of
118-
// the input is.
119-
if (token.isEof) return token.charOffset == charOffset;
120-
// If we've found a non-error token, then we know there is additional input
121-
// text after [charOffset].
122-
if (token.type.kind != BAD_INPUT_TOKEN) return false;
123-
// Otherwise keep looking.
124-
}
125-
}
126-
127-
/**
128-
* Used to report a scan error at the given offset.
129-
* The [errorCode] is the error code indicating the nature of the error.
130-
* The [arguments] are any arguments needed to complete the error message.
131-
*/
132-
typedef ReportError(
133-
ScannerErrorCode errorCode,
134-
int offset,
135-
List<Object>? arguments,
136-
);

pkg/analyzer/lib/src/dart/scanner/scanner.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
import 'dart:typed_data';
66

7-
import 'package:_fe_analyzer_shared/src/scanner/errors.dart'
8-
show translateErrorToken;
97
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' as fasta;
108
import 'package:_fe_analyzer_shared/src/scanner/token.dart'
119
show Token, TokenType;
@@ -16,6 +14,8 @@ import 'package:analyzer/source/source.dart';
1614
import 'package:analyzer/src/dart/analysis/experiments.dart';
1715
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
1816
import 'package:analyzer/src/dart/scanner/reader.dart';
17+
import 'package:analyzer/src/dart/scanner/translate_error_token.dart'
18+
show translateErrorToken;
1919
import 'package:analyzer/src/error/codes.dart';
2020
import 'package:meta/meta.dart';
2121
import 'package:pub_semver/pub_semver.dart';
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:_fe_analyzer_shared/src/messages/codes.dart';
6+
import 'package:_fe_analyzer_shared/src/scanner/error_token.dart';
7+
import 'package:_fe_analyzer_shared/src/scanner/token.dart'
8+
show Token, TokenType;
9+
import 'package:_fe_analyzer_shared/src/scanner/token_constants.dart';
10+
import 'package:analyzer/src/dart/scanner/scanner.dart';
11+
12+
/// Translates the given error [token] into an analyzer error and reports it
13+
/// using [reportError].
14+
void translateErrorToken(ErrorToken token, ReportError reportError) {
15+
int charOffset = token.charOffset;
16+
// TODO(paulberry): why is endOffset sometimes null?
17+
int endOffset = token.endOffset ?? charOffset;
18+
void makeError(ScannerErrorCode errorCode, List<Object>? arguments) {
19+
if (_isAtEnd(token, charOffset)) {
20+
// Analyzer never generates an error message past the end of the input,
21+
// since such an error would not be visible in an editor.
22+
// TODO(paulberry): would it make sense to replicate this behavior
23+
// in cfe, or move it elsewhere in analyzer?
24+
charOffset--;
25+
}
26+
reportError(errorCode, charOffset, arguments);
27+
}
28+
29+
Code errorCode = token.errorCode;
30+
switch (errorCode.pseudoSharedCode) {
31+
case PseudoSharedCode.encoding:
32+
reportError(ScannerErrorCode.encoding, charOffset, null);
33+
return;
34+
35+
case PseudoSharedCode.unterminatedStringLiteral:
36+
// TODO(paulberry): Fasta reports the error location as the entire
37+
// string; analyzer expects the end of the string.
38+
reportError(
39+
ScannerErrorCode.unterminatedStringLiteral,
40+
endOffset - 1,
41+
null,
42+
);
43+
return;
44+
45+
case PseudoSharedCode.unterminatedMultiLineComment:
46+
// TODO(paulberry): Fasta reports the error location as the entire
47+
// comment; analyzer expects the end of the comment.
48+
reportError(
49+
ScannerErrorCode.unterminatedMultiLineComment,
50+
endOffset - 1,
51+
null,
52+
);
53+
return;
54+
55+
case PseudoSharedCode.missingDigit:
56+
// TODO(paulberry): Fasta reports the error location as the entire
57+
// number; analyzer expects the end of the number.
58+
charOffset = endOffset - 1;
59+
return makeError(ScannerErrorCode.missingDigit, null);
60+
61+
case PseudoSharedCode.missingHexDigit:
62+
// TODO(paulberry): Fasta reports the error location as the entire
63+
// number; analyzer expects the end of the number.
64+
charOffset = endOffset - 1;
65+
return makeError(ScannerErrorCode.missingHexDigit, null);
66+
67+
case PseudoSharedCode.illegalCharacter:
68+
// We can safely assume `token.character` is non-`null` because this error
69+
// is only reported when there is a character associated with the token.
70+
return makeError(ScannerErrorCode.illegalCharacter, [token.character!]);
71+
72+
case PseudoSharedCode.unexpectedSeparatorInNumber:
73+
return makeError(ScannerErrorCode.unexpectedSeparatorInNumber, null);
74+
75+
case PseudoSharedCode.unsupportedOperator:
76+
return makeError(ScannerErrorCode.unsupportedOperator, [
77+
(token as UnsupportedOperator).token.lexeme,
78+
]);
79+
80+
default:
81+
if (errorCode == codeUnmatchedToken) {
82+
charOffset = token.begin!.endToken!.charOffset;
83+
TokenType type = token.begin!.type;
84+
if (type == TokenType.OPEN_CURLY_BRACKET ||
85+
type == TokenType.STRING_INTERPOLATION_EXPRESSION) {
86+
return makeError(ScannerErrorCode.expectedToken, ['}']);
87+
}
88+
if (type == TokenType.OPEN_SQUARE_BRACKET) {
89+
return makeError(ScannerErrorCode.expectedToken, [']']);
90+
}
91+
if (type == TokenType.OPEN_PAREN) {
92+
return makeError(ScannerErrorCode.expectedToken, [')']);
93+
}
94+
if (type == TokenType.LT) {
95+
return makeError(ScannerErrorCode.expectedToken, ['>']);
96+
}
97+
} else if (errorCode == codeUnexpectedDollarInString) {
98+
return makeError(ScannerErrorCode.missingIdentifier, null);
99+
}
100+
throw UnimplementedError('$errorCode "${errorCode.pseudoSharedCode}"');
101+
}
102+
}
103+
104+
/// Determines whether the given [charOffset], which came from the non-EOF token
105+
/// [token], represents the end of the input.
106+
bool _isAtEnd(Token token, int charOffset) {
107+
while (true) {
108+
// Skip to the next token.
109+
token = token.next!;
110+
// If we've found an EOF token, its charOffset indicates where the end of
111+
// the input is.
112+
if (token.isEof) return token.charOffset == charOffset;
113+
// If we've found a non-error token, then we know there is additional input
114+
// text after [charOffset].
115+
if (token.type.kind != BAD_INPUT_TOKEN) return false;
116+
// Otherwise keep looking.
117+
}
118+
}
119+
120+
/// Used to report a scan error at the given offset.
121+
/// The [errorCode] is the error code indicating the nature of the error.
122+
/// The [arguments] are any arguments needed to complete the error message.
123+
typedef ReportError =
124+
void Function(
125+
ScannerErrorCode errorCode,
126+
int offset,
127+
List<Object>? arguments,
128+
);

pkg/analyzer/lib/src/fasta/ast_builder.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ import 'package:_fe_analyzer_shared/src/parser/parser.dart'
5050
import 'package:_fe_analyzer_shared/src/parser/quote.dart';
5151
import 'package:_fe_analyzer_shared/src/parser/stack_listener.dart'
5252
show NullValues, StackListener;
53-
import 'package:_fe_analyzer_shared/src/scanner/errors.dart'
54-
show translateErrorToken;
5553
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart';
5654
import 'package:_fe_analyzer_shared/src/scanner/token.dart'
5755
show KeywordToken, StringToken, SyntheticToken;
@@ -67,6 +65,8 @@ import 'package:analyzer/src/dart/analysis/experiments.dart';
6765
import 'package:analyzer/src/dart/ast/ast.dart';
6866
import 'package:analyzer/src/dart/ast/extensions.dart';
6967
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
68+
import 'package:analyzer/src/dart/scanner/translate_error_token.dart'
69+
show translateErrorToken;
7070
import 'package:analyzer/src/fasta/doc_comment_builder.dart';
7171
import 'package:analyzer/src/fasta/error_converter.dart';
7272
import 'package:analyzer/src/generated/utilities_dart.dart';

pkg/front_end/test/scanner_cfe_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import 'package:_fe_analyzer_shared/src/scanner/scanner.dart'
1212
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart';
1313
import 'package:_fe_analyzer_shared/src/scanner/token.dart';
1414
import 'package:_fe_analyzer_shared/src/scanner/token_constants.dart';
15+
import 'package:analyzer/src/dart/scanner/translate_error_token.dart';
1516
import 'package:front_end/src/codes/cfe_codes.dart';
1617
import 'package:test/test.dart';
1718
import 'package:test_reflective_loader/test_reflective_loader.dart';

pkg/front_end/test/scanner_replacement_test.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44

55
import 'package:_fe_analyzer_shared/src/scanner/error_token.dart';
66
import 'package:_fe_analyzer_shared/src/scanner/errors.dart'
7-
show ScannerErrorCode, translateErrorToken;
7+
show ScannerErrorCode;
88
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart';
99
import 'package:_fe_analyzer_shared/src/scanner/token.dart';
10+
import 'package:analyzer/src/dart/scanner/translate_error_token.dart'
11+
show translateErrorToken;
1012
import 'package:test/test.dart';
1113
import 'package:test_reflective_loader/test_reflective_loader.dart';
1214

0 commit comments

Comments
 (0)