Package org.apache.xalan.xsltc.compiler

Source Code of org.apache.xalan.xsltc.compiler.Parser

/*
* @(#)$Id: Parser.java,v 1.4 2001/05/02 10:25:00 morten Exp $
*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2001 The Apache Software Foundation.  All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
*    not be used to endorse or promote products derived from this
*    software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
*    nor may "Apache" appear in their name, without prior written
*    permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 2001, Sun
* Microsystems., http://www.sun.com.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* @author Jacek Ambroziak
* @author Santiago Pericas-Geertsen
* @author G. Todd Miller
* @author Morten Jorgensen
*
*/

package org.apache.xalan.xsltc.compiler;

import java.io.*;
import java.net.URL;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.net.MalformedURLException;

import javax.xml.parsers.*;

import org.w3c.dom.*;
import org.xml.sax.*;

import java_cup.runtime.Symbol;

import org.apache.xalan.xsltc.compiler.util.*;

public final class Parser implements Constants {

    private static final String XSL = "xsl";            // standard prefix
    private static final String TRANSLET = "translet"; // extension prefix
   
    private XSLTC _xsltc;             // Reference to the compiler object.
    private XPathParser _xpathParser; // Reference to the XPath parser.
    private Vector _errors;           // Contains all compilation errors
    private Vector _warnings;        // Contains all compilation errors

    private Hashtable   _instructionClasses; // Maps instructions to classes
    private Hashtable   _qNames;
    private Hashtable   _namespaces;
    private QName       _useAttributeSets;
    private QName       _excludeResultPrefixes;
    private QName       _extensionElementPrefixes;
    private Hashtable   _variableScope;
    private Stylesheet  _currentStylesheet;
    private SymbolTable _symbolTable; // Maps QNames to syntax-tree nodes
    private Output      _output = null;
    private Template    _template;    // Reference to the template being parsed.

    private int _currentImportPrecedence = 1;

    public Parser(XSLTC xsltc) {
  _xsltc = xsltc;
    }

    public void setOutput(Output output) {
  if (_output == null)
      _output = output;
  else
      output.disable();
    }

    public void init() {
  _qNames              = new Hashtable(512);
  _namespaces          = new Hashtable();
  _instructionClasses  = new Hashtable();
  _variableScope       = new Hashtable();
  _template            = null;
  _errors              = new Vector();
  _warnings            = new Vector();
  _symbolTable         = new SymbolTable();
  _xpathParser         = new XPathParser(this);
  _currentStylesheet   = null;
  _currentImportPrecedence = 1;
 
  initStdClasses();
  initExtClasses();
  initSymbolTable();
 
  _useAttributeSets = getQName(XSLT_URI, XSL, "use-attribute-sets");
  _excludeResultPrefixes
      = getQName(XSLT_URI, XSL, "exclude-result-prefixes");
  _extensionElementPrefixes
      = getQName(XSLT_URI, XSL, "extension-element-prefixes");
    }
   
    public void addVariable(Variable var) {
  _variableScope.put(var.getName(), var);
    }

    public void addParameter(Param param) {
  _variableScope.put(param.getName(), param);
    }

    public void removeVariable(QName name) {
  _variableScope.remove(name);
    }

    public SyntaxTreeNode lookupVariable(QName name) {
  return (SyntaxTreeNode)_variableScope.get(name);
    }

    public XSLTC getXSLTC() {
  return _xsltc;
    }

    public int getCurrentImportPrecedence() {
  return _currentImportPrecedence;
    }
   
    public int getNextImportPrecedence() {
  return ++_currentImportPrecedence;
    }

    public void setCurrentStylesheet(Stylesheet stylesheet) {
  _currentStylesheet = stylesheet;
    }

    public Stylesheet getCurrentStylesheet() {
  return _currentStylesheet;
    }
   
    public Stylesheet getTopLevelStylesheet() {
  return _xsltc.getStylesheet();
    }

    public QName getQNameSafe(final String stringRep) {
  // parse and retrieve namespace
  final int colon = stringRep.lastIndexOf(':');
  if (colon != -1) {
      final String prefix = stringRep.substring(0, colon);
      final String localname = stringRep.substring(colon + 1);
      String namespace = null;
     
      // Get the namespace uri from the symbol table
      if (prefix.equals("xmlns") == false) {
    namespace = _symbolTable.lookupNamespace(prefix);
    if (namespace == null) namespace = "";
      }
      return getQName(namespace, prefix, localname);
  }
  else {
      return getQName(_symbolTable.lookupNamespace(""), null, stringRep);
  }
    }
   
