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

Side by Side Diff: pkg/string_scanner/lib/string_scanner.dart

Issue 213833013: Add a string_scanner package. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 8 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 | Annotate | Revision Log
« no previous file with comments | « pkg/string_scanner/README.md ('k') | pkg/string_scanner/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
(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;
kevmoo 2014/04/02 16:30:09 A short doc-comment on the library is nice, if you
nweiz 2014/04/02 20:26:40 Done.
6
7 // TODO(nweiz): Add some integration between this and source maps.
8 /// A class that scans through a string using [Pattern]s.
9 class StringScanner {
10 /// The string being scanned through.
11 final String string;
12
13 /// The current position of the scanner in the string, in characters.
14 int get position => _position;
15 set position(int position) {
kevmoo 2014/04/02 16:30:09 void? silly, but I like it
nweiz 2014/04/02 20:26:40 It's redundant with "set".
16 if (position < 0 || position > string.length) {
17 throw new ArgumentError("Invalid position $position");
18 }
19
20 _position = position;
21 }
22 int _position = 0;
23
24 /// The data about the previous match made by the scanner.
25 ///
26 /// If the last match failed, this will be `null`.
27 Match get lastMatch => _lastMatch;
28 Match _lastMatch;
29
30 /// The portion of the string that hasn't yet been scanned.
31 String get rest => string.substring(position);
32
33 /// Whether the scanner has completely consumed [string].
34 bool get isDone => position == string.length;
35
36 /// Creates a new [StringScanner] that starts scanning from [position].
37 ///
38 /// [position] defaults to 0, the beginning of the string.
39 StringScanner(this.string, {int position}) {
40 if (position != null) this.position = position;
41 }
42
43 /// If [pattern] matches at the current position of the string, scans forward
44 /// until the end of the match.
45 ///
46 /// Returns whether or not [pattern] matched.
47 bool scan(Pattern pattern) {
48 var success = matches(pattern);
49 if (success) _position = _lastMatch.end;
50 return success;
51 }
52
53 /// If [pattern] matches at the current position of the string, scans forward
54 /// until the end of the match.
55 ///
56 /// If [pattern] did not match, throws a [FormatException] describing the
57 /// position of the failure. [name] is used in this error as the expected name
58 /// of the pattern being matched; if it's `null`, the pattern itself is used
59 /// instead.
60 void expect(Pattern pattern, {String name}) {
61 if (scan(pattern)) return;
62
63 if (name == null) {
64 if (pattern is RegExp) {
65 name = "/${pattern.pattern.replaceAll("/", "\\/")}/";
66 } else {
67 name = pattern.toString()
68 .replaceAll("\\", "\\\\").replaceAll('"', '\\"');
69 name = '"$name"';
70 }
71 }
72 _fail(name);
73 }
74
75 /// If the string has not been fully consumed, this throws a
76 /// [FormatException].
77 void expectDone() {
78 if (isDone) return;
79 _fail("no more input");
80 }
81
82 /// Returns whether or not [pattern] matches at the current position of the
83 /// string.
84 ///
85 /// This doesn't move the scan pointer forward.
86 bool matches(Pattern pattern) {
87 _lastMatch = pattern.matchAsPrefix(string, position);
88 return _lastMatch != null;
89 }
90
91 // TODO(nweiz): Make this handle long lines more gracefully.
92 /// Throws a [FormatException] describing that [name] is expected at the
93 /// current position in the string.
94 void _fail(String name) {
95 var newlines = "\n".allMatches(string.substring(0, position)).toList();
96 var line = newlines.length + 1;
97 var column;
98 var lastLine;
99 if (newlines.isEmpty) {
100 column = position + 1;
101 lastLine = string.substring(0, position);
102 } else {
103 column = position - newlines.last.end + 1;
104 lastLine = string.substring(newlines.last.end, position);
105 }
106 lastLine += rest.replaceFirst(new RegExp(r"\n.*"), '');
107 throw new FormatException(
108 "Expected $name on line $line, column $column.\n"
109 "$lastLine\n"
110 "${new List.filled(column - 1, ' ').join()}^");
111 }
112 }
OLDNEW
« no previous file with comments | « pkg/string_scanner/README.md ('k') | pkg/string_scanner/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698