Line data Source code
1 : // Copyright (c) 2016, 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 boolean selector.
12 : ///
13 : /// Boolean selectors use a stripped-down version of the Dart expression syntax
14 : /// that only contains variables, parentheses, and boolean operators. Variables
15 : /// may also contain dashes, contrary to Dart's syntax; this allows consistency
16 : /// with command-line arguments.
17 : class Parser {
18 : /// The scanner that tokenizes the selector.
19 : final Scanner _scanner;
20 :
21 : Parser(String selector)
22 0 : : _scanner = new Scanner(selector);
23 :
24 : /// Parses the selector.
25 : ///
26 : /// This must only be called once per parser.
27 : Node parse() {
28 0 : var selector = _conditional();
29 :
30 0 : if (_scanner.peek().type != TokenType.endOfFile) {
31 0 : throw new SourceSpanFormatException(
32 0 : "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 0 : var condition = _or();
45 0 : if (!_scanner.scan(TokenType.questionMark)) return condition;
46 :
47 0 : var whenTrue = _conditional();
48 0 : if (!_scanner.scan(TokenType.colon)) {
49 0 : throw new SourceSpanFormatException(
50 0 : 'Expected ":".', _scanner.peek().span);
51 : }
52 :
53 0 : var whenFalse = _conditional();
54 0 : return new ConditionalNode(condition, whenTrue, whenFalse);
55 : }
56 :
57 : /// Parses a logical or:
58 : ///
59 : /// logicalOrExpression:
60 : /// logicalAndExpression ("||" logicalOrExpression)?
61 : Node _or() {
62 0 : var left = _and();
63 0 : if (!_scanner.scan(TokenType.or)) return left;
64 0 : return new OrNode(left, _or());
65 : }
66 :
67 : /// Parses a logical and:
68 : ///
69 : /// logicalAndExpression:
70 : /// simpleExpression ("&&" logicalAndExpression)?
71 : Node _and() {
72 0 : var left = _simpleExpression();
73 0 : if (!_scanner.scan(TokenType.and)) return left;
74 0 : 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 0 : var token = _scanner.next();
85 0 : switch (token.type) {
86 0 : case TokenType.not:
87 0 : var child = _simpleExpression();
88 0 : return new NotNode(child, token.span.expand(child.span));
89 :
90 0 : case TokenType.leftParen:
91 0 : var child = _conditional();
92 0 : if (!_scanner.scan(TokenType.rightParen)) {
93 0 : throw new SourceSpanFormatException(
94 0 : 'Expected ")".', _scanner.peek().span);
95 : }
96 : return child;
97 :
98 0 : case TokenType.identifier:
99 0 : return new VariableNode((token as IdentifierToken).name, token.span);
100 :
101 : default:
102 0 : throw new SourceSpanFormatException("Expected expression.", token.span);
103 : }
104 : }
105 : }
|