    public QName getQName(final String stringRep) {
  // parse and retrieve namespace
  final int colon = stringRep.lastIndexOf(':');
  if (colon != -1) {
      final String prefix = stringRep.substring(0, colon);
      final String localname = stringRep.substring(colon + 1);
      String namespace = null;
     
      // Get the namespace uri from the symbol table
      if (prefix.equals("xmlns") == false) {
    namespace = _symbolTable.lookupNamespace(prefix);
    if (namespace == null) {
        addError(new ErrorMsg(ErrorMsg.NSPUNDEF_ERR, prefix));
    }
      }
      return getQName(namespace, prefix, localname);
  }
  else {
      return getQName(_symbolTable.lookupNamespace(""), null, stringRep);
  }
    }

    public QName getQName(String namespace, String prefix, String localname) {
  if (namespace == null) {
      QName name = (QName)_qNames.get(localname);
      if (name == null) {
    _qNames.put(localname,
          name = new QName(null, prefix, localname));
      }
      return name;
  }
  else {
      Dictionary space = (Dictionary)_namespaces.get(namespace);
      if (space == null) {
    final QName name = new QName(namespace, prefix, localname);
    _namespaces.put(namespace, space = new Hashtable());
    space.put(localname, name);
    return name;
      }
      else {
    QName name = (QName)space.get(localname);
    if (name == null) {
        space.put(localname,
            name = new QName(namespace, prefix, localname));
    }
    return name;
      }
  }
    }
   
    public QName getQName(String scope, String name) {
  return getQName(scope + name);
    }

    public QName getQName(QName scope, QName name) {
  return getQName(scope.toString() + name.toString());
    }

    public QName getUseAttributeSets() {
  return _useAttributeSets;
    }

    public QName getExtensionElementPrefixes() {
  return _extensionElementPrefixes;
    }

    public QName getExcludeResultPrefixes() {
  return _excludeResultPrefixes;
    }
   
    /** 
     * Create an instance of the <code>Stylesheet</code> class,
     * and then parse, typecheck and compile the instance.
     * Must be called after <code>parse()</code>.
     */
    public Stylesheet makeStylesheet(Element element)
  throws CompilerException {
  try {
      Stylesheet stylesheet;

      // Push any namespaces declared in the root element
      pushNamespaces(element);

      // Get the name of this element and try to map it to a class
      final QName qName = getQName(element.getTagName());
      final String namespace = element.getNamespaceURI();
      final String classname = (String)_instructionClasses.get(qName);

      // Make a Stylesheet object from the root node if it is an
      // xsl:stylesheet element
      if (classname != null) {
    stylesheet = (Stylesheet)makeInstance(element);
      }
      // Otherwise we create an empty Stylesheet object, and tag it
      // as a simplified stylesheet (a simplified stylesheet will have
      // to insert a <xsl:template match="/"/> as its only child).
      else {
    stylesheet = new Stylesheet();
    stylesheet.setSimplified();
      }

      stylesheet.setParser(this);
      popNamespaces(element);
      return stylesheet;
  }
  catch (ClassCastException e) {
      throw new CompilerException("The input document does not "+
          "contain an XSL stylesheet.");
  }
    }
   
    /**
     * Update the symbol table with the namespace declarations defined in
     * <tt>element</tt>.
     */
    public void pushNamespaces(Element element) {
  pushPopNamespaces(element, true);
    }

    /**
     * Update the symbol table with the namespace declarations defined in
     * <tt>element</tt>.
     */
    public void popNamespaces(Element element) {
  pushPopNamespaces(element, false);
    }

