OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2014, 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.line_scanner; | |
6 | |
7 import 'string_scanner.dart'; | |
8 | |
9 /// A subclass of [StringScanner] that tracks line and column information. | |
10 class LineScanner extends StringScanner { | |
11 /// The scanner's current (zero-based) line number. | |
Bob Nystrom
2014/05/28 21:28:57
Almost every other line/column reporter I've seen
nweiz
2014/05/28 23:56:34
I want to match the source_maps package here, whic
| |
12 int get line => _line; | |
13 int _line = 0; | |
14 | |
15 /// The scanner's current (zero-based) column number. | |
16 int get column => _column; | |
17 int _column = 0; | |
18 | |
19 /// The scanner's state, including line and column information. | |
20 /// | |
21 /// This can be used to efficiently save and restore the state of the scanner | |
22 /// when backtracking. A given [LineScannerState] is only valid for the | |
23 /// [LineScanner] that created it. | |
24 LineScannerState get state => | |
25 new LineScannerState._(this, position, line, column); | |
26 | |
27 set state(LineScannerState state) { | |
28 if (!identical(state._scanner, this)) { | |
29 throw new ArgumentError("The given LineScannerState was not returned by " | |
30 "this LineScanner."); | |
31 } | |
Bob Nystrom
2014/05/28 21:28:57
Nice.
| |
32 | |
33 super.position = state.position; | |
34 _line = state.line; | |
35 _column = state.column; | |
36 } | |
37 | |
38 set position(int newPosition) { | |
39 var oldPosition = position; | |
40 super.position = newPosition; | |
41 | |
42 if (newPosition > oldPosition) { | |
43 var newlines = "\n".allMatches(string.substring(oldPosition, newPosition)) | |
44 .toList(); | |
45 _line += newlines.length; | |
46 if (newlines.isEmpty) { | |
47 _column += newPosition - oldPosition; | |
48 } else { | |
49 _column = newPosition - newlines.last.end; | |
50 } | |
51 } else { | |
52 var newlines = "\n".allMatches(string.substring(newPosition, oldPosition)) | |
53 .toList(); | |
54 _line -= newlines.length; | |
55 if (newlines.isEmpty) { | |
56 _column -= oldPosition - newPosition; | |
57 } else { | |
58 _column = newPosition - string.lastIndexOf("\n", newPosition) - 1; | |
59 } | |
60 } | |
61 } | |
62 | |
63 LineScanner(String string, {sourceUrl, int position}) | |
64 : super(string, sourceUrl: sourceUrl, position: position); | |
65 | |
66 int readChar() { | |
67 var char = super.readChar(); | |
68 if (char == 0xA) { | |
69 _line += 1; | |
70 _column = 0; | |
71 } else { | |
72 _column += 1; | |
73 } | |
74 return char; | |
75 } | |
76 | |
77 bool scan(Pattern pattern) { | |
78 var oldPosition = position; | |
79 if (!super.scan(pattern)) return false; | |
80 | |
81 var newlines = "\n".allMatches(lastMatch[0]).toList(); | |
82 _line = newlines.length; | |
Bob Nystrom
2014/05/28 21:28:57
+=?
Does this take into account newlines after th
nweiz
2014/05/28 23:56:34
Done.
| |
83 if (newlines.isEmpty) { | |
84 _column += lastMatch[0].length; | |
85 } else { | |
86 _column = lastMatch[0].length - newlines.last.end; | |
87 } | |
88 | |
89 return true; | |
90 } | |
91 } | |
92 | |
93 /// A class representing the state of a [LineScanner]. | |
94 class LineScannerState { | |
95 /// The [LineScanner] that created this. | |
96 final LineScanner _scanner; | |
97 | |
98 /// The position of the scanner in this state. | |
99 final int position; | |
100 | |
101 /// The zero-based line number of the scanner in this state. | |
102 final int line; | |
103 | |
104 /// The zero-based column number of the scanner in this state. | |
105 final int column; | |
106 | |
107 LineScannerState._(this._scanner, this.position, this.line, this.column); | |
108 } | |
OLD | NEW |