Line data Source code
1 : // Copyright (c) 2016, 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:source_span/source_span.dart'; 6 : 7 : import 'exception.dart'; 8 : import 'line_scanner.dart'; 9 : import 'span_scanner.dart'; 10 : import 'string_scanner.dart'; 11 : import 'utils.dart'; 12 : 13 : /// A [SpanScanner] that scans within an existing [FileSpan]. 14 : /// 15 : /// This re-implements chunks of [SpanScanner] rather than using a dummy span or 16 : /// inheritance because scanning is often a performance-critical operation, so 17 : /// it's important to avoid adding extra overhead when relative scanning isn't 18 : /// needed. 19 : class RelativeSpanScanner extends StringScanner implements SpanScanner { 20 : /// The source of the scanner. 21 : /// 22 : /// This caches line break information and is used to generate [SourceSpan]s. 23 : final SourceFile _sourceFile; 24 : 25 : /// The start location of the span within which this scanner is scanning. 26 : /// 27 : /// This is used to convert between span-relative and file-relative fields. 28 : final FileLocation _startLocation; 29 : 30 0 : @override 31 : int get line => 32 0 : _sourceFile.getLine(_startLocation.offset + position) - 33 0 : _startLocation.line; 34 : 35 0 : @override 36 : int get column { 37 0 : final line = _sourceFile.getLine(_startLocation.offset + position); 38 : final column = 39 0 : _sourceFile.getColumn(_startLocation.offset + position, line: line); 40 0 : return line == _startLocation.line 41 0 : ? column - _startLocation.column 42 : : column; 43 : } 44 : 45 0 : @override 46 0 : LineScannerState get state => _SpanScannerState(this, position); 47 : 48 0 : @override 49 : set state(LineScannerState state) { 50 0 : if (state is! _SpanScannerState || !identical(state._scanner, this)) { 51 0 : throw ArgumentError('The given LineScannerState was not returned by ' 52 : 'this LineScanner.'); 53 : } 54 : 55 0 : position = state.position; 56 : } 57 : 58 0 : @override 59 0 : FileSpan? get lastSpan => _lastSpan; 60 : FileSpan? _lastSpan; 61 : 62 0 : @override 63 : FileLocation get location => 64 0 : _sourceFile.location(_startLocation.offset + position); 65 : 66 0 : @override 67 0 : FileSpan get emptySpan => location.pointSpan(); 68 : 69 0 : RelativeSpanScanner(FileSpan span) 70 0 : : _sourceFile = span.file, 71 0 : _startLocation = span.start, 72 0 : super(span.text, sourceUrl: span.sourceUrl); 73 : 74 0 : @override 75 : FileSpan spanFrom(LineScannerState startState, [LineScannerState? endState]) { 76 0 : final endPosition = endState == null ? position : endState.position; 77 0 : return _sourceFile.span(_startLocation.offset + startState.position, 78 0 : _startLocation.offset + endPosition); 79 : } 80 : 81 0 : @override 82 : bool matches(Pattern pattern) { 83 0 : if (!super.matches(pattern)) { 84 0 : _lastSpan = null; 85 : return false; 86 : } 87 : 88 0 : _lastSpan = _sourceFile.span(_startLocation.offset + position, 89 0 : _startLocation.offset + lastMatch!.end); 90 : return true; 91 : } 92 : 93 0 : @override 94 : Never error(String message, {Match? match, int? position, int? length}) { 95 0 : validateErrorArgs(string, match, position, length); 96 : 97 0 : if (match == null && position == null && length == null) match = lastMatch; 98 0 : position ??= match == null ? this.position : match.start; 99 0 : length ??= match == null ? 1 : match.end - match.start; 100 : 101 0 : final span = _sourceFile.span(_startLocation.offset + position, 102 0 : _startLocation.offset + position + length); 103 0 : throw StringScannerException(message, span, string); 104 : } 105 : } 106 : 107 : /// A class representing the state of a [SpanScanner]. 108 : class _SpanScannerState implements LineScannerState { 109 : /// The [SpanScanner] that created this. 110 : final RelativeSpanScanner _scanner; 111 : 112 : @override 113 : final int position; 114 0 : @override 115 0 : int get line => _scanner._sourceFile.getLine(position); 116 0 : @override 117 0 : int get column => _scanner._sourceFile.getColumn(position); 118 : 119 0 : _SpanScannerState(this._scanner, this.position); 120 : }