    /**
     * Update the symbol table with the namespace declarations defined in
     * <tt>element</tt>. The declarations are added or removed form the
     * symbol table depending on the value of <tt>push</tt>.
     */
    private void pushPopNamespaces(Element element, boolean push) {
  final NamedNodeMap map = element.getAttributes();
  final int n = map.getLength();
  for (int i = 0; i < n; i++) {
      final Node node = map.item(i);
      final String name = node.getNodeName();
      String prefix;

      if (name.equals("xmlns")) {
    prefix = "";    // default namespace
      }
      else {
    final int index = name.indexOf(':');
    if (index >= 0 && name.substring(0, index).equals("xmlns")) {
        prefix = name.substring(index + 1);
    }
    else {
        continue;
    }
      }

      if (push)
    _symbolTable.pushNamespace(prefix, node.getNodeValue());
      else
    _symbolTable.popNamespace(prefix);
  }
    }

    public void createAST(Element element, Stylesheet stylesheet) {
  try {
      if (stylesheet != null) {
    stylesheet.parseContents(element, this);
    final int precedence = stylesheet.getImportPrecedence();
    final Enumeration elements = stylesheet.elements();
    while (elements.hasMoreElements()) {
        Object child = elements.nextElement();
        // GTM: fixed bug # 4415344
        if (child instanceof Text){
      throw new TypeCheckError(new ErrorMsg(
          "character data '" + ((Text)child).getText() +
          "' found outside top level stylesheet element."));
        }
    }
    if (!errorsFound()) {
        stylesheet.typeCheck(_symbolTable);
    }
      }
  }
  catch (TypeCheckError e) {
      //e.printStackTrace();
      addError(new ErrorMsg(e.toString())); // TODO
  }
    }

    public Element parse(URL url) {
  return(parse(url.toString()));
    }

    public Element parse(String stylesheetURL) {
  try {
      // Get an instance of the document builder factory
      final DocumentBuilderFactory factory =
    DocumentBuilderFactory.newInstance();
      factory.setNamespaceAware(true);

      // Then make an instance of the actual document builder
      final DocumentBuilder builder = factory.newDocumentBuilder();
      if (!builder.isNamespaceAware()) { // Must be namespace aware
    addError(new ErrorMsg("SAX parser is not namespace aware"));
      }

      // Parse the stylesheet document and return the root element
      Document document = builder.parse(stylesheetURL);
      return document.getDocumentElement();
  }
  catch (ParserConfigurationException e) {
      addError(new ErrorMsg("JAXP parser not configured correctly"));
  }
  catch (IOException e) {
      addError(new ErrorMsg(ErrorMsg.FILECANT_ERR, stylesheetURL));
  }
  catch (SAXParseException e){
      addError(new ErrorMsg(e.getMessage(),e.getLineNumber()));
  }
  catch (SAXException e) {
      addError(new ErrorMsg(e.getMessage()));
  }
  return null;
    }

    /**
     * Extracts the DOM for the stylesheet. In the case of an embedded
     * stylesheet, it extracts the DOM subtree corresponding to the
     * embedded stylesheet that has an 'id' attribute whose value is the
     * same as the value declared in the <?xml-stylesheet...?> processing
     * instruction (P.I.). In the xml-stylesheet P.I. the value is labeled
     * as the 'href' data of the P.I. The extracted DOM representing the
     * stylesheet is returned as an Element object.
     */
    private Element getStylesheet(Document doc) throws CompilerException {

  // Get the xml-stylesheet processing instruction (P.I.)
  org.w3c.dom.ProcessingInstruction stylesheetPI = getStylesheetPI(doc);
  // If there is none we assume this is a pure XSL file and return root.
  if (stylesheetPI == null ) return (Element)doc.getDocumentElement();

  // Get href value from P.I. to identify the correct stylesheet
  String href = getXmlStylesheetPIHrefValue(stylesheetPI);
  if (href == null) {
      throw new CompilerException(
    "Processing instruction <?xml-stylesheet ... ?> is " +
    "missing the href data.");
  }

  // Create list of all xsl:stylesheet (or alt. xsl:transform) elements
  NodeList elements = doc.getElementsByTagName("xsl:stylesheet");
  if (elements.getLength() == 0)
      elements = doc.getElementsByTagName("xsl:transform");

  // Scan all elements to find the one that matches the href in the PI
  for(int i=0; i<elements.getLength(); i++) {
      Node curr = elements.item(i);
      NamedNodeMap map = curr.getAttributes();
      if (map.getLength() != 0) {
    Node attr = map.getNamedItem("id");
    String attrValue = attr.getNodeValue();
    if ((href == null) || (href.equals(attrValue))) {
        return (Element)curr;
    }
      }
  }

  // If there is none we assume this is a pure XSL file and return root.
  // GTM Note: removed this line because it was causing failures
  //   in test suite, the presence of a xml-stylesheet P.I. AND
  //   the absence of an href should be an error. See 'href == null'
  //   above.... we will remove this comment and associated line
  //   after test suite confirms it has not damaged anything else.
  // if (href == null) return (Element)doc.getDocumentElement();

  // If we did not find the references stylesheet in the current XML
  // file we assume it is an external file and load that...
  return(loadExternalStylesheet(doc, href));
    }

