blob: a1b521d9eca557cb5e52b4d7abe2779bde6a16c5 [file] [log] [blame]
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library _fe_analyzer_shared.scanner;
import 'dart:convert' show unicodeReplacementCharacterRune;
import 'dart:typed_data' show Uint8List;
import 'abstract_scanner.dart'
show LanguageVersionChanged, ScannerConfiguration;
import 'string_scanner.dart' show StringScanner;
import 'token.dart' show Token;
import 'utf8_bytes_scanner.dart' show Utf8BytesScanner;
export 'abstract_scanner.dart'
show LanguageVersionChanged, ScannerConfiguration;
export 'error_token.dart' show ErrorToken, buildUnexpectedCharacterToken;
export 'string_scanner.dart' show StringScanner;
export 'token.dart'
show LanguageVersionToken, Keyword, Token, TokenIsAExtension;
export 'token_constants.dart' show EOF_TOKEN;
export 'token_impl.dart'
show
StringTokenImpl,
isBinaryOperator,
isMinusOperator,
isTernaryOperator,
isUnaryOperator,
isUserDefinableOperator;
export 'utf8_bytes_scanner.dart' show Utf8BytesScanner;
const int unicodeReplacementCharacter = unicodeReplacementCharacterRune;
abstract class Scanner {
/// Returns true if an error occurred during [tokenize].
bool get hasErrors;
List<int> get lineStarts;
/// Configure which tokens are produced.
set configuration(ScannerConfiguration config);
Token tokenize();
}
class ScannerResult {
final Token tokens;
final List<int> lineStarts;
final bool hasErrors;
ScannerResult(this.tokens, this.lineStarts, this.hasErrors);
}
/// Scan/tokenize the given UTF8 [bytes].
ScannerResult scan(
Uint8List bytes, {
ScannerConfiguration? configuration,
bool includeComments = false,
LanguageVersionChanged? languageVersionChanged,
bool allowLazyStrings = true,
}) {
Utf8BytesScanner scanner = new Utf8BytesScanner(
bytes,
configuration: configuration,
includeComments: includeComments,
languageVersionChanged: languageVersionChanged,
allowLazyStrings: allowLazyStrings,
);
Token tokens = scanner.tokenize();
if (scanner.hasErrors) {
// If there was a single missing `}` and the scanner can identify a good
// candidate for better recovery, create a new scanner and instruct it to
// do that recovery.
int? offsetForCurlyBracketRecoveryStart =
scanner.getOffsetForCurlyBracketRecoveryStart();
if (offsetForCurlyBracketRecoveryStart != null) {
scanner = new Utf8BytesScanner(
bytes,
configuration: configuration,
includeComments: includeComments,
languageVersionChanged: languageVersionChanged,
allowLazyStrings: allowLazyStrings,
);
scanner.offsetForCurlyBracketRecoveryStart =
offsetForCurlyBracketRecoveryStart;
tokens = scanner.tokenize();
}
}
return new ScannerResult(tokens, scanner.lineStarts, scanner.hasErrors);
}
/// Scan/tokenize the given [source].
ScannerResult scanString(
String source, {
ScannerConfiguration? configuration,
bool includeComments = false,
LanguageVersionChanged? languageVersionChanged,
}) {
StringScanner scanner = new StringScanner(
source,
configuration: configuration,
includeComments: includeComments,
languageVersionChanged: languageVersionChanged,
);
Token tokens = scanner.tokenize();
if (scanner.hasErrors) {
// If there was a single missing `}` and the scanner can identify a good
// candidate for better recovery, create a new scanner and instruct it to
// do that recovery.
int? offsetForCurlyBracketRecoveryStart =
scanner.getOffsetForCurlyBracketRecoveryStart();
if (offsetForCurlyBracketRecoveryStart != null) {
scanner = new StringScanner(
source,
configuration: configuration,
includeComments: includeComments,
languageVersionChanged: languageVersionChanged,
);
scanner.offsetForCurlyBracketRecoveryStart =
offsetForCurlyBracketRecoveryStart;
tokens = scanner.tokenize();
}
}
return new ScannerResult(tokens, scanner.lineStarts, scanner.hasErrors);
}