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

Side by Side Diff: lib/src/backend/platform_selector/scanner.dart

Issue 997593003: Add a scanner and parser for platform selectors. (Closed) Base URL: git@github.com:dart-lang/unittest@master
Patch Set: A few more fixes from better future knowledge Created 5 years, 9 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
OLDNEW
(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 unittest.backend.platform_selector.scanner;
6
7 import 'package:string_scanner/string_scanner.dart';
8
9 import 'token.dart';
10
11 /// A regular expression matching both whitespace and single-line comments.
12 ///
13 /// This will only match if consumes at least one character.
14 final _whitespaceAndSingleLineComments =
15 new RegExp(r"([ \t\n]+|//[^\n]*(\n|$))+");
16
17 /// A regular expression matching the body of a multi-line comment, after `/*`
18 /// but before `*/` or a nested `/*`.
19 ///
20 /// This will only match if it consumes at least one character.
21 final _multiLineCommentBody = new RegExp(r"([^/*]|/[^*]|\*[^/])+");
22
23 /// A regular expression matching an identifier.
24 ///
25 /// Unlike standard Dart identifiers, platform selector identifiers may
26 /// contain dashes for consistency with command-line arguments.
27 final _identifier = new RegExp(r"[a-zA-Z_-][a-zA-Z0-9_-]*");
28
29 /// A scanner that converts a platform selector string into a stream of
30 /// tokens.
31 class Scanner {
32 /// The underlying string scanner.
33 final SpanScanner _scanner;
34
35 /// The next token to emit.
36 Token _next;
37
38 /// Whether the scanner has emitted a [TokenType.endOfFile] token.
39 bool _endOfFileEmitted = false;
40
41 Scanner(String selector)
42 : _scanner = new SpanScanner(selector);
43
44 /// Returns the next token that will be returned by [next].
45 ///
46 /// Throws a [StateError] if [next] has already returned a
47 /// [TokenType.endOfFile] token.
48 Token peek() {
49 if (_next == null) _next = _getNext();
50 return _next;
51 }
52
53 /// Consumes and returns the next token in the stream.
54 ///
55 /// Throws a [StateError] if this has already returned a
56 /// [TokenType.endOfFile] token.
57 Token next() {
58 var token = _next == null ? _getNext() : _next;
59 _endOfFileEmitted = token.type == TokenType.endOfFile;
60 _next = null;
61 return token;
62 }
63
64 /// Scan and return the next token in the stream.
65 Token _getNext() {
66 if (_endOfFileEmitted) {
67 throw new StateError("No more tokens.");
Bob Nystrom 2015/03/11 20:05:52 Nit: you could make this a one-line if if you want
nweiz 2015/03/12 19:48:57 Done.
68 }
69
70 _consumeWhitespace();
71 if (_scanner.isDone) {
72 return new Token(
73 TokenType.endOfFile, _scanner.spanFrom(_scanner.state));
74 }
75
76 switch (_scanner.peekChar()) {
77 case 0x28 /* ( */: return _scanOperator(TokenType.leftParen);
78 case 0x29 /* ) */: return _scanOperator(TokenType.rightParen);
79 case 0x3F /* ? */: return _scanOperator(TokenType.questionMark);
80 case 0x3A /* : */: return _scanOperator(TokenType.colon);
81 case 0x21 /* ! */: return _scanOperator(TokenType.not);
82 case 0x7C /* | */: return _scanOr();
83 case 0x26 /* & */: return _scanAnd();
84 default: return _scanIdentifier();
85 }
86 }
87
88 /// Scans a single-character operator and returns a token of type [type].
89 ///
90 /// This assumes that the caller has already verified that the next character
91 /// is correct for the given operator.
92 Token _scanOperator(TokenType type) {
93 var start = _scanner.state;
94 _scanner.readChar();
95 return new Token(type, _scanner.spanFrom(start));
96 }
97
98 /// Scans a `||` operator and returns the appropriate token.
99 ///
100 /// This validates that the next two characters are `||`.
101 Token _scanOr() {
102 var start = _scanner.state;
103 _scanner.expect("||");
104 return new Token(TokenType.or, _scanner.spanFrom(start));
105 }
106
107 /// Scans a `&&` operator and returns the appropriate token.
108 ///
109 /// This validates that the next two characters are `&&`.
110 Token _scanAnd() {
111 var start = _scanner.state;
112 _scanner.expect("&&");
113 return new Token(TokenType.and, _scanner.spanFrom(start));
114 }
115
116 /// Scans and returns an identifier token.
117 Token _scanIdentifier() {
118 _scanner.expect(_identifier, name: "expression");
119 return new IdentifierToken(_scanner.lastMatch[0], _scanner.lastSpan);
120 }
121
122 /// Consumes all whitespace and comments immediately following the cursor's
123 /// current position.
124 void _consumeWhitespace() {
125 while (_scanner.scan(_whitespaceAndSingleLineComments) ||
126 _multiLineComment()) {
127 // Do nothing.
128 }
129 }
130
131 /// Consumes a single multi-line comment.
132 ///
133 /// Returns whether or not a comment was consumed.
134 bool _multiLineComment() {
135 if (!_scanner.scan("/*")) return false;
136
137 while (_scanner.scan(_multiLineCommentBody) || _multiLineComment()) {
138 // Do nothing.
139 }
140 _scanner.expect("*/");
141
142 return true;
143 }
144 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698