    /**
     * For embedded stylesheets: Load an external file with stylesheet
     */
    private Element loadExternalStylesheet(Document doc, String url)
  throws CompilerException {
  try {
      // Check if the URL is a local file
      if ((new File(url)).exists()) url = "file:"+url;

      // Get an instance of the document builder factory
      final DocumentBuilderFactory factory =
    DocumentBuilderFactory.newInstance();
      factory.setNamespaceAware(true);

      // Then make an instance of the actual document builder
      final DocumentBuilder builder = factory.newDocumentBuilder();
      if (!builder.isNamespaceAware()) { // Must be namespace aware
    addError(new ErrorMsg("SAX parser is not namespace aware"));
      }

      // Parse the stylesheet document and return the root element
      Document document = builder.parse(url);
      return document.getDocumentElement();
  }
  catch (ParserConfigurationException e) {
      throw new CompilerException("JAXP parser not configured "+
          "correctly");
  }
  catch (IOException e) {
      throw new CompilerException("Could not find stylesheet - '"+url+
          "' is not a named element in the "+
          "current file nor a local file.");
  }
  catch (SAXException e) {
      throw new CompilerException("Could not parse stylesheet with id='"+
          url+"' (referenced in stylesheet PI)");
  }
    }

    /**
     * Returns the first xml-stylesheet processing instruction found in the DOM.
     */
    private org.w3c.dom.ProcessingInstruction getStylesheetPI(Document doc) {

        Node node = doc;

  while (node != null) {
      switch (node.getNodeType ()) {
      case Node.PROCESSING_INSTRUCTION_NODE:
    org.w3c.dom.ProcessingInstruction pi =
        (org.w3c.dom.ProcessingInstruction)node;
    if (pi.getTarget().equals("xml-stylesheet")) return pi;
    // FALLTHROUGH
      case Node.DOCUMENT_FRAGMENT_NODE:
      case Node.DOCUMENT_NODE:
      case Node.ELEMENT_NODE:
    // First try to traverse any children of the node
    Node child = node.getFirstChild();
    if (child != null) {
        node = child;
        break;
    }
    // FALLTHROUGH
      default:
    // Then try the siblings
    Node next = node.getNextSibling();
    if (next == null) {
        // Then step up to the parent node
        Node parent = node.getParentNode();
        if ((parent == null) || (node == doc)) return null;
        node = parent;
    }
    else {
        node = next;
    }
      }
  }
  return null;
    }

    /**
     * Extracts the value of the 'href' in an xml-stylesheet processing
     * instruction. The value of the P.I. href is prefixed with the '#'
     * character, this method removes the prefix before returning it to
     * caller. Returns: String (without '#' prefix) or null if none found.
     */
    private String getXmlStylesheetPIHrefValue(
        org.w3c.dom.ProcessingInstruction pi)
    {
  String data = pi.getData();
  int start = -1;
  if ((start = data.indexOf("href")) < 0) {
      return null;
  }
  String hrefportion = data.substring(start);
  StringTokenizer tok = new StringTokenizer(hrefportion, "\"");
  tok.nextToken();    // throw away 'href='
  String retval = tok.nextToken();
  return (retval.startsWith("#")) ? retval.substring(1):retval;
    }
   

