package com.bigdata.rdf.sparql.ast;
import java.util.Map;
import com.bigdata.bop.BOp;
import com.bigdata.bop.NV;
/**
* AST Node used to represent a property path.
*
* See http://www.w3.org/TR/sparql11-query/#rTriplesSameSubjectPath for details.
*
* This class corresponds to "VerbPath".
*
* A VerbPath (PathNode) has one Path.
* VerbPath ::= Path
*
* A Path has one PathAlternative.
* Path ::= PathAlt
*
* A PathAlternative has one or more PathSequences.
* PathAlternative ::= PathSequence ( '|' PathSequence )*
*
* A PathSequence has one or more PathEltOrInverses.
* PathSequence ::= PathEltOrInverse ( '/' PathEltOrInverse )*
*
* A PathEltOrInverse has one PathElt and a boolean flag for inverse ('^').
* PathEltOrInverse ::= PathElt | '^' PathElt
*
* A PathElt has a PathPrimary and an optional PathMod.
* PathElt ::= PathPrimary PathMod?
*
* A PathPrimary has either an iri, a PathNegatedPropertySet, or a nested Path.
* PathPrimary ::= iri | '!' PathNegatedPropertySet | '(' Path ')'
*
* A PathMod is one from the enumeration '?', '*', or '+'. '?' means zero or
* one (simple optional), '+' means one or more (fixed point), and '*' means
* zero or more (optional fixed point).
* PathMod ::= '?' | '*' | '+'
*
* A PathNegatedPropertySet is zero or more PathOneInPropertySets.
* PathNegatedPropertySet ::= PathOneInPropertySet |
* '(' (PathOneInPropertySet ( '|' PathOneInPropertySet )* )? ')'
*
* A PathOneInPropertySet is an iri and a boolean flag for inverse ('^').
* PathOneInPropertySet ::= iri | '^' iri
*
* This model is actually flattened a bit by Sesame, so I followed Sesame's
* model instead of the grammar. In Sesame's model, the top level is
* PathAlternative, which contains one or more PathSequences. Each
* PathSequence contains one or more PathElt. Each PathElt has two modifiers -
* the PathMod (for arbitrary length and zero length paths) and the inverse
* modifier. It also has the actual element - one of either a TermNode,
* a nested path (a PathAlternative), a NegatedPropertySet, or a zero
* length path.
*
* @author mikepersonick
*/
public class PathNode extends ASTBase {
/**
*
*/
private static final long serialVersionUID = -4396141823074067307L;
/**
* Constructor required for {@link com.bigdata.bop.BOpUtility#deepCopy(FilterNode)}.
*/
public PathNode(PathNode op) {
super(op);
}
/**
* Required shallow copy constructor.
*/
public PathNode(final BOp[] args, final Map<String, Object> anns) {
super(args, anns);
}
public PathNode(final PathAlternative arg) {
this(new BOp[] { arg }, BOp.NOANNS);
}
/**
* The root of the property path is always a PathAlternative.
*/
public PathAlternative getPathAlternative() {
return (PathAlternative) get(0);
}
/**
* Used to signify an OR (UNION) of multiple possible subpaths.
*/
public static class PathAlternative extends ASTBase {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* Constructor required for {@link com.bigdata.bop.BOpUtility#deepCopy(FilterNode)}.
*/
public PathAlternative(PathAlternative op) {
super(op);
}
/**
* Required shallow copy constructor.
*/
public PathAlternative(final BOp[] args, final Map<String, Object> anns) {
super(args, anns);
}
public PathAlternative(final PathSequence... args) {
this(args, BOp.NOANNS);
if (args == null || args.length == 0)
throw new IllegalArgumentException("one or more args required");
}
}
/**
* A sequence of paths (JOINS).
*/
public static class PathSequence extends ASTBase {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* Constructor required for {@link com.bigdata.bop.BOpUtility#deepCopy(FilterNode)}.
*/
public PathSequence(PathSequence op) {
super(op);
}
/**
* Required shallow copy constructor.
*/
public PathSequence(final BOp[] args, final Map<String, Object> anns) {
super(args, anns);
}
public PathSequence(final PathElt... args) {
this(args, BOp.NOANNS);
if (args == null || args.length == 0)
throw new IllegalArgumentException("one or more args required");
}
}
/**
* A specific path element. Can be a nested path (a PathAlternative).
*/
public static class PathElt extends ASTBase {
/**
*
*/
private static final long serialVersionUID = 1L;
interface Annotations extends ASTBase.Annotations {
/**
* The inverse modifier '^'.
*/
String INVERSE = Annotations.class.getName() + ".inverse";
/**
* The cardinality modifiers '?', '*', and '+'.
*/
String MOD = Annotations.class.getName() + ".mod";
}
/**
* Constructor required for {@link com.bigdata.bop.BOpUtility#deepCopy(FilterNode)}.
*/
public PathElt(PathElt op) {
super(op);
}
/**
* Required shallow copy constructor.
*/
public PathElt(final BOp[] args, final Map<String, Object> anns) {
super(args, anns);
}
/**
* @see {@link #PathNode(BOp, boolean, PathMod)}.
*/
public PathElt(final BOp arg) {
this(arg, false);
}
/**
* @see {@link #PathNode(BOp, boolean, PathMod)}.
*/
public PathElt(final BOp arg, final boolean inverse) {
this(arg, inverse, null);
}
/**
* @see {@link #PathNode(BOp, boolean, PathMod)}.
*/
public PathElt(final BOp arg, final PathMod mod) {
this(arg, false, mod);
}
/**
* @param arg Must be one of the following types:
* <ul>
* <li>{@link ConstantNode}</li>
* <li>{@link PathAlternative}</li>
* <li>{@link PathNegatedPropertySet}</li>
* <li>{@link ZeroLengthPathNode}</li>
* <ul>
*/
public PathElt(final BOp arg, final boolean inverse, final PathMod mod) {
this(new BOp[] { arg }, NV.asMap(
new NV(Annotations.INVERSE, inverse),
new NV(Annotations.MOD, mod)));
if (!(arg instanceof ConstantNode ||
arg instanceof PathAlternative ||
arg instanceof PathNegatedPropertySet ||
arg instanceof ZeroLengthPathNode)) {
throw new IllegalArgumentException();
}
}
public boolean inverse() {
return (Boolean) super.getRequiredProperty(Annotations.INVERSE);
}
public void setInverse(final boolean inverse) {
super.setProperty(Annotations.INVERSE, inverse);
}
public PathMod getMod() {
return (PathMod) super.getProperty(Annotations.MOD);
}
public void setMod(final PathMod mod) {
super.setProperty(Annotations.MOD, mod);
}
public boolean isIRI() {
return get(0) instanceof ConstantNode;
}
public boolean isNestedPath() {
return get(0) instanceof PathAlternative;
}
public boolean isNegatedPropertySet() {
return get(0) instanceof PathNegatedPropertySet;
}
public boolean isZeroLengthPath() {
return get(0) instanceof ZeroLengthPathNode;
}
}
public static enum PathMod {
ZERO_OR_ONE("?"),
ZERO_OR_MORE("*"),
ONE_OR_MORE("+");
final String mod;
PathMod(final String mod) {
this.mod = mod;
}
public String toString() {
return mod;
}
}
public static class PathNegatedPropertySet extends ASTBase {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* Constructor required for {@link com.bigdata.bop.BOpUtility#deepCopy(FilterNode)}.
*/
public PathNegatedPropertySet(PathNegatedPropertySet op) {
super(op);
}
/**
* Required shallow copy constructor.
*/
public PathNegatedPropertySet(final BOp[] args, final Map<String, Object> anns) {
super(args, anns);
}
public PathNegatedPropertySet(final PathOneInPropertySet... args) {
this(args, BOp.NOANNS);
}
}
public static class PathOneInPropertySet extends ASTBase {
/**
*
*/
private static final long serialVersionUID = 1L;
interface Annotations extends ASTBase.Annotations {
String INVERSE = Annotations.class.getName() + ".inverse";
}
/**
* Constructor required for {@link com.bigdata.bop.BOpUtility#deepCopy(FilterNode)}.
*/
public PathOneInPropertySet(PathOneInPropertySet op) {
super(op);
}
/**
* Required shallow copy constructor.
*/
public PathOneInPropertySet(final BOp[] args, final Map<String, Object> anns) {
super(args, anns);
}
public PathOneInPropertySet(final ConstantNode arg) {
this(arg, false);
}
public PathOneInPropertySet(final ConstantNode arg, final boolean inverse) {
this(new BOp[] { arg }, NV.asMap(new NV(Annotations.INVERSE, inverse)));
}
public boolean inverse() {
return (Boolean) super.getRequiredProperty(Annotations.INVERSE);
}
}
}