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