Line data Source code
1 : // Copyright (c) 2015, 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:charcode/ascii.dart';
6 :
7 : import 'line_scanner.dart';
8 : import 'span_scanner.dart';
9 :
10 : // TODO(nweiz): Currently this duplicates code in line_scanner.dart. Once
11 : // sdk#23770 is fully complete, we should move the shared code into a mixin.
12 :
13 : /// A regular expression matching newlines across platforms.
14 : final _newlineRegExp = new RegExp(r"\r\n?|\n");
15 :
16 : /// A [SpanScanner] that tracks the line and column eagerly, like [LineScanner].
17 : class EagerSpanScanner extends SpanScanner {
18 0 : int get line => _line;
19 : int _line = 0;
20 :
21 0 : int get column => _column;
22 : int _column = 0;
23 :
24 : LineScannerState get state =>
25 0 : new _EagerSpanScannerState(this, position, line, column);
26 :
27 0 : bool get _betweenCRLF => peekChar(-1) == $cr && peekChar() == $lf;
28 :
29 : set state(LineScannerState state) {
30 0 : if (state is! _EagerSpanScannerState ||
31 0 : !identical((state as _EagerSpanScannerState)._scanner, this)) {
32 0 : throw new ArgumentError("The given LineScannerState was not returned by "
33 : "this LineScanner.");
34 : }
35 :
36 0 : super.position = state.position;
37 0 : _line = state.line;
38 0 : _column = state.column;
39 : }
40 :
41 : set position(int newPosition) {
42 0 : var oldPosition = position;
43 0 : super.position = newPosition;
44 :
45 0 : if (newPosition > oldPosition) {
46 0 : var newlines = _newlinesIn(string.substring(oldPosition, newPosition));
47 0 : _line += newlines.length;
48 0 : if (newlines.isEmpty) {
49 0 : _column += newPosition - oldPosition;
50 : } else {
51 0 : _column = newPosition - newlines.last.end;
52 : }
53 : } else {
54 0 : var newlines = _newlinesIn(string.substring(newPosition, oldPosition));
55 0 : if (_betweenCRLF) newlines.removeLast();
56 :
57 0 : _line -= newlines.length;
58 0 : if (newlines.isEmpty) {
59 0 : _column -= oldPosition - newPosition;
60 : } else {
61 0 : _column = newPosition -
62 0 : string.lastIndexOf(_newlineRegExp, newPosition) - 1;
63 : }
64 : }
65 : }
66 :
67 : EagerSpanScanner(String string, {sourceUrl, int position})
68 0 : : super(string, sourceUrl: sourceUrl, position: position);
69 :
70 : bool scanChar(int character) {
71 0 : if (!super.scanChar(character)) return false;
72 0 : _adjustLineAndColumn(character);
73 : return true;
74 : }
75 :
76 : int readChar() {
77 0 : var character = super.readChar();
78 0 : _adjustLineAndColumn(character);
79 : return character;
80 : }
81 :
82 : /// Adjusts [_line] and [_column] after having consumed [character].
83 : void _adjustLineAndColumn(int character) {
84 0 : if (character == $lf || (character == $cr && peekChar() != $lf)) {
85 0 : _line += 1;
86 0 : _column = 0;
87 : } else {
88 0 : _column += 1;
89 : }
90 : }
91 :
92 : bool scan(Pattern pattern) {
93 0 : if (!super.scan(pattern)) return false;
94 :
95 0 : var newlines = _newlinesIn(lastMatch[0]);
96 0 : _line += newlines.length;
97 0 : if (newlines.isEmpty) {
98 0 : _column += lastMatch[0].length;
99 : } else {
100 0 : _column = lastMatch[0].length - newlines.last.end;
101 : }
102 :
103 : return true;
104 : }
105 :
106 : /// Returns a list of [Match]es describing all the newlines in [text], which
107 : /// is assumed to end at [position].
108 : List<Match> _newlinesIn(String text) {
109 0 : var newlines = _newlineRegExp.allMatches(text).toList();
110 0 : if (_betweenCRLF) newlines.removeLast();
111 : return newlines;
112 : }
113 : }
114 :
115 : /// A class representing the state of an [EagerSpanScanner].
116 : class _EagerSpanScannerState implements LineScannerState {
117 : final EagerSpanScanner _scanner;
118 : final int position;
119 : final int line;
120 : final int column;
121 :
122 0 : _EagerSpanScannerState(this._scanner, this.position, this.line, this.column);
123 : }
124 :
|