/* * eXist Open Source Native XML Database * * Copyright (C) 2001-06, Wolfgang M. Meier (meier@ifs.tu-darmstadt.de) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Id$ */ package org.exist.xquery; import org.apache.log4j.Logger; import org.exist.xquery.util.ExpressionDumper; import org.exist.xquery.value.Item; import org.exist.xquery.value.Sequence; import org.exist.xquery.value.Type; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public abstract class Step extends AbstractExpression { protected final static Logger LOG = Logger.getLogger(Step.class); protected int axis = Constants.UNKNOWN_AXIS; protected boolean abbreviatedStep = false; protected ArrayList predicates = new ArrayList(); protected NodeTest test; protected boolean inPredicate = false; protected int staticReturnType = Type.ITEM; protected boolean hasPositionalPredicate = false; public Step( XQueryContext context, int axis ) { super(context); this.axis = axis; } public Step( XQueryContext context, int axis, NodeTest test ) { this( context, axis ); this.test = test; } public void addPredicate( Expression expr ) { predicates.add( expr ); } public void insertPredicate(Expression previous, Expression predicate) { int idx = predicates.indexOf(previous); if (idx < 0) { LOG.warn("Old predicate not found: " + ExpressionDumper.dump(previous) + "; in: " + ExpressionDumper.dump(this)); return; } predicates.add(idx + 1, predicate); } public boolean hasPredicates() { return predicates.size() > 0; } public List getPredicates() { return predicates; } /* (non-Javadoc) * @see org.exist.xquery.Expression#analyze(org.exist.xquery.AnalyzeContextInfo) */ public void analyze(AnalyzeContextInfo contextInfo) throws XPathException { //context.("t") if (test != null && test.getName() != null && test.getName().getPrefix() != null && !test.getName().getPrefix().equals("") && context.inScopePrefixes != null && context.getURIForPrefix(test.getName().getPrefix()) == null) throw new XPathException(this, "XPST0081 : undeclared prefix '" + test.getName().getPrefix() + "'"); inPredicate = (contextInfo.getFlags() & IN_PREDICATE) > 0; this.contextId = contextInfo.getContextId(); if (predicates.size() > 0) { AnalyzeContextInfo newContext = new AnalyzeContextInfo(contextInfo); newContext.setStaticType(this.axis == Constants.SELF_AXIS ? contextInfo.getStaticType() : Type.NODE); newContext.setParent(this); newContext.setContextStep(this); for ( Iterator i = predicates.iterator(); i.hasNext(); ) { ((Predicate) i.next()).analyze(newContext); } if (predicates.size() == 1 && (newContext.getFlags() & POSITIONAL_PREDICATE) != 0) hasPositionalPredicate = true; } // if we are on the self axis, remember the static return type given in the context if (this.axis == Constants.SELF_AXIS) staticReturnType = contextInfo.getStaticType(); } public abstract Sequence eval( Sequence contextSequence, Item contextItem ) throws XPathException; public int getAxis() { return axis; } /* (non-Javadoc) * @see org.exist.xquery.AbstractExpression#setPrimaryAxis(int) */ public void setPrimaryAxis(int axis) { this.axis = axis; } public int getPrimaryAxis() { return this.axis; } public boolean isAbbreviated() { return abbreviatedStep; } public void setAbbreviated(boolean abbrev) { abbreviatedStep = abbrev; } /* (non-Javadoc) * @see org.exist.xquery.Expression#dump(org.exist.xquery.util.ExpressionDumper) */ public void dump(ExpressionDumper dumper) { if (axis != Constants.UNKNOWN_AXIS) dumper.display( Constants.AXISSPECIFIERS[axis] ); dumper.display( "::" ); if ( test != null ) //TODO : toString() or... dump ? dumper.display( test.toString() ); else dumper.display( "node()" ); if ( predicates.size() > 0 ) for ( Iterator i = predicates.iterator(); i.hasNext(); ) { ( (Predicate) i.next() ).dump(dumper); } } public String toString() { StringBuilder result = new StringBuilder(); if ( axis != Constants.UNKNOWN_AXIS) result.append( Constants.AXISSPECIFIERS[axis] ); result.append( "::" ); if ( test != null ) result.append( test.toString() ); else result.append( "node()" ); if ( predicates.size() > 0 ) for ( Iterator i = predicates.iterator(); i.hasNext(); ) { result.append(i.next().toString()); } return result.toString(); } //TODO : not sure about this one... /* public int getDependencies() { if (test == null) return Dependency.CONTEXT_SET; else return Dependency.CONTEXT_SET + Dependency.CONTEXT_ITEM; } */ public int returnsType() { //Polysemy of "." which might be atomic if the context sequence is atomic itself if (axis == Constants.SELF_AXIS) { //Type.ITEM by default : this may change *after* evaluation // LOG.debug("My static type: " + Type.getTypeName(staticReturnType)); return staticReturnType; } else return Type.NODE; } public int getCardinality() { return Cardinality.ZERO_OR_MORE; } public void setAxis( int axis ) { this.axis = axis; } public void setTest( NodeTest test ) { this.test = test; } public NodeTest getTest() { return test; } /* (non-Javadoc) * @see org.exist.xquery.AbstractExpression#resetState() */ public void resetState(boolean postOptimization) { super.resetState(postOptimization); for (Iterator i = predicates.iterator(); i.hasNext();) { Predicate pred = (Predicate) i.next(); pred.resetState(postOptimization); } } }