OLD | NEW |
---|---|
(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.parser; | |
6 | |
7 import 'package:source_span/source_span.dart'; | |
8 | |
9 import 'ast.dart'; | |
10 import 'scanner.dart'; | |
11 import 'token.dart'; | |
12 | |
13 /// A class for parsing a platform selector. | |
14 /// | |
15 /// Platform selectors use a stripped-down version of the Dart expression | |
16 /// syntax that only contains variables, parentheses, and boolean operators. | |
17 /// Variables may also contain dashes, contrary to Dart's syntax; this allows | |
18 /// consistency with command-line arguments. | |
Bob Nystrom
2015/03/11 20:05:52
Does this add enough value to be worth the possibl
nweiz
2015/03/12 19:48:57
I think so. A lot of the identifiers that people w
| |
19 class Parser { | |
20 /// The scanner that tokenizes the selector. | |
21 final Scanner _scanner; | |
22 | |
23 Parser(String selector) | |
24 : _scanner = new Scanner(selector); | |
25 | |
26 /// Parses the selector. | |
27 /// | |
28 /// This must only be called once per parser. | |
29 Node parse() { | |
30 var selector = _conditional(); | |
31 | |
32 if (_scanner.peek().type != TokenType.endOfFile) { | |
33 throw new SourceSpanFormatException( | |
34 "Expected end of input.", _scanner.peek().span); | |
35 } | |
36 | |
37 return selector; | |
38 } | |
39 | |
40 /// Parses a conditional: | |
41 /// | |
42 /// conditionalExpression: | |
43 /// logicalOrExpression ("?" conditionalExpression ":" | |
44 /// conditionalExpression)? | |
45 Node _conditional() { | |
46 var condition = _or(); | |
47 if (_scanner.peek().type != TokenType.questionMark) return condition; | |
48 | |
49 _scanner.next(); | |
Bob Nystrom
2015/03/11 20:05:52
You could simplify this (and a bunch below) by add
nweiz
2015/03/12 19:48:57
Done.
| |
50 var branch1 = _conditional(); | |
51 var token = _scanner.next(); | |
52 if (token.type != TokenType.colon) { | |
53 throw new SourceSpanFormatException('Expected ":".', token.span); | |
54 } | |
55 | |
56 var branch2 = _conditional(); | |
57 return new ConditionalNode(condition, branch1, branch2); | |
58 } | |
59 | |
60 /// Parses a logical or: | |
61 /// | |
62 /// logicalOrExpression: | |
63 /// logicalAndExpression ("||" logicalOrExpression)? | |
64 Node _or() { | |
65 var branch1 = _and(); | |
66 if (_scanner.peek().type != TokenType.or) return branch1; | |
67 _scanner.next(); | |
68 return new OrNode(branch1, _or()); | |
69 } | |
70 | |
71 /// Parses a logical and: | |
72 /// | |
73 /// logicalAndExpression: | |
74 /// simpleExpression ("&&" logicalAndExpression)? | |
75 Node _and() { | |
76 var branch1 = _simpleExpression(); | |
77 if (_scanner.peek().type != TokenType.and) return branch1; | |
78 _scanner.next(); | |
79 return new AndNode(branch1, _and()); | |
80 } | |
81 | |
82 /// Parses a simple expression: | |
83 /// | |
84 /// simpleExpression: | |
85 /// "!" simpleExpression | | |
86 /// "(" conditionalExpression ")" | | |
87 /// IDENTIFIER | |
88 Node _simpleExpression() { | |
89 var token = _scanner.next(); | |
90 switch (token.type) { | |
91 case TokenType.not: | |
92 var child = _simpleExpression(); | |
93 return new NotNode(child, token.span.expand(child.span)); | |
94 | |
95 case TokenType.leftParen: | |
96 var child = _conditional(); | |
97 var next = _scanner.next(); | |
98 if (next.type != TokenType.rightParen) { | |
99 throw new SourceSpanFormatException('Expected ")".', next.span); | |
100 } | |
101 return child; | |
102 | |
103 case TokenType.identifier: | |
104 return new VariableNode(token.name, token.span); | |
105 | |
106 default: | |
107 throw new SourceSpanFormatException("Expected expression.", token.span); | |
108 } | |
109 } | |
110 } | |
OLD | NEW |