    private void initStdClasses() {
  initStdClass("template", "Template");
  initStdClass("stylesheet", "Stylesheet");
  initStdClass("transform", "Stylesheet");
  initStdClass("text", "Text");
  initStdClass("if", "If");
  initStdClass("choose", "Choose");
  initStdClass("when", "When");
  initStdClass("otherwise", "Otherwise");
  initStdClass("for-each", "ForEach");
  initStdClass("message", "Message");
  initStdClass("number", "Number");
  initStdClass("comment", "Comment");
  initStdClass("copy", "Copy");
  initStdClass("copy-of", "CopyOf");
  initStdClass("param", "Param");
  initStdClass("with-param", "WithParam");
  initStdClass("variable", "Variable");
  initStdClass("output", "Output");
  initStdClass("sort", "Sort");
  initStdClass("key", "Key");
  initStdClass("fallback", "Fallback");
  initStdClass("attribute", "XslAttribute");
  initStdClass("attribute-set", "AttributeSet");
  initStdClass("value-of", "ValueOf");
  initStdClass("element", "XslElement");
  initStdClass("call-template", "CallTemplate");
  initStdClass("apply-templates", "ApplyTemplates");
  initStdClass("apply-imports", "ApplyImports");
  initStdClass("decimal-format", "DecimalFormatting");
  initStdClass("import", "Import");
  initStdClass("include", "Include");
  initStdClass("strip-space", "Whitespace");
  initStdClass("preserve-space", "Whitespace");
  initStdClass("processing-instruction", "ProcessingInstruction");
  initStdClass("namespace-alias", "NamespaceAlias");
    }
   
    private void initStdClass(String elementName, String className) {
  _instructionClasses.put(getQName(XSLT_URI, XSL, elementName),
        COMPILER_PACKAGE + '.' + className);
    }

    private void initExtClasses() {
  initExtClass("output", "TransletOutput");
    }

    private void initExtClass(String elementName, String className) {
  _instructionClasses.put(getQName(TRANSLET_URI, TRANSLET, elementName),
        COMPILER_PACKAGE + '.' + className);
    }

