Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(330)

Side by Side Diff: lib/src/line_scanner.dart

Issue 1327713003: Properly handle CR LF in LineScanner. (Closed) Base URL: git@github.com:dart-lang/string_scanner@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « CHANGELOG.md ('k') | pubspec.yaml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library string_scanner.line_scanner; 5 library string_scanner.line_scanner;
6 6
7 import 'package:charcode/ascii.dart';
8
7 import 'string_scanner.dart'; 9 import 'string_scanner.dart';
8 10
11 /// A regular expression matching newlines across platforms.
12 final _newlineRegExp = new RegExp(r"\r\n?|\n");
13
9 /// A subclass of [StringScanner] that tracks line and column information. 14 /// A subclass of [StringScanner] that tracks line and column information.
10 class LineScanner extends StringScanner { 15 class LineScanner extends StringScanner {
11 /// The scanner's current (zero-based) line number. 16 /// The scanner's current (zero-based) line number.
12 int get line => _line; 17 int get line => _line;
13 int _line = 0; 18 int _line = 0;
14 19
15 /// The scanner's current (zero-based) column number. 20 /// The scanner's current (zero-based) column number.
16 int get column => _column; 21 int get column => _column;
17 int _column = 0; 22 int _column = 0;
18 23
19 /// The scanner's state, including line and column information. 24 /// The scanner's state, including line and column information.
20 /// 25 ///
21 /// This can be used to efficiently save and restore the state of the scanner 26 /// 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 27 /// when backtracking. A given [LineScannerState] is only valid for the
23 /// [LineScanner] that created it. 28 /// [LineScanner] that created it.
24 LineScannerState get state => 29 LineScannerState get state =>
25 new LineScannerState._(this, position, line, column); 30 new LineScannerState._(this, position, line, column);
26 31
32 /// Whether the current position is between a CR character and an LF
33 /// charactet.
34 bool get _betweenCRLF => peekChar(-1) == $cr && peekChar() == $lf;
35
27 set state(LineScannerState state) { 36 set state(LineScannerState state) {
28 if (!identical(state._scanner, this)) { 37 if (!identical(state._scanner, this)) {
29 throw new ArgumentError("The given LineScannerState was not returned by " 38 throw new ArgumentError("The given LineScannerState was not returned by "
30 "this LineScanner."); 39 "this LineScanner.");
31 } 40 }
32 41
33 super.position = state.position; 42 super.position = state.position;
34 _line = state.line; 43 _line = state.line;
35 _column = state.column; 44 _column = state.column;
36 } 45 }
37 46
38 set position(int newPosition) { 47 set position(int newPosition) {
39 var oldPosition = position; 48 var oldPosition = position;
40 super.position = newPosition; 49 super.position = newPosition;
41 50
42 if (newPosition > oldPosition) { 51 if (newPosition > oldPosition) {
43 var newlines = 52 var newlines = _newlineRegExp
44 "\n".allMatches(string.substring(oldPosition, newPosition)).toList(); 53 .allMatches(string.substring(oldPosition, newPosition)).toList();
54 if (_betweenCRLF) newlines.removeLast();
Bob Nystrom 2015/09/02 00:07:24 How about hoisting this to a function: int _newli
nweiz 2015/09/02 00:10:57 Done.
55
45 _line += newlines.length; 56 _line += newlines.length;
46 if (newlines.isEmpty) { 57 if (newlines.isEmpty) {
47 _column += newPosition - oldPosition; 58 _column += newPosition - oldPosition;
48 } else { 59 } else {
49 _column = newPosition - newlines.last.end; 60 _column = newPosition - newlines.last.end;
50 } 61 }
51 } else { 62 } else {
52 var newlines = 63 var newlines = _newlineRegExp
53 "\n".allMatches(string.substring(newPosition, oldPosition)).toList(); 64 .allMatches(string.substring(newPosition, oldPosition)).toList();
65 if (_betweenCRLF) newlines.removeLast();
66
54 _line -= newlines.length; 67 _line -= newlines.length;
55 if (newlines.isEmpty) { 68 if (newlines.isEmpty) {
56 _column -= oldPosition - newPosition; 69 _column -= oldPosition - newPosition;
57 } else { 70 } else {
58 _column = newPosition - string.lastIndexOf("\n", newPosition) - 1; 71 _column = newPosition -
72 string.lastIndexOf(_newlineRegExp, newPosition) - 1;
59 } 73 }
60 } 74 }
61 } 75 }
62 76
63 LineScanner(String string, {sourceUrl, int position}) 77 LineScanner(String string, {sourceUrl, int position})
64 : super(string, sourceUrl: sourceUrl, position: position); 78 : super(string, sourceUrl: sourceUrl, position: position);
65 79
66 int readChar() { 80 int readChar() {
67 var char = super.readChar(); 81 var char = super.readChar();
68 if (char == 0xA) { 82 if (char == $lf || (char == $cr && peekChar() != $lf)) {
69 _line += 1; 83 _line += 1;
70 _column = 0; 84 _column = 0;
71 } else { 85 } else {
72 _column += 1; 86 _column += 1;
73 } 87 }
74 return char; 88 return char;
75 } 89 }
76 90
77 bool scan(Pattern pattern) { 91 bool scan(Pattern pattern) {
78 if (!super.scan(pattern)) return false; 92 if (!super.scan(pattern)) return false;
79 93
80 var newlines = "\n".allMatches(lastMatch[0]).toList(); 94 var newlines = _newlineRegExp.allMatches(lastMatch[0]).toList();
95 if (_betweenCRLF) newlines.removeLast();
81 _line += newlines.length; 96 _line += newlines.length;
Bob Nystrom 2015/09/02 00:07:24 Even here.
nweiz 2015/09/02 00:10:57 Done.
82 if (newlines.isEmpty) { 97 if (newlines.isEmpty) {
83 _column += lastMatch[0].length; 98 _column += lastMatch[0].length;
84 } else { 99 } else {
85 _column = lastMatch[0].length - newlines.last.end; 100 _column = lastMatch[0].length - newlines.last.end;
86 } 101 }
87 102
88 return true; 103 return true;
89 } 104 }
90 } 105 }
91 106
92 /// A class representing the state of a [LineScanner]. 107 /// A class representing the state of a [LineScanner].
93 class LineScannerState { 108 class LineScannerState {
94 /// The [LineScanner] that created this. 109 /// The [LineScanner] that created this.
95 final LineScanner _scanner; 110 final LineScanner _scanner;
96 111
97 /// The position of the scanner in this state. 112 /// The position of the scanner in this state.
98 final int position; 113 final int position;
99 114
100 /// The zero-based line number of the scanner in this state. 115 /// The zero-based line number of the scanner in this state.
101 final int line; 116 final int line;
102 117
103 /// The zero-based column number of the scanner in this state. 118 /// The zero-based column number of the scanner in this state.
104 final int column; 119 final int column;
105 120
106 LineScannerState._(this._scanner, this.position, this.line, this.column); 121 LineScannerState._(this._scanner, this.position, this.line, this.column);
107 } 122 }
OLDNEW
« no previous file with comments | « CHANGELOG.md ('k') | pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698