/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
package lux.xpath;
import lux.xquery.VariableContext;
/**
* A path expression represents two expressions joined with a "/"
* @author sokolov
*
*/
public class PathExpression extends AbstractExpression {
public PathExpression (AbstractExpression lhs, AbstractExpression rhs) {
super (Type.PATH_EXPRESSION);
subs = new AbstractExpression[2];
setSubs (lhs, rhs);
}
public final AbstractExpression getRHS() {
return subs[1];
}
public final AbstractExpression getLHS() {
return subs[0];
}
/**
* @return 18
*/
@Override public int getPrecedence () {
return 18;
}
@Override
public void toString(StringBuilder buf) {
if (! (subs[0] instanceof Root)) {
appendSub (buf, subs[0]);
}
buf.append('/');
appendSub(buf, subs[1]);
}
/**
* Whenever we see a new absolute context (/, collection(), search()), its dependent
* expressions are a possible target for optimization.
* @return the root of this path, or null if it is not an absolute path.
*/
@Override
public AbstractExpression getRoot() {
return subs[0].getRoot();
}
@Override
public AbstractExpression accept(ExpressionVisitor visitor) {
acceptSubs(visitor);
return visitor.visit(this);
}
/**
* @return the leftmost path sub-expression
*/
@Override
public AbstractExpression getHead() {
return subs[0].getHead();
}
/**
* @return the expression remaining after removing the left-most sub-expression (the CDR).
*/
@Override
public AbstractExpression getTail() {
AbstractExpression left = subs[0].getTail();
if (left == null) {
return subs[1];
}
return new PathExpression (left, subs[1]);
}
/**
* @return the rightmost step of this path expression
*/
@Override
public AbstractExpression getLastContextStep() {
AbstractExpression expr = subs[1].getLastContextStep();
if (expr.getType() == Type.PATH_STEP) {
return expr;
}
return subs[0].getLastContextStep();
}
/**
* @return the context in which a variable in the LHS of the path is bound, if any
*/
@Override
public VariableContext getBindingContext () {
return subs[0].getBindingContext();
}
@Override
public boolean isRestrictive () {
return true;
}
/**
* @param other another expression
* @return whether the two expressions are s.t. this expr is non-empty
* whenever (for whichever contexts) the other one is.
*/
@Override
public boolean geq (AbstractExpression other) {
return other instanceof PathExpression || other instanceof Predicate;
}
@Override
public boolean matchDown (AbstractExpression fieldExpr, AbstractExpression fromExpr) {
if (! fieldExpr.geq(this)) {
// if fieldExpr does not encompass this at least formally, it is too restrictive
return false;
}
if (fieldExpr.subs == null || fieldExpr.subs.length == 0) {
return true;
}
// fieldExpr must be either a path expression or a predicate
return subs[0].matchDown(fieldExpr.subs[0], fromExpr)
&&
subs[1].matchDown(fieldExpr.subs[1], fromExpr);
}
}
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */