// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. /** * @author Simon Thoresen Hult */ options { CACHE_TOKENS = true; DEBUG_PARSER = false; ERROR_REPORTING = true; IGNORE_CASE = true; STATIC = false; UNICODE_INPUT = true; USER_CHAR_STREAM = true; USER_TOKEN_MANAGER = false; } PARSER_BEGIN(SelectParser) package com.yahoo.document.select.parser; import com.yahoo.document.select.rule.*; import java.math.BigInteger; import java.util.List; import java.util.ArrayList; public class SelectParser { } PARSER_END(SelectParser) SKIP : { " " | "\f" | "\n" | "\r" | "\t" } TOKEN : { (["l","L"])? | (["l","L"])? | (["l","L"])?> | <#DECIMAL: ["1"-"9"] (["0"-"9"])*> | <#HEX: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+> | <#OCTAL: "0" (["0"-"7"])*> | )? (["f","F","d","D"])?> | <#EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+> } TOKEN : { | | | | | | | | | ="> | | | "> | | | | | | | | | | | | | | | | | | | } ExpressionNode expression() : { ExpressionNode ret = new LiteralNode(true); } { ( [ ret = logic() ] ) { return ret; } } ExpressionNode logic() : { LogicNode lst = new LogicNode(); String op = null; ExpressionNode node; } { ( node = negation() { lst.add(null, node); } ( ( | ) { op = token.image; } node = negation() { lst.add(op, node); } )* ) { return op != null ? lst : node; } } ExpressionNode negation() : { boolean not = false; ExpressionNode node; } { ( [ { not = true; } ] node = relational() ) { return not ? new NegationNode(node) : node; } } NowNode now() : { } { ( ) { return new NowNode(); } } ExpressionNode relational() : { ExpressionNode lhs, rhs = null; String op = null; } { ( lhs = arithmetic() [ ( | | | | | | | ) { op = token.image; } rhs = arithmetic() ] ) { return rhs != null ? new ComparisonNode(lhs, op, rhs) : lhs; } } ExpressionNode arithmetic() : { ArithmeticNode lst = new ArithmeticNode(); String op = null; ExpressionNode node; } { ( node = attribute() { lst.add(null, node); } ( ( | |
| | ) { op = token.image; } node = attribute() { lst.add(op, node); } )* ) { return op != null ? lst : node; } } VariableNode variable() : { VariableNode ret; } { ( identifier() { ret = new VariableNode(token.image); } ) { return ret; } } ExpressionNode attribute() : { ExpressionNode value; AttributeNode.Item item; List items = new ArrayList(); } { ( value = value() ( identifier() { item = new AttributeNode.Item(token.image); } [ { item.setType(AttributeNode.Item.FUNCTION); } ] { items.add(item); } )* ) { if ( ! items.isEmpty()) // A value followed by dotted access/method call return new AttributeNode(value, items); if (value instanceof DocumentNode) // A standalone document type access: Convert to exact type matching return new DocumentTypeNode(((DocumentNode)value).getType()); return value; } } ExpressionNode value() : { ExpressionNode ret; } { ( LOOKAHEAD(2) ( ret = id() | ret = literal() | ret = variable() | ret = now() | ret = logic() { ret = new EmbracedNode(ret); } ) | ( ret = document() ) ) { return ret; } } DocumentNode document() : { DocumentNode ret; } { ( identifier() { ret = new DocumentNode(token.image); } ) { return ret; } } void identifier() : { } { ( | | | | | | | | | | | | | | // | Causes a choice conflict, but it is not such a good name anyway ... ) } IdNode id() : { IdNode ret = new IdNode(); } { ( [ LOOKAHEAD(2) ( { ret.setField(token.image); } | { ret.setField(token.image); } | { ret.setField(token.image); } | { ret.setField(token.image); } | { ret.setField(token.image); } | { ret.setField(token.image); } | { ret.setField(token.image); } ) ] ) { return ret; } } LiteralNode literal() : { String sign = ""; Object ret = null; } { ( ( [ { sign = "-"; } ] ( { ret = Double.parseDouble(sign + token.image); } | { ret = SelectParserUtils.decodeLong(sign + token.image); } ) ) | ( { ret = Double.parseDouble(token.image); } ) | ( { ret = SelectParserUtils.unquote(token.image); } ) | ( { ret = true; } ) | ( { ret = false; } ) | ( { ret = null; } ) ) { return new LiteralNode(ret); } }