    /**
     * Add primops and base functions to the symbol table.
     */
    private void initSymbolTable() {
  MethodType I_V  = new MethodType(Type.Int, Type.Void);
  MethodType I_R  = new MethodType(Type.Int, Type.Real);
  MethodType I_S  = new MethodType(Type.Int, Type.String);
  MethodType I_D  = new MethodType(Type.Int, Type.NodeSet);
  MethodType R_I  = new MethodType(Type.Real, Type.Int);
  MethodType R_V  = new MethodType(Type.Real, Type.Void);
  MethodType R_R  = new MethodType(Type.Real, Type.Real);
  MethodType R_D  = new MethodType(Type.Real, Type.NodeSet);
  MethodType R_O  = new MethodType(Type.Real, Type.Reference);
  MethodType I_I  = new MethodType(Type.Int, Type.Int);
  MethodType D_O  = new MethodType(Type.NodeSet, Type.Reference);
  MethodType D_SS = new MethodType(Type.NodeSet,
           Type.String, Type.String);
  MethodType D_SD = new MethodType(Type.NodeSet,
           Type.String, Type.NodeSet);
  MethodType D_S  = new MethodType(Type.NodeSet, Type.String);
  MethodType D_D  = new MethodType(Type.NodeSet, Type.NodeSet);
  MethodType A_V  = new MethodType(Type.Node, Type.Void);
  MethodType S_V  = new MethodType(Type.String, Type.Void);
  MethodType S_S  = new MethodType(Type.String, Type.String);
  MethodType S_A  = new MethodType(Type.String, Type.Node);
  MethodType S_D  = new MethodType(Type.String, Type.NodeSet);
  MethodType S_O  = new MethodType(Type.String, Type.Reference);
  MethodType B_O  = new MethodType(Type.Boolean, Type.Reference);
  MethodType B_V  = new MethodType(Type.Boolean, Type.Void);
  MethodType B_B  = new MethodType(Type.Boolean, Type.Boolean);
  MethodType B_S  = new MethodType(Type.Boolean, Type.String);
  MethodType R_RR = new MethodType(Type.Real, Type.Real, Type.Real);
  MethodType I_II = new MethodType(Type.Int, Type.Int, Type.Int);
  MethodType B_RR = new MethodType(Type.Boolean, Type.Real, Type.Real);
  MethodType B_II = new MethodType(Type.Boolean, Type.Int, Type.Int);
  MethodType B_BB = new MethodType(Type.Boolean, Type.Boolean,
           Type.Boolean);
  MethodType B_SS = new MethodType(Type.Boolean, Type.String,
           Type.String);
  MethodType S_SS = new MethodType(Type.String, Type.String,
           Type.String);
  MethodType S_SD = new MethodType(Type.String, Type.String,
           Type.NodeSet);
  MethodType S_DS  = new MethodType(Type.String, Type.Real, Type.String);
  MethodType S_DSS = new MethodType(Type.String, Type.Real, Type.String,
            Type.String);
  MethodType S_SR  = new MethodType(Type.String, Type.String, Type.Real);
  MethodType S_SRR = new MethodType(Type.String, Type.String, Type.Real,
            Type.Real);
  MethodType S_SSS = new MethodType(Type.String, Type.String,
            Type.String, Type.String);

  /*
   * Standard functions: implemented but not in this table concat().
   * When adding a new function make sure to uncomment
   * the corresponding line in <tt>FunctionAvailableCall</tt>.
   */

  // The following functions are inlined
  _symbolTable.addPrimop(getQName("current"), A_V);
  _symbolTable.addPrimop(getQName("last"), I_V);
  _symbolTable.addPrimop(getQName("position"), I_V);
  _symbolTable.addPrimop(getQName("true"), B_V);
  _symbolTable.addPrimop(getQName("false"), B_V);
  _symbolTable.addPrimop(getQName("not"), B_B);
  _symbolTable.addPrimop(getQName("name"), S_V);
  _symbolTable.addPrimop(getQName("name"), S_A);
  _symbolTable.addPrimop(getQName("generate-id"), S_V);
  _symbolTable.addPrimop(getQName("generate-id"), S_A);
  _symbolTable.addPrimop(getQName("ceiling"), R_R);
  _symbolTable.addPrimop(getQName("floor"), R_R);
  _symbolTable.addPrimop(getQName("round"), I_R);
  _symbolTable.addPrimop(getQName("contains"), B_SS);
  _symbolTable.addPrimop(getQName("number"), R_O);
  _symbolTable.addPrimop(getQName("number"), R_V);
  _symbolTable.addPrimop(getQName("boolean"), B_O);
  _symbolTable.addPrimop(getQName("string"), S_O);
  _symbolTable.addPrimop(getQName("string"), S_V);
  _symbolTable.addPrimop(getQName("translate"), S_SSS);
  _symbolTable.addPrimop(getQName("string-length"), I_V);
  _symbolTable.addPrimop(getQName("string-length"), I_S);
  _symbolTable.addPrimop(getQName("starts-with"), B_SS);
  _symbolTable.addPrimop(getQName("format-number"), S_DS);
  _symbolTable.addPrimop(getQName("format-number"), S_DSS);
  _symbolTable.addPrimop(getQName("unparsed-entity-uri"), S_S);
  _symbolTable.addPrimop(getQName("key"), D_SS);
  _symbolTable.addPrimop(getQName("key"), D_SD);
  _symbolTable.addPrimop(getQName("id"), D_S);
  _symbolTable.addPrimop(getQName("id"), D_D);
  _symbolTable.addPrimop(getQName("namespace-uri"), S_V);

  // The following functions are implemented in the basis library
  _symbolTable.addPrimop(getQName("count"), I_D);
  _symbolTable.addPrimop(getQName("sum"), R_D);
  _symbolTable.addPrimop(getQName("local-name"), S_V);
  _symbolTable.addPrimop(getQName("local-name"), S_D);
  _symbolTable.addPrimop(getQName("namespace-uri"), S_V);
  _symbolTable.addPrimop(getQName("namespace-uri"), S_D);
  _symbolTable.addPrimop(getQName("substring"), S_SR);
  _symbolTable.addPrimop(getQName("substring"), S_SRR);
  _symbolTable.addPrimop(getQName("substring-after"), S_SS);
  _symbolTable.addPrimop(getQName("substring-before"), S_SS);
  _symbolTable.addPrimop(getQName("normalize-space"), S_V);
  _symbolTable.addPrimop(getQName("normalize-space"), S_S);
  _symbolTable.addPrimop(getQName("function-available"), B_S);
  _symbolTable.addPrimop(getQName("system-property"), S_S);

  // Operators +, -, *, /, % defined on real types.
  _symbolTable.addPrimop(getQName("+"), R_RR)
  _symbolTable.addPrimop(getQName("-"), R_RR)
  _symbolTable.addPrimop(getQName("*"), R_RR)
  _symbolTable.addPrimop(getQName("/"), R_RR)
  _symbolTable.addPrimop(getQName("%"), R_RR)

  // Operators +, -, * defined on integer types.
  // Operators / and % are not  defined on integers (may cause exception)
  _symbolTable.addPrimop(getQName("+"), I_II)
  _symbolTable.addPrimop(getQName("-"), I_II)
  _symbolTable.addPrimop(getQName("*"), I_II)

   // Operators <, <= >, >= defined on real types.
  _symbolTable.addPrimop(getQName("<"),  B_RR)
  _symbolTable.addPrimop(getQName("<="), B_RR)
  _symbolTable.addPrimop(getQName(">"),  B_RR)
  _symbolTable.addPrimop(getQName(">="), B_RR)

  // Operators <, <= >, >= defined on int types.
  _symbolTable.addPrimop(getQName("<"),  B_II)
  _symbolTable.addPrimop(getQName("<="), B_II)
  _symbolTable.addPrimop(getQName(">"),  B_II)
  _symbolTable.addPrimop(getQName(">="), B_II)

  // Operators <, <= >, >= defined on boolean types.
  _symbolTable.addPrimop(getQName("<"),  B_BB)
  _symbolTable.addPrimop(getQName("<="), B_BB)
  _symbolTable.addPrimop(getQName(">"),  B_BB)
  _symbolTable.addPrimop(getQName(">="), B_BB)

  // Operators 'and' and 'or'.
  _symbolTable.addPrimop(getQName("or"), B_BB)
  _symbolTable.addPrimop(getQName("and"), B_BB)

  // Unary minus.
  _symbolTable.addPrimop(getQName("u-"), R_R)
  _symbolTable.addPrimop(getQName("u-"), I_I)
  _symbolTable.pushNamespace("xml", "xml");
    }

