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