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..162e097c3d6e602380fe6be97cec033bbcfb48d6 |
| --- /dev/null |
| +++ b/lib/src/backend/platform_selector/parser.dart |
| @@ -0,0 +1,108 @@ |
| +// 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. |
| +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; |
|
Bob Nystrom
2015/03/12 20:37:21
Use _scanner.scan(TokenType.questionMark) here?
nweiz
2015/03/12 23:12:54
Done.
|
| + |
| + _scanner.next(); |
| + var whenTrue = _conditional(); |
| + if (!_scanner.scan(TokenType.colon)) { |
| + throw new SourceSpanFormatException( |
| + 'Expected ":".', _scanner.peek().span); |
| + } |
| + |
| + var whenFalse = _conditional(); |
| + return new ConditionalNode(condition, whenTrue, whenFalse); |
| + } |
| + |
| + /// Parses a logical or: |
| + /// |
| + /// logicalOrExpression: |
| + /// logicalAndExpression ("||" logicalOrExpression)? |
| + Node _or() { |
| + var left = _and(); |
| + if (!_scanner.scan(TokenType.or)) return left; |
| + return new OrNode(left, _or()); |
| + } |
| + |
| + /// Parses a logical and: |
| + /// |
| + /// logicalAndExpression: |
| + /// simpleExpression ("&&" logicalAndExpression)? |
| + Node _and() { |
| + var left = _simpleExpression(); |
| + if (!_scanner.scan(TokenType.and)) return left; |
| + return new AndNode(left, _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(); |
| + if (!_scanner.scan(TokenType.rightParen)) { |
| + throw new SourceSpanFormatException( |
| + 'Expected ")".', _scanner.peek().span); |
| + } |
| + return child; |
| + |
| + case TokenType.identifier: |
| + return new VariableNode(token.name, token.span); |
| + |
| + default: |
| + throw new SourceSpanFormatException("Expected expression.", token.span); |
| + } |
| + } |
| +} |