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

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

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

Powered by Google App Engine
This is Rietveld 408576698