| // 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.md file. |
| |
| library _fe_analyzer_shared.scanner; |
| |
| import 'dart:convert' show unicodeReplacementCharacterRune, utf8; |
| |
| import 'token.dart' show Token; |
| |
| import 'abstract_scanner.dart' |
| show LanguageVersionChanged, ScannerConfiguration; |
| |
| import 'string_scanner.dart' show StringScanner; |
| |
| import 'utf8_bytes_scanner.dart' show Utf8BytesScanner; |
| |
| import 'recover.dart' show scannerRecovery; |
| |
| export 'abstract_scanner.dart' |
| show LanguageVersionChanged, ScannerConfiguration; |
| |
| export 'token_impl.dart' |
| show |
| LanguageVersionToken, |
| StringToken, |
| isBinaryOperator, |
| isMinusOperator, |
| isTernaryOperator, |
| isUnaryOperator, |
| isUserDefinableOperator; |
| |
| export 'error_token.dart' show ErrorToken, buildUnexpectedCharacterToken; |
| |
| export 'token_impl.dart' show LanguageVersionToken; |
| |
| export 'token_constants.dart' show EOF_TOKEN; |
| |
| export 'utf8_bytes_scanner.dart' show Utf8BytesScanner; |
| |
| export 'string_scanner.dart' show StringScanner; |
| |
| export 'token.dart' show Keyword, Token; |
| |
| const int unicodeReplacementCharacter = unicodeReplacementCharacterRune; |
| |
| typedef Token Recover(List<int> bytes, Token tokens, List<int> lineStarts); |
| |
| 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(List<int> bytes, |
| {ScannerConfiguration? configuration, |
| bool includeComments: false, |
| LanguageVersionChanged? languageVersionChanged}) { |
| if (bytes.last != 0) { |
| throw new ArgumentError("[bytes]: the last byte must be null."); |
| } |
| Scanner scanner = new Utf8BytesScanner(bytes, |
| configuration: configuration, |
| includeComments: includeComments, |
| languageVersionChanged: languageVersionChanged); |
| return _tokenizeAndRecover(scanner, bytes: bytes); |
| } |
| |
| /// Scan/tokenize the given [source]. |
| ScannerResult scanString(String source, |
| {ScannerConfiguration? configuration, |
| bool includeComments: false, |
| LanguageVersionChanged? languageVersionChanged}) { |
| // ignore: unnecessary_null_comparison |
| assert(source != null, 'source must not be null'); |
| StringScanner scanner = new StringScanner(source, |
| configuration: configuration, |
| includeComments: includeComments, |
| languageVersionChanged: languageVersionChanged); |
| return _tokenizeAndRecover(scanner, source: source); |
| } |
| |
| ScannerResult _tokenizeAndRecover(Scanner scanner, |
| {List<int>? bytes, String? source}) { |
| Token tokens = scanner.tokenize(); |
| if (scanner.hasErrors) { |
| if (bytes == null) bytes = utf8.encode(source!); |
| tokens = scannerRecovery(bytes, tokens, scanner.lineStarts); |
| } |
| return new ScannerResult(tokens, scanner.lineStarts, scanner.hasErrors); |
| } |