/* * Copyright 2001-2004 The Apache Software Foundation. * * Licensed 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.xalan.xsltc.dom.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 true 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; 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, STAR; 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 STAR 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 (fname == parser.getQNameIgnoreDefaultNs("current")) { RESULT = new CurrentCall(fname); } else if (fname == parser.getQNameIgnoreDefaultNs("number")) { RESULT = new NumberCall(fname, parser.EmptyArgs); } else if (fname == parser.getQNameIgnoreDefaultNs("string")) { RESULT = new StringCall(fname, parser.EmptyArgs); } else if (fname == parser.getQNameIgnoreDefaultNs("concat")) { RESULT = new ConcatCall(fname, parser.EmptyArgs); } else if (fname == parser.getQNameIgnoreDefaultNs("true")) { RESULT = new BooleanExpr(true); } else if (fname == parser.getQNameIgnoreDefaultNs("false")) { RESULT = new BooleanExpr(false); } else if (fname == parser.getQNameIgnoreDefaultNs("name")) { RESULT = new NameCall(fname); } else if (fname == parser.getQNameIgnoreDefaultNs("generate-id")) { RESULT = new GenerateIdCall(fname, parser.EmptyArgs); } else if (fname == parser.getQNameIgnoreDefaultNs("string-length")) { RESULT = new StringLengthCall(fname, parser.EmptyArgs); } else if (fname == parser.getQNameIgnoreDefaultNs("position")) { RESULT = new PositionCall(fname); } else if (fname == parser.getQNameIgnoreDefaultNs("last")) { RESULT = new LastCall(fname); } else if (fname == parser.getQNameIgnoreDefaultNs("local-name")) { RESULT = new LocalNameCall(fname); } else if (fname == parser.getQNameIgnoreDefaultNs("namespace-uri")) { RESULT = new NamespaceUriCall(fname); } else { RESULT = new FunctionCall(fname, parser.EmptyArgs); } :} | FunctionName:fname LPAREN NonemptyArgumentList:argl RPAREN {: if (fname == parser.getQNameIgnoreDefaultNs("concat")) { RESULT = new ConcatCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("number")) { RESULT = new NumberCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("document")) { parser.setMultiDocument(true); RESULT = new DocumentCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("string")) { RESULT = new StringCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("boolean")) { RESULT = new BooleanCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("name")) { RESULT = new NameCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("generate-id")) { RESULT = new GenerateIdCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("not")) { RESULT = new NotCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("format-number")) { RESULT = new FormatNumberCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("unparsed-entity-uri")) { RESULT = new UnparsedEntityUriCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("key")) { RESULT = new KeyCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("id")) { RESULT = new KeyCall(fname, argl); parser.setHasIdCall(true); } else if (fname == parser.getQNameIgnoreDefaultNs("ceiling")) { RESULT = new CeilingCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("round")) { RESULT = new RoundCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("floor")) { RESULT = new FloorCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("contains")) { RESULT = new ContainsCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("string-length")) { RESULT = new StringLengthCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("starts-with")) { RESULT = new StartsWithCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("function-available")) { RESULT = new FunctionAvailableCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("element-available")) { RESULT = new ElementAvailableCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("local-name")) { RESULT = new LocalNameCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("lang")) { RESULT = new LangCall(fname, argl); } else if (fname == parser.getQNameIgnoreDefaultNs("namespace-uri")) { RESULT = new NamespaceUriCall(fname, argl); } else if (fname == parser.getQName(Constants.TRANSLET_URI, "xsltc", "cast")) { 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"); :};