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. | |
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; | |
Bob Nystrom
2015/03/12 20:37:21
Use _scanner.scan(TokenType.questionMark) here?
nweiz
2015/03/12 23:12:54
Done.
| |
48 | |
49 _scanner.next(); | |
50 var whenTrue = _conditional(); | |
51 if (!_scanner.scan(TokenType.colon)) { | |
52 throw new SourceSpanFormatException( | |
53 'Expected ":".', _scanner.peek().span); | |
54 } | |
55 | |
56 var whenFalse = _conditional(); | |
57 return new ConditionalNode(condition, whenTrue, whenFalse); | |
58 } | |
59 | |
60 /// Parses a logical or: | |
61 /// | |
62 /// logicalOrExpression: | |
63 /// logicalAndExpression ("||" logicalOrExpression)? | |
64 Node _or() { | |
65 var left = _and(); | |
66 if (!_scanner.scan(TokenType.or)) return left; | |
67 return new OrNode(left, _or()); | |
68 } | |
69 | |
70 /// Parses a logical and: | |
71 /// | |
72 /// logicalAndExpression: | |
73 /// simpleExpression ("&&" logicalAndExpression)? | |
74 Node _and() { | |
75 var left = _simpleExpression(); | |
76 if (!_scanner.scan(TokenType.and)) return left; | |
77 return new AndNode(left, _and()); | |
78 } | |
79 | |
80 /// Parses a simple expression: | |
81 /// | |
82 /// simpleExpression: | |
83 /// "!" simpleExpression | | |
84 /// "(" conditionalExpression ")" | | |
85 /// IDENTIFIER | |
86 Node _simpleExpression() { | |
87 var token = _scanner.next(); | |
88 switch (token.type) { | |
89 case TokenType.not: | |
90 var child = _simpleExpression(); | |
91 return new NotNode(child, token.span.expand(child.span)); | |
92 | |
93 case TokenType.leftParen: | |
94 var child = _conditional(); | |
95 if (!_scanner.scan(TokenType.rightParen)) { | |
96 throw new SourceSpanFormatException( | |
97 'Expected ")".', _scanner.peek().span); | |
98 } | |
99 return child; | |
100 | |
101 case TokenType.identifier: | |
102 return new VariableNode(token.name, token.span); | |
103 | |
104 default: | |
105 throw new SourceSpanFormatException("Expected expression.", token.span); | |
106 } | |
107 } | |
108 } | |
OLD | NEW |