blob: 972a4cc54da06671b2cc26a4200dbcdabd21d97b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* $Id$
*/
/*
* @author Jacek Ambroziak
* @author Santiago Pericas-Geertsen
* @author Morten Jorgensen
* @author G. Todd Miller
*/
package org.apache.xalan.xsltc.compiler;
import java.util.Stack;
import java.util.Vector;
import java.io.StringReader;
import java_cup.runtime.*;
import org.apache.xml.dtm.DTM;
import org.apache.xalan.xsltc.DOM;
import org.apache.xml.dtm.Axis;
import org.apache.xalan.xsltc.runtime.Operators;
import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
parser code {:
/**
* Used by function calls with no args.
*/
static public final Vector EmptyArgs = new Vector(0);
/**
* Reference to non-existing variable.
*/
static public final VariableRef DummyVarRef = null;
/**
* Reference to the Parser class.
*/
private Parser _parser;
private XSLTC _xsltc;
/**
* String representation of the expression being parsed.
*/
private String _expression;
/**
* Line number where this expression/pattern was declared.
*/
private int _lineNumber = 0;
/**
* Reference to the symbol table.
*/
public SymbolTable _symbolTable;
public XPathParser(Parser parser) {
_parser = parser;
_xsltc = parser.getXSLTC();
_symbolTable = parser.getSymbolTable();
}
public int getLineNumber() {
return _lineNumber;
}
public QName getQNameIgnoreDefaultNs(String name) {
return _parser.getQNameIgnoreDefaultNs(name);
}
public QName getQName(String namespace, String prefix, String localname) {
return _parser.getQName(namespace, prefix, localname);
}
public void setMultiDocument(boolean flag) {
_xsltc.setMultiDocument(flag);
}
public void setCallsNodeset(boolean flag) {
_xsltc.setCallsNodeset(flag);
}
public void setHasIdCall(boolean flag) {
_xsltc.setHasIdCall(flag);
}
/**
* This method is similar to findNodeType(int, Object) except that it
* creates a StepPattern instead of just returning a node type. It also
* differs in the way it handles "{uri}:*" and "{uri}:@*". The last two
* patterns are expanded as "*[namespace-uri() = 'uri']" and
* "@*[namespace-uri() = 'uri']", respectively. This expansion considerably
* simplifies the grouping of patterns in the Mode class. For this
* expansion to be correct, the priority of the pattern/template must be
* set to -0.25 (when no other predicates are present).
*/
public StepPattern createStepPattern(int axis, Object test, Vector predicates) {
int nodeType;
if (test == null) { // "*"
nodeType = (axis == Axis.ATTRIBUTE) ? NodeTest.ATTRIBUTE :
(axis == Axis.NAMESPACE) ? -1 : NodeTest.ELEMENT;
return new StepPattern(axis, nodeType, predicates);
}
else if (test instanceof Integer) {
nodeType = ((Integer) test).intValue();
return new StepPattern(axis, nodeType, predicates);
}
else {
QName name = (QName)test;
boolean setPriority = false;
if (axis == Axis.NAMESPACE) {
nodeType = (name.toString().equals("*")) ? -1
: _xsltc.registerNamespacePrefix(name);;
}
else {
final String uri = name.getNamespace();
final String local = name.getLocalPart();
final QName namespace_uri =
_parser.getQNameIgnoreDefaultNs("namespace-uri");
// Expand {uri}:* to *[namespace-uri() = 'uri'] - same for @*
if (uri != null && (local.equals("*") || local.equals("@*"))) {
if (predicates == null) {
predicates = new Vector(2);
}
// Priority is set by hand if no other predicates exist
setPriority = (predicates.size() == 0);
predicates.add(
new Predicate(
new EqualityExpr(Operators.EQ,
new NamespaceUriCall(namespace_uri),
new LiteralExpr(uri))));
}
if (local.equals("*")) {
nodeType = (axis == Axis.ATTRIBUTE) ? NodeTest.ATTRIBUTE
: NodeTest.ELEMENT;
}
else if (local.equals("@*")) {
nodeType = NodeTest.ATTRIBUTE;
}
else {
nodeType = (axis == Axis.ATTRIBUTE) ? _xsltc.registerAttribute(name)
: _xsltc.registerElement(name);
}
}
final StepPattern result = new StepPattern(axis, nodeType, predicates);
// Set priority for case prefix:* and prefix:@* (no predicates)
if (setPriority) {
result.setPriority(-0.25);
}
return result;
}
}
public int findNodeType(int axis, Object test) {
if (test == null) { // *
return (axis == Axis.ATTRIBUTE) ?
NodeTest.ATTRIBUTE :
(axis == Axis.NAMESPACE) ? -1 : NodeTest.ELEMENT;
}
else if (test instanceof Integer) {
return ((Integer)test).intValue();
}
else {
QName name = (QName)test;
if (axis == Axis.NAMESPACE) {
return (name.toString().equals("*")) ? -1
: _xsltc.registerNamespacePrefix(name);
}
if (name.getNamespace() == null) {
final String local = name.getLocalPart();
if (local.equals("*")) {
return (axis == Axis.ATTRIBUTE) ? NodeTest.ATTRIBUTE
: NodeTest.ELEMENT;
}
else if (local.equals("@*")) {
return NodeTest.ATTRIBUTE;
}
}
return (axis == Axis.ATTRIBUTE) ? _xsltc.registerAttribute(name)
: _xsltc.registerElement(name);
}
}
/**
* Parse the expression passed to the current scanner. If this
* expression contains references to local variables and it will be
* compiled in an external module (not in the main class) request
* the current template to create a new variable stack frame.
*
* @param lineNumber Line where the current expression is defined.
* @param external Set to <tt>true</tt> if this expression is
* compiled in a separate module.
*
*/
public Symbol parse(String expression, int lineNumber) throws Exception {
try {
_expression = expression;
_lineNumber = lineNumber;
return super.parse();
}
catch (IllegalCharException e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.ILLEGAL_CHAR_ERR,
lineNumber, e.getMessage());
_parser.reportError(Constants.FATAL, err);
}
return null;
}
/**
* Lookup a variable or parameter in the symbol table given its name.
*
* @param name Name of the symbol being looked up.
*/
final SyntaxTreeNode lookupName(QName name) {
// Is it a local var or param ?
final SyntaxTreeNode result = _parser.lookupVariable(name);
if (result != null)
return(result);
else
return(_symbolTable.lookupName(name));
}
public final void addError(ErrorMsg error) {
_parser.reportError(Constants.ERROR, error);
}
public void report_error(String message, Object info) {
final ErrorMsg err = new ErrorMsg(ErrorMsg.SYNTAX_ERR, _lineNumber,
_expression);
_parser.reportError(Constants.FATAL, err);
}
public void report_fatal_error(String message, Object info) {
// empty
}
public RelativeLocationPath insertStep(Step step, RelativeLocationPath rlp) {
if (rlp instanceof Step) {
return new ParentLocationPath(step, (Step) rlp);
}
else if (rlp instanceof ParentLocationPath) {
final ParentLocationPath plp = (ParentLocationPath) rlp;
final RelativeLocationPath newrlp = insertStep(step, plp.getPath());
return new ParentLocationPath(newrlp, plp.getStep());
}
else {
addError(new ErrorMsg(ErrorMsg.INTERNAL_ERR, "XPathParser.insertStep"));
return rlp;
}
}
/**
* Returns true if the axis applies to elements only. The axes
* child, attribute, namespace, descendant result in non-empty
* nodesets only if the context node is of type element.
*/
public boolean isElementAxis(int axis) {
return (axis == Axis.CHILD || axis == Axis.ATTRIBUTE ||
axis == Axis.NAMESPACE || axis == Axis.DESCENDANT);
}
:}
terminal SLASH, DOT, LBRACK, RBRACK, VBAR, LPAREN, RPAREN, STAR, COMMA;
terminal DOLLAR, ATSIGN;
terminal DDOT, DCOLON, DSLASH;
terminal EQ, NE;
terminal LT, GT, LE, GE;
terminal PLUS, MINUS, DIV, MOD, MULT;
terminal String Literal;
terminal String QNAME;
terminal ID, KEY, TEXT, NODE, OR, AND, COMMENT, PI, PIPARAM, PRECEDINGSIBLING;
terminal SELF, PARENT, CHILD, ATTRIBUTE, ANCESTOR, ANCESTORORSELF, DESCENDANT;
terminal DESCENDANTORSELF, FOLLOWING, FOLLOWINGSIBLING, NAMESPACE, PRECEDING;
terminal Double REAL;
terminal Long INT;
terminal PATTERN, EXPRESSION;
non terminal SyntaxTreeNode TopLevel;
non terminal Expression Expr, Argument, LocationPath;
non terminal Expression Predicate, FilterExpr, Step;
non terminal Expression OrExpr, AndExpr, EqualityExpr;
non terminal Expression RelationalExpr, AdditiveExpr;
non terminal Expression MultiplicativeExpr, UnaryExpr;
non terminal Expression VariableReference, FunctionCall;
non terminal Expression PrimaryExpr, UnionExpr, PathExpr, AbbreviatedStep;
non terminal Expression RelativeLocationPath, AbbreviatedRelativeLocationPath;
non terminal Expression AbsoluteLocationPath, AbbreviatedAbsoluteLocationPath;
non terminal Object NodeTest, NameTest;
non terminal IdKeyPattern IdKeyPattern;
non terminal Pattern Pattern;
non terminal Pattern LocationPathPattern;
non terminal StepPattern ProcessingInstructionPattern;
non terminal RelativePathPattern RelativePathPattern;
non terminal StepPattern StepPattern;
non terminal Object NodeTestPattern, NameTestPattern;
non terminal Vector Predicates, NonemptyArgumentList;
non terminal QName QName, FunctionName, VariableName;
non terminal Integer AxisName, AxisSpecifier;
non terminal Integer ChildOrAttributeAxisSpecifier;
precedence left VBAR;
precedence left OR;
precedence left AND;
precedence nonassoc EQ, NE;
precedence left LT, GT, LE, GE;
precedence left PLUS, MINUS;
precedence left DIV, MOD, MULT;
precedence left DOLLAR;
precedence left ATSIGN;
precedence right DCOLON;
start with TopLevel;
TopLevel ::= PATTERN Pattern:pattern
{: RESULT = pattern; :}
| EXPRESSION Expr:expr
{: RESULT = expr; :};
/* --------------------------- Patterns ----------------------------------- */
Pattern ::= LocationPathPattern:lpp
{: RESULT = lpp; :}
| LocationPathPattern:lpp VBAR Pattern:p
{: RESULT = new AlternativePattern(lpp, p); :};
LocationPathPattern ::= SLASH
{: RESULT = new AbsolutePathPattern(null); :}
| SLASH RelativePathPattern:rpp
{: RESULT = new AbsolutePathPattern(rpp); :}
| IdKeyPattern:ikp
{: RESULT = ikp; :}
| IdKeyPattern:ikp SLASH RelativePathPattern:rpp
{: RESULT = new ParentPattern(ikp, rpp); :}
| IdKeyPattern:ikp DSLASH RelativePathPattern:rpp
{: RESULT = new AncestorPattern(ikp, rpp); :}
| DSLASH RelativePathPattern:rpp
{: RESULT = new AncestorPattern(rpp); :}
| RelativePathPattern:rpp
{: RESULT = rpp; :};
IdKeyPattern ::= ID LPAREN Literal:l RPAREN
{: RESULT = new IdPattern(l);
parser.setHasIdCall(true);
:}
| KEY LPAREN Literal:l1 COMMA Literal:l2 RPAREN
{: RESULT = new KeyPattern(l1, l2); :};
ProcessingInstructionPattern ::= PIPARAM LPAREN Literal:l RPAREN
{: RESULT = new ProcessingInstructionPattern(l); :};
RelativePathPattern ::= StepPattern:sp
{: RESULT = sp; :}
| StepPattern:sp SLASH RelativePathPattern:rpp
{: RESULT = new ParentPattern(sp, rpp); :}
| StepPattern:sp DSLASH RelativePathPattern:rpp
{: RESULT = new AncestorPattern(sp, rpp); :};
StepPattern ::= NodeTestPattern:nt
{:
RESULT = parser.createStepPattern(Axis.CHILD, nt, null);
:}
| NodeTestPattern:nt Predicates:pp
{:
RESULT = parser.createStepPattern(Axis.CHILD, nt, pp);
:}
| ProcessingInstructionPattern:pip
{: RESULT = pip; :}
| ProcessingInstructionPattern:pip Predicates:pp
{: RESULT = (ProcessingInstructionPattern)pip.setPredicates(pp); :}
| ChildOrAttributeAxisSpecifier:axis NodeTestPattern:nt
{:
RESULT = parser.createStepPattern(axis.intValue(), nt, null);
:}
| ChildOrAttributeAxisSpecifier:axis
NodeTestPattern:nt Predicates:pp
{:
RESULT = parser.createStepPattern(axis.intValue(), nt, pp);
:}
| ChildOrAttributeAxisSpecifier:axis ProcessingInstructionPattern:pip
{:
RESULT = pip; // TODO: report error if axis is attribute
:}
| ChildOrAttributeAxisSpecifier:axis ProcessingInstructionPattern:pip
Predicates:pp
{:
// TODO: report error if axis is attribute
RESULT = (ProcessingInstructionPattern)pip.setPredicates(pp);
:};
NodeTestPattern ::= NameTestPattern:nt
{: RESULT = nt; :}
| NODE
{: RESULT = new Integer(NodeTest.ANODE); :}
| TEXT
{: RESULT = new Integer(NodeTest.TEXT); :}
| COMMENT
{: RESULT = new Integer(NodeTest.COMMENT); :}
| PI
{: RESULT = new Integer(NodeTest.PI); :};
NameTestPattern ::= STAR
{: RESULT = null; :}
| QName:qn
{: RESULT = qn; :};
ChildOrAttributeAxisSpecifier ::= ATSIGN
{: RESULT = new Integer(Axis.ATTRIBUTE); :}
| CHILD DCOLON
{: RESULT = new Integer(Axis.CHILD); :}
| ATTRIBUTE DCOLON
{: RESULT = new Integer(Axis.ATTRIBUTE); :};
Predicates ::= Predicate:p
{:
Vector temp = new Vector();
temp.addElement(p);
RESULT = temp;
:}
| Predicate:p Predicates:pp
{: pp.insertElementAt(p, 0); RESULT = pp; :};
Predicate ::= LBRACK Expr:e RBRACK
{:
RESULT = new Predicate(e);
:};
/* --------------------------- Expressions --------------------------------- */
Expr ::= OrExpr:ex
{: RESULT = ex; :};
OrExpr ::= AndExpr:ae
{: RESULT = ae; :}
| OrExpr:oe OR AndExpr:ae
{: RESULT = new LogicalExpr(LogicalExpr.OR, oe, ae); :};
AndExpr ::= EqualityExpr:e
{: RESULT = e; :}
| AndExpr:ae AND EqualityExpr:ee
{: RESULT = new LogicalExpr(LogicalExpr.AND, ae, ee); :};
EqualityExpr ::= RelationalExpr:re
{: RESULT = re; :}
| EqualityExpr:ee EQ RelationalExpr:re
{: RESULT = new EqualityExpr(Operators.EQ, ee, re); :}
| EqualityExpr:ee NE RelationalExpr:re
{: RESULT = new EqualityExpr(Operators.NE, ee, re); :};
RelationalExpr ::= AdditiveExpr:ae
{: RESULT = ae; :}
| RelationalExpr:re LT AdditiveExpr:ae
{: RESULT = new RelationalExpr(Operators.LT, re, ae); :}
| RelationalExpr:re GT AdditiveExpr:ae
{: RESULT = new RelationalExpr(Operators.GT, re, ae); :}
| RelationalExpr:re LE AdditiveExpr:ae
{: RESULT = new RelationalExpr(Operators.LE, re, ae); :}
| RelationalExpr:re GE AdditiveExpr:ae
{: RESULT = new RelationalExpr(Operators.GE, re, ae); :};
AdditiveExpr ::= MultiplicativeExpr:me
{: RESULT = me; :}
| AdditiveExpr:ae PLUS MultiplicativeExpr:me
{: RESULT = new BinOpExpr(BinOpExpr.PLUS, ae, me); :}
| AdditiveExpr:ae MINUS MultiplicativeExpr:me
{: RESULT = new BinOpExpr(BinOpExpr.MINUS, ae, me); :};
MultiplicativeExpr ::= UnaryExpr:ue
{: RESULT = ue; :}
| MultiplicativeExpr:me MULT UnaryExpr:ue
{: RESULT = new BinOpExpr(BinOpExpr.TIMES, me, ue); :}
| MultiplicativeExpr:me DIV UnaryExpr:ue
{: RESULT = new BinOpExpr(BinOpExpr.DIV, me, ue); :}
| MultiplicativeExpr:me MOD UnaryExpr:ue
{: RESULT = new BinOpExpr(BinOpExpr.MOD, me, ue); :};
UnaryExpr ::= UnionExpr:ue
{: RESULT = ue; :}
| MINUS UnaryExpr:ue
{: RESULT = new UnaryOpExpr(ue); :};
UnionExpr ::= PathExpr:pe
{: RESULT = pe; :}
| PathExpr:pe VBAR UnionExpr:rest
{: RESULT = new UnionPathExpr(pe, rest); :};
PathExpr ::= LocationPath:lp
{: RESULT = lp; :}
| FilterExpr:fexp
{: RESULT = fexp; :}
| FilterExpr:fexp SLASH RelativeLocationPath:rlp
{: RESULT = new FilterParentPath(fexp, rlp); :}
| FilterExpr:fexp DSLASH RelativeLocationPath:rlp
{:
//
// Expand '//' into '/descendant-or-self::node()/' or
// into /descendant-or-self::*/
//
int nodeType = DOM.NO_TYPE;
if (rlp instanceof Step &&
parser.isElementAxis(((Step) rlp).getAxis()))
{
nodeType = DTM.ELEMENT_NODE;
}
final Step step = new Step(Axis.DESCENDANTORSELF, nodeType, null);
FilterParentPath fpp = new FilterParentPath(fexp, step);
fpp = new FilterParentPath(fpp, rlp);
if (fexp instanceof KeyCall == false) {
fpp.setDescendantAxis();
}
RESULT = fpp;
:};
LocationPath ::= RelativeLocationPath:rlp
{: RESULT = rlp; :}
| AbsoluteLocationPath:alp
{: RESULT = alp; :};
RelativeLocationPath ::= Step:step
{: RESULT = step; :}
| RelativeLocationPath:rlp SLASH Step:step
{:
if (rlp instanceof Step && ((Step) rlp).isAbbreviatedDot()) {
RESULT = step; // Remove './' from the middle
}
else if (((Step) step).isAbbreviatedDot()) {
RESULT = rlp; // Remove '/.' from the end
}
else {
RESULT =
new ParentLocationPath((RelativeLocationPath) rlp, step);
}
:}
| AbbreviatedRelativeLocationPath:arlp
{: RESULT = arlp; :};
AbsoluteLocationPath ::= SLASH
{: RESULT = new AbsoluteLocationPath(); :}
| SLASH RelativeLocationPath:rlp
{: RESULT = new AbsoluteLocationPath(rlp); :}
| AbbreviatedAbsoluteLocationPath:aalp
{: RESULT = aalp; :};
AbbreviatedRelativeLocationPath ::= RelativeLocationPath:rlp DSLASH Step:step
{:
final Step right = (Step)step;
final int axis = right.getAxis();
final int type = right.getNodeType();
final Vector predicates = right.getPredicates();
if ((axis == Axis.CHILD) && (type != NodeTest.ATTRIBUTE)) {
// Compress './/child:E' into 'descendant::E' - if possible
if (predicates == null) {
right.setAxis(Axis.DESCENDANT);
if (rlp instanceof Step && ((Step)rlp).isAbbreviatedDot()) {
RESULT = right;
}
else {
// Expand 'rlp//child::E' into 'rlp/descendant::E'
RelativeLocationPath left = (RelativeLocationPath)rlp;
RESULT = new ParentLocationPath(left, right);
}
}
else {
// Expand './/step' -> 'descendant-or-self::*/step'
if (rlp instanceof Step && ((Step)rlp).isAbbreviatedDot()) {
Step left = new Step(Axis.DESCENDANTORSELF,
DTM.ELEMENT_NODE, null);
RESULT = new ParentLocationPath(left, right);
}
else {
// Expand 'rlp//step' -> 'rlp/descendant-or-self::*/step'
RelativeLocationPath left = (RelativeLocationPath)rlp;
Step mid = new Step(Axis.DESCENDANTORSELF,
DTM.ELEMENT_NODE, null);
ParentLocationPath ppl = new ParentLocationPath(mid, right);
RESULT = new ParentLocationPath(left, ppl);
}
}
}
else if ((axis == Axis.ATTRIBUTE) || (type == NodeTest.ATTRIBUTE)) {
// Expand 'rlp//step' -> 'rlp/descendant-or-self::*/step'
RelativeLocationPath left = (RelativeLocationPath)rlp;
Step middle = new Step(Axis.DESCENDANTORSELF,
DTM.ELEMENT_NODE, null);
ParentLocationPath ppl = new ParentLocationPath(middle, right);
RESULT = new ParentLocationPath(left, ppl);
}
else {
// Expand 'rlp//step' -> 'rlp/descendant-or-self::node()/step'
RelativeLocationPath left = (RelativeLocationPath)rlp;
Step middle = new Step(Axis.DESCENDANTORSELF,
DOM.NO_TYPE, null);
ParentLocationPath ppl = new ParentLocationPath(middle, right);
RESULT = new ParentLocationPath(left, ppl);
}
:};
AbbreviatedAbsoluteLocationPath ::= DSLASH RelativeLocationPath:rlp
{:
//
// Expand '//' into '/descendant-or-self::node()/' or
// into /descendant-or-self::*/
//
int nodeType = DOM.NO_TYPE;
if (rlp instanceof Step &&
parser.isElementAxis(((Step) rlp).getAxis()))
{
nodeType = DTM.ELEMENT_NODE;
}
final Step step = new Step(Axis.DESCENDANTORSELF, nodeType, null);
RESULT = new AbsoluteLocationPath(parser.insertStep(step,
(RelativeLocationPath) rlp));
:};
Step ::= NodeTest:ntest
{:
if (ntest instanceof Step) {
RESULT = (Step)ntest;
}
else {
RESULT = new Step(Axis.CHILD,
parser.findNodeType(Axis.CHILD, ntest),
null);
}
:}
| NodeTest:ntest Predicates:pp
{:
if (ntest instanceof Step) {
Step step = (Step)ntest;
step.addPredicates(pp);
RESULT = (Step)ntest;
}
else {
RESULT = new Step(Axis.CHILD,
parser.findNodeType(Axis.CHILD, ntest), pp);
}
:}
| AxisSpecifier:axis NodeTest:ntest Predicates:pp
{: RESULT = new Step(axis.intValue(),
parser.findNodeType(axis.intValue(), ntest),
pp);
:}
| AxisSpecifier:axis NodeTest:ntest
{: RESULT = new Step(axis.intValue(),
parser.findNodeType(axis.intValue(), ntest),
null);
:}
| AbbreviatedStep:abbrev
{: RESULT = abbrev; :};
AxisSpecifier ::= AxisName:an DCOLON
{: RESULT = an; :}
| ATSIGN
{: RESULT = new Integer(Axis.ATTRIBUTE); :};
AxisName ::= ANCESTOR
{: RESULT = new Integer(Axis.ANCESTOR); :}
| ANCESTORORSELF
{: RESULT = new Integer(Axis.ANCESTORORSELF); :}
| ATTRIBUTE
{: RESULT = new Integer(Axis.ATTRIBUTE); :}
| CHILD
{: RESULT = new Integer(Axis.CHILD); :}
| DESCENDANT
{: RESULT = new Integer(Axis.DESCENDANT); :}
| DESCENDANTORSELF
{: RESULT = new Integer(Axis.DESCENDANTORSELF); :}
| FOLLOWING
{: RESULT = new Integer(Axis.FOLLOWING); :}
| FOLLOWINGSIBLING
{: RESULT = new Integer(Axis.FOLLOWINGSIBLING); :}
| NAMESPACE
{: RESULT = new Integer(Axis.NAMESPACE); :}
| PARENT
{: RESULT = new Integer(Axis.PARENT); :}
| PRECEDING
{: RESULT = new Integer(Axis.PRECEDING); :}
| PRECEDINGSIBLING
{: RESULT = new Integer(Axis.PRECEDINGSIBLING); :}
| SELF
{: RESULT = new Integer(Axis.SELF); :};
AbbreviatedStep ::= DOT
{: RESULT = new Step(Axis.SELF, NodeTest.ANODE, null); :}
| DDOT
{: RESULT = new Step(Axis.PARENT, NodeTest.ANODE, null); :};
FilterExpr ::= PrimaryExpr:primary
{: RESULT = primary; :}
| PrimaryExpr:primary Predicates:pp
{: RESULT = new FilterExpr(primary, pp); :};
PrimaryExpr ::= VariableReference:vr
{: RESULT = vr; :}
| LPAREN Expr:ex RPAREN
{: RESULT = ex; :}
| Literal:string
{:
/*
* If the string appears to have the syntax of a QName, store
* namespace info in the literal expression. This is used for
* element-available and function-available functions, among
* others. Also, the default namespace must be ignored.
*/
String namespace = null;
final int index = string.lastIndexOf(':');
if (index > 0) {
final String prefix = string.substring(0, index);
namespace = parser._symbolTable.lookupNamespace(prefix);
}
RESULT = (namespace == null) ? new LiteralExpr(string)
: new LiteralExpr(string, namespace);
:}
| INT:num
{:
long value = num.longValue();
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
RESULT = new RealExpr(value);
}
else {
if (num.doubleValue() == -0)
RESULT = new RealExpr(num.doubleValue());
else if (num.intValue() == 0)
RESULT = new IntExpr(num.intValue());
else if (num.doubleValue() == 0.0)
RESULT = new RealExpr(num.doubleValue());
else
RESULT = new IntExpr(num.intValue());
}
:}
| REAL:num
{: RESULT = new RealExpr(num.doubleValue()); :}
| FunctionCall:fc
{: RESULT = fc; :};
VariableReference ::= DOLLAR VariableName:varName
{:
// An empty qname prefix for a variable or parameter reference
// should map to the null namespace and not the default URI.
SyntaxTreeNode node = parser.lookupName(varName);
if (node != null) {
if (node instanceof Variable) {
RESULT = new VariableRef((Variable)node);
}
else if (node instanceof Param) {
RESULT = new ParameterRef((Param)node);
}
else {
RESULT = new UnresolvedRef(varName);
}
}
if (node == null) {
RESULT = new UnresolvedRef(varName);
}
:};
FunctionCall ::= FunctionName:fname LPAREN RPAREN
{:
if (parser.getQNameIgnoreDefaultNs("current").equals(fname)) {
RESULT = new CurrentCall(fname);
}
else if (parser.getQNameIgnoreDefaultNs("number").equals(fname)) {
RESULT = new NumberCall(fname, parser.EmptyArgs);
}
else if (parser.getQNameIgnoreDefaultNs("string").equals(fname)) {
RESULT = new StringCall(fname, parser.EmptyArgs);
}
else if (parser.getQNameIgnoreDefaultNs("concat").equals(fname)) {
RESULT = new ConcatCall(fname, parser.EmptyArgs);
}
else if (parser.getQNameIgnoreDefaultNs("true").equals(fname)) {
RESULT = new BooleanExpr(true);
}
else if (parser.getQNameIgnoreDefaultNs("false").equals(fname)) {
RESULT = new BooleanExpr(false);
}
else if (parser.getQNameIgnoreDefaultNs("name").equals(fname)) {
RESULT = new NameCall(fname);
}
else if (parser.getQNameIgnoreDefaultNs("generate-id").equals(fname)) {
RESULT = new GenerateIdCall(fname, parser.EmptyArgs);
}
else if (parser.getQNameIgnoreDefaultNs("string-length").equals(fname)) {
RESULT = new StringLengthCall(fname, parser.EmptyArgs);
}
else if (parser.getQNameIgnoreDefaultNs("position").equals(fname)) {
RESULT = new PositionCall(fname);
}
else if (parser.getQNameIgnoreDefaultNs("last").equals(fname)) {
RESULT = new LastCall(fname);
}
else if (parser.getQNameIgnoreDefaultNs("local-name").equals(fname)) {
RESULT = new LocalNameCall(fname);
}
else if (parser.getQNameIgnoreDefaultNs("namespace-uri").equals(fname)) {
RESULT = new NamespaceUriCall(fname);
}
else {
RESULT = new FunctionCall(fname, parser.EmptyArgs);
}
:}
| FunctionName:fname LPAREN NonemptyArgumentList:argl RPAREN
{:
if (parser.getQNameIgnoreDefaultNs("concat").equals(fname)) {
RESULT = new ConcatCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("number").equals(fname)) {
RESULT = new NumberCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("document").equals(fname)) {
parser.setMultiDocument(true);
RESULT = new DocumentCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("string").equals(fname)) {
RESULT = new StringCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("boolean").equals(fname)) {
RESULT = new BooleanCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("name").equals(fname)) {
RESULT = new NameCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("generate-id").equals(fname)) {
RESULT = new GenerateIdCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("not").equals(fname)) {
RESULT = new NotCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("format-number").equals(fname)) {
RESULT = new FormatNumberCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("unparsed-entity-uri").equals(fname)) {
RESULT = new UnparsedEntityUriCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("key").equals(fname)) {
RESULT = new KeyCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("id").equals(fname)) {
RESULT = new KeyCall(fname, argl);
parser.setHasIdCall(true);
}
else if (parser.getQNameIgnoreDefaultNs("ceiling").equals(fname)) {
RESULT = new CeilingCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("round").equals(fname)) {
RESULT = new RoundCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("floor").equals(fname)) {
RESULT = new FloorCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("contains").equals(fname)) {
RESULT = new ContainsCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("string-length").equals(fname)) {
RESULT = new StringLengthCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("starts-with").equals(fname)) {
RESULT = new StartsWithCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("function-available").equals(fname)) {
RESULT = new FunctionAvailableCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("element-available").equals(fname)) {
RESULT = new ElementAvailableCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("local-name").equals(fname)) {
RESULT = new LocalNameCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("lang").equals(fname)) {
RESULT = new LangCall(fname, argl);
}
else if (parser.getQNameIgnoreDefaultNs("namespace-uri").equals(fname)) {
RESULT = new NamespaceUriCall(fname, argl);
}
else if (parser.getQName(Constants.TRANSLET_URI, "xsltc", "cast").equals(fname)) {
RESULT = new CastCall(fname, argl);
}
// Special case for extension function nodeset()
else if (fname.getLocalPart().equals("nodeset") || fname.getLocalPart().equals("node-set")) {
parser.setCallsNodeset(true); // implies MultiDOM
RESULT = new FunctionCall(fname, argl);
}
else {
RESULT = new FunctionCall(fname, argl);
}
:};
NonemptyArgumentList ::= Argument:arg
{:
Vector temp = new Vector();
temp.addElement(arg);
RESULT = temp;
:}
| Argument:arg COMMA NonemptyArgumentList:argl
{: argl.insertElementAt(arg, 0); RESULT = argl; :};
FunctionName ::= QName:fname
{:
RESULT = fname;
:};
VariableName ::= QName:vname
{:
RESULT = vname;
:};
Argument ::= Expr:ex
{: RESULT = ex; :};
NodeTest ::= NameTest:nt
{: RESULT = nt; :}
| NODE
{: RESULT = new Integer(NodeTest.ANODE); :}
| TEXT
{: RESULT = new Integer(NodeTest.TEXT); :}
| COMMENT
{: RESULT = new Integer(NodeTest.COMMENT); :}
| PIPARAM LPAREN Literal:l RPAREN
{:
QName name = parser.getQNameIgnoreDefaultNs("name");
Expression exp = new EqualityExpr(Operators.EQ,
new NameCall(name),
new LiteralExpr(l));
Vector predicates = new Vector();
predicates.addElement(new Predicate(exp));
RESULT = new Step(Axis.CHILD, NodeTest.PI, predicates);
:}
| PI
{: RESULT = new Integer(NodeTest.PI); :};
NameTest ::= STAR
{: RESULT = null; :}
| QName:qn
{: RESULT = qn; :};
QName ::= QNAME:qname
{: RESULT = parser.getQNameIgnoreDefaultNs(qname); :}
| DIV
{: RESULT = parser.getQNameIgnoreDefaultNs("div"); :}
| MOD
{: RESULT = parser.getQNameIgnoreDefaultNs("mod"); :}
| KEY
{: RESULT = parser.getQNameIgnoreDefaultNs("key"); :}
| ANCESTOR
{: RESULT = parser.getQNameIgnoreDefaultNs("child"); :}
| ANCESTORORSELF
{: RESULT = parser.getQNameIgnoreDefaultNs("ancestor-or-self"); :}
| ATTRIBUTE
{: RESULT = parser.getQNameIgnoreDefaultNs("attribute"); :}
| CHILD
{: RESULT = parser.getQNameIgnoreDefaultNs("child"); :}
| DESCENDANT
{: RESULT = parser.getQNameIgnoreDefaultNs("decendant"); :}
| DESCENDANTORSELF
{: RESULT = parser.getQNameIgnoreDefaultNs("decendant-or-self"); :}
| FOLLOWING
{: RESULT = parser.getQNameIgnoreDefaultNs("following"); :}
| FOLLOWINGSIBLING
{: RESULT = parser.getQNameIgnoreDefaultNs("following-sibling"); :}
| NAMESPACE
{: RESULT = parser.getQNameIgnoreDefaultNs("namespace"); :}
| PARENT
{: RESULT = parser.getQNameIgnoreDefaultNs("parent"); :}
| PRECEDING
{: RESULT = parser.getQNameIgnoreDefaultNs("preceding"); :}
| PRECEDINGSIBLING
{: RESULT = parser.getQNameIgnoreDefaultNs("preceding-sibling"); :}
| SELF
{: RESULT = parser.getQNameIgnoreDefaultNs("self"); :}
| ID
{: RESULT = parser.getQNameIgnoreDefaultNs("id"); :};