Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 } |
| OLD | NEW |