Chromium Code Reviews| Index: lib/src/backend/platform_selector/parser.dart |
| diff --git a/lib/src/backend/platform_selector/parser.dart b/lib/src/backend/platform_selector/parser.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..83468d6af14d0d08b89ae9524ec23f70ba05d7e2 |
| --- /dev/null |
| +++ b/lib/src/backend/platform_selector/parser.dart |
| @@ -0,0 +1,110 @@ |
| +// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +library unittest.backend.platform_selector.parser; |
| + |
| +import 'package:source_span/source_span.dart'; |
| + |
| +import 'ast.dart'; |
| +import 'scanner.dart'; |
| +import 'token.dart'; |
| + |
| +/// A class for parsing a platform selector. |
| +/// |
| +/// Platform selectors use a stripped-down version of the Dart expression |
| +/// syntax that only contains variables, parentheses, and boolean operators. |
| +/// Variables may also contain dashes, contrary to Dart's syntax; this allows |
| +/// 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
|
| +class Parser { |
| + /// The scanner that tokenizes the selector. |
| + final Scanner _scanner; |
| + |
| + Parser(String selector) |
| + : _scanner = new Scanner(selector); |
| + |
| + /// Parses the selector. |
| + /// |
| + /// This must only be called once per parser. |
| + Node parse() { |
| + var selector = _conditional(); |
| + |
| + if (_scanner.peek().type != TokenType.endOfFile) { |
| + throw new SourceSpanFormatException( |
| + "Expected end of input.", _scanner.peek().span); |
| + } |
| + |
| + return selector; |
| + } |
| + |
| + /// Parses a conditional: |
| + /// |
| + /// conditionalExpression: |
| + /// logicalOrExpression ("?" conditionalExpression ":" |
| + /// conditionalExpression)? |
| + Node _conditional() { |
| + var condition = _or(); |
| + if (_scanner.peek().type != TokenType.questionMark) return condition; |
| + |
| + _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.
|
| + var branch1 = _conditional(); |
| + var token = _scanner.next(); |
| + if (token.type != TokenType.colon) { |
| + throw new SourceSpanFormatException('Expected ":".', token.span); |
| + } |
| + |
| + var branch2 = _conditional(); |
| + return new ConditionalNode(condition, branch1, branch2); |
| + } |
| + |
| + /// Parses a logical or: |
| + /// |
| + /// logicalOrExpression: |
| + /// logicalAndExpression ("||" logicalOrExpression)? |
| + Node _or() { |
| + var branch1 = _and(); |
| + if (_scanner.peek().type != TokenType.or) return branch1; |
| + _scanner.next(); |
| + return new OrNode(branch1, _or()); |
| + } |
| + |
| + /// Parses a logical and: |
| + /// |
| + /// logicalAndExpression: |
| + /// simpleExpression ("&&" logicalAndExpression)? |
| + Node _and() { |
| + var branch1 = _simpleExpression(); |
| + if (_scanner.peek().type != TokenType.and) return branch1; |
| + _scanner.next(); |
| + return new AndNode(branch1, _and()); |
| + } |
| + |
| + /// Parses a simple expression: |
| + /// |
| + /// simpleExpression: |
| + /// "!" simpleExpression | |
| + /// "(" conditionalExpression ")" | |
| + /// IDENTIFIER |
| + Node _simpleExpression() { |
| + var token = _scanner.next(); |
| + switch (token.type) { |
| + case TokenType.not: |
| + var child = _simpleExpression(); |
| + return new NotNode(child, token.span.expand(child.span)); |
| + |
| + case TokenType.leftParen: |
| + var child = _conditional(); |
| + var next = _scanner.next(); |
| + if (next.type != TokenType.rightParen) { |
| + throw new SourceSpanFormatException('Expected ")".', next.span); |
| + } |
| + return child; |
| + |
| + case TokenType.identifier: |
| + return new VariableNode(token.name, token.span); |
| + |
| + default: |
| + throw new SourceSpanFormatException("Expected expression.", token.span); |
| + } |
| + } |
| +} |