    public SymbolTable getSymbolTable() {
  return _symbolTable;
    }

    public Template getTemplate() {
  return _template;
    }

    int _templateIndex = 0;

    public int getTemplateIndex() {
  return(_templateIndex++);
    }

    //!!! temporarily here
    public void internalError() {
  _xsltc.internalError();
    }
   
    public void notYetImplemented(String feature) {
  _xsltc.notYetImplemented(feature);
    }
   
    public void setTemplate(Template template) {
  _template = template;
    }

    private Element findFallback(Element root) {
  final NodeList nodes = root.getChildNodes();
  final int length = (nodes != null) ? nodes.getLength() : 0;

  for (int i = 0; i < length; i++) {
      Node node = nodes.item(i);
      if (node.getNodeType() == Node.ELEMENT_NODE) {
    Element child = (Element)node;
    String namespace = child.getNamespaceURI();
    String localname = child.getLocalName();
    if (namespace.equals(XSLT_URI) &&
        localname.equals("fallback")) {
        return child;
    }
    else {
        Element result = findFallback(child);
        if (result != null) return result;
    }
      }
  }
  return null;
    }

    public Fallback makeFallback(Element root) {
  Element element = findFallback(root);
  if (element != null) {
      Fallback fallback = (Fallback)makeInstance(FALLBACK_CLASS, element);
      fallback.activate();
      fallback.parseContents(element, this);
      return(fallback);
  }
  else {
      return(null);
  }
    }

    /**
     * Creates an object that is of a sub-class of SyntaxTreeNode
     * from the node in the DOM (if possible).
     */
    public SyntaxTreeNode makeInstance(Element element) {
  QName qName = getQName(element.getTagName());
  String className = (String)_instructionClasses.get(qName);
  if (className != null) {
      return makeInstance(className, element);
  }
  else {
      final String namespace = element.getNamespaceURI();
      if (namespace != null) {
    // Check if the element belongs in our namespace
    if (namespace.equals(XSLT_URI)) {
        Fallback fallback = makeFallback(element);
        if (fallback == null)
      _xsltc.notYetImplemented(element.getTagName());
        return(fallback);
    }
    // Check if this is an XSLTC extension element
    else if (namespace.equals(TRANSLET_URI)) {
        Fallback fallback = makeFallback(element);
        if (fallback == null)
      _xsltc.extensionNotSupported(element.getTagName());
        return(fallback);
    }
    // Check if this is an extension of some other XSLT processor
    else if (_xsltc.getStylesheet().isExtension(namespace)) {
        Fallback fallback = makeFallback(element);
        if (fallback == null)
      _xsltc.extensionNotSupported(element.getTagName());
        return(fallback);
    }
      }
      return new LiteralElement();
  }
    }
 
    private SyntaxTreeNode makeInstance(String className, Element element) {
  if (className != null) {
      try {
    final Class clazz = Class.forName(className);
    SyntaxTreeNode node = (SyntaxTreeNode)clazz.newInstance();
    node.setParser(this);
    return node;
      }
      catch (ClassNotFoundException e) {
    e.printStackTrace();
      }
      catch (Exception e) {
    e.printStackTrace();
    _xsltc.internalError();
      }
  }
  else {
      _xsltc.notYetImplemented(element.getTagName());
  }
  return null;
    }

    public Expression parseExpression(SyntaxTreeNode parent,
              String expression) {
  return (Expression)parseTopLevel(parent, "<EXPRESSION>"+expression,
           0, null);
    }

    public Expression parseExpression(SyntaxTreeNode parent,
              Element element, String attrName) {
  return parseExpression(parent, element, attrName, null);
    }

    public Expression parseExpression(SyntaxTreeNode parent,
              Element element, String attrName,
              String defaultValue) {
        String expression = element.getAttribute(attrName);
        if (expression.length() == 0 && defaultValue != null) {
            expression = defaultValue;
        }
        //final int line = ((Integer)element.getUserObject()).intValue();
        return (Expression)parseTopLevel(parent, "<EXPRESSION>" + expression,
           -1 /*line*/, expression);
    }

    public Pattern parsePattern(SyntaxTreeNode parent, String pattern) {
  return (Pattern)parseTopLevel(parent, "<PATTERN>"+pattern, 0, pattern);
    }

    public Pattern parsePattern(SyntaxTreeNode parent,
        Element element, String attrName) {
        final String pattern = element.getAttribute(attrName);
        //final int line = ((Integer)element.getUserObject()).intValue();
        return (Pattern)parseTopLevel(parent, "<PATTERN>" + pattern,
              -1 /*line*/, pattern);
    }

    private SyntaxTreeNode parseTopLevel(SyntaxTreeNode parent,
           String text, int lineNumber,
           String expression) {
  try {
      _xpathParser.setScanner(new XPathLexer(new StringReader(text)));
      Symbol result = _xpathParser.parse(lineNumber);
      if (result != null) {
    final SyntaxTreeNode node = (SyntaxTreeNode)result.value;
    node.setParser(this);
    node.setParent(parent);
    return node;
      }
            else {
                addError(new ErrorMsg(ErrorMsg.XPATHPAR_ERR,
              lineNumber, expression));
            }
  }
  catch (Exception e) {
      if (_xsltc.debug()) {
    e.printStackTrace();
      }
      // Intentional fall through
  }
  // Return a dummy pattern (which is an expression)
  SyntaxTreeNode.Dummy.setParser(this);
        return SyntaxTreeNode.Dummy;
    }

    /**
     * Returns true if there were any errors during compilation
     */
    public boolean errorsFound() {
  return _errors.size() > 0;
    }

    public boolean warnings() {
  return _warnings.size() > 0;
    }

    /**
     * Adds an error to the vector containing compile-time errors.
     */
    public void addError(ErrorMsg error) {
  _errors.addElement(error);
    }

    public void addWarning(ErrorMsg msg) {
  _warnings.addElement(msg);
    }

    /**
     * Prints all compile-time errors
     */
    public void printErrors() {
  System.err.println("Compile errors:");
  final int size = _errors.size();
  for (int i = 0; i < size; i++) {
      System.err.println("  " + _errors.elementAt(i));
  }
    }

    public void printWarnings() {
  if (_warnings.size() > 0) {
      System.err.println("Warning:");
      final int size = _warnings.size();
      for (int i = 0; i < size; i++) {
    System.err.println("  " + _warnings.elementAt(i));
      }
  }
    }
}
TOP

Related Classes of org.apache.xalan.xsltc.compiler.Parser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.