Package dk.brics.xact.analysis.xmlgraph

Source Code of dk.brics.xact.analysis.xmlgraph.XMLGraphBuilder

package dk.brics.xact.analysis.xmlgraph;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

import dk.brics.automaton.Automaton;
import dk.brics.xact.XMLTemplateException;
import dk.brics.xact.analysis.Debug;
import dk.brics.xact.analysis.XMLAnalysisException;
import dk.brics.xact.analysis.config.Configuration;
import dk.brics.xact.analysis.dataflow.DataflowAnalyzer;
import dk.brics.xact.analysis.dataflow.VariableAnalysis;
import dk.brics.xact.analysis.dataflow.VariableAnalysisElement;
import dk.brics.xact.analysis.flowgraph.FlowGraph;
import dk.brics.xact.analysis.flowgraph.Statement;
import dk.brics.xact.analysis.flowgraph.TemplateConstant;
import dk.brics.xact.analysis.flowgraph.Variable;
import dk.brics.xact.analysis.flowgraph.statements.BasicStatementVisitor;
import dk.brics.xact.analysis.flowgraph.statements.ConcatStm;
import dk.brics.xact.analysis.flowgraph.statements.ConstStm;
import dk.brics.xact.analysis.flowgraph.statements.CopyStm;
import dk.brics.xact.analysis.flowgraph.statements.GapifyStm;
import dk.brics.xact.analysis.flowgraph.statements.GetStm;
import dk.brics.xact.analysis.flowgraph.statements.InsertStm;
import dk.brics.xact.analysis.flowgraph.statements.NodeStm;
import dk.brics.xact.analysis.flowgraph.statements.PlugStm;
import dk.brics.xact.analysis.flowgraph.statements.RemoveStm;
import dk.brics.xact.analysis.flowgraph.statements.SetStm;
import dk.brics.xact.analysis.flowgraph.statements.ValidateStm;
import dk.brics.xmlgraph.AttributeNode;
import dk.brics.xmlgraph.ChoiceNode;
import dk.brics.xmlgraph.ElementNode;
import dk.brics.xmlgraph.Node;
import dk.brics.xmlgraph.OneOrMoreNode;
import dk.brics.xmlgraph.SequenceNode;
import dk.brics.xmlgraph.TextNode;
import dk.brics.xmlgraph.XMLGraph;
import dk.brics.xmlgraph.XMLGraphFragment;

/**
* Performs dataflow analysis on flow graphs to build XML graphs.
*/
public class XMLGraphBuilder {
 
  private XMLGraph global_xg;

  private  DataflowAnalyzer<VariableAnalysisElement<XMLGraph>> da;
 
  private Set<Statement> empty_xpath;
 
  private Set<Statement> check_fails;
//  private Configuration config;
  private SequenceNode emptySequence;
 
  /**
   * Builds and executes a dataflow analyzer for the given flow graph.
   */
  public XMLGraphBuilder(FlowGraph fg, Configuration config) {
    // build XML graph fragments for schemas, constants, etc.
//    this.config = config;
    global_xg = fg.getXMLGraph().clone();
    empty_xpath = new HashSet<Statement>();
    check_fails = new HashSet<Statement>();
    final StatementNodes stm_nodes = new StatementNodes();
    ChoiceNode dummy_root_content = new ChoiceNode(new ArrayList<Integer>(), null);
    global_xg.addNode(dummy_root_content);
    ElementNode dummy_root = new ElementNode(Automaton.makeEmpty(), dummy_root_content.getIndex(), false, null);
    global_xg.addNode(dummy_root);
    emptySequence = new SequenceNode(new ArrayList<Integer>(), null);
    global_xg.addNode(emptySequence);
    stm_nodes.setEmptySequenceNode(emptySequence);
    for (Statement s : fg.getNodes()) {
      s.visitBy(new BasicStatementVisitor() {
        @Override
        public void visitSetStm(SetStm s) {
          TextNode tn = new TextNode(Automaton.makeEmpty(), s.getOrigin());
          global_xg.addNode(tn);
          stm_nodes.setSetTextNode(s, tn);
        }
       
        @Override
        public void visitInsertStm(InsertStm s) {
          SequenceNode seq = new SequenceNode(new ArrayList<Integer>(), s.getOrigin());
          ChoiceNode left = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
          ChoiceNode right = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
          TextNode tn = new TextNode(Automaton.makeEmpty(), s.getOrigin());
         
          global_xg.addNode(seq);
          global_xg.addNode(left);
          global_xg.addNode(right);
          global_xg.addNode(tn);
         
          seq.addContent(left.getIndex());
          seq.addContent(right.getIndex());
         
          stm_nodes.setInsertLeftSide(s, left);
          stm_nodes.setInsertRightSide(s, right);
          stm_nodes.setInsertSequenceNode(s, seq);
          stm_nodes.setInsertTextNode(s, tn);
        }
       
        @Override
        public void visitConcatStm(ConcatStm s) {
          ChoiceNode cn = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
          SequenceNode sn = new SequenceNode(new ArrayList<Integer>(), s.getOrigin());
          OneOrMoreNode on = new OneOrMoreNode(cn.getIndex(), s.getOrigin());
          TextNode tn = new TextNode(Automaton.makeEmpty(), s.getOrigin());
         
          global_xg.addNode(cn);
          global_xg.addNode(sn);
          global_xg.addNode(on);
          global_xg.addNode(tn);
         
          on.setContent(cn.getIndex());
         
          stm_nodes.setConcatOneOrMoreNode(s, on);
          stm_nodes.setConcatTextNode(s, tn);
          stm_nodes.setConcatChoiceNode(s, cn);
          stm_nodes.setConcatSequenceNode(s, sn);
        }
       
        @Override
        public void visitConstStm(ConstStm s) {
          TemplateConstant t = s.getConst();
          try {
            stm_nodes.setTemplateConstantXMLFragment(t, t.getFragment());
          } catch (XMLTemplateException e) {
            Throwable tr = e;
            if (tr.getCause() != null)
              tr = tr.getCause();
            String msg = tr.getMessage();
            if (msg.endsWith("."))
              msg = msg.substring(0, msg.length() - 1);
           
            if (System.getProperty("dk.brics.xact.analysis.tolerate-errors") != null) {
              // error recovery if enabled
              System.err.println("Error: " + msg + " at " + s.getOrigin());
              Node empty = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
              global_xg.addNode(empty);
              stm_nodes.setTemplateConstantXMLFragment(t, new XMLGraphFragment(empty, new HashSet<String>(), new HashSet<String>(), new HashMap<String,String>()));
            } else {
              throw new XMLAnalysisException(msg, s.getOrigin());
            }
          }
        }

        @Override
        public void visitGetStm(GetStm s) {
          ChoiceNode cn = new ChoiceNode(new HashSet<Integer>(), s.getOrigin());
          global_xg.addNode(cn);
          stm_nodes.setGetChoiceNode(s, cn);
          switch (s.getKind()) {
          case GETNEXTATTR:
          case GETNEXTATTRIBUTE:
          case GETNEXTSIBLING:
          case GETFIRSTELEMENT:
              SequenceNode sq = new SequenceNode(new ArrayList<Integer>(), s.getOrigin());
              global_xg.addNode(sq);
              stm_nodes.setGetEmptySequence(s, sq);
//            OneOrMoreNode on = new OneOrMoreNode(cn.getIndex(), s.getOrigin());
//            global_xg.addNode(on);
//            stm_nodes.setGetOneOrMoreNode(s, on);
            break;
          }
        }
       
        @Override
        public void visitGapifyStm(GapifyStm s) {
          ChoiceNode cn = new ChoiceNode(s.getGapName(), false, false, new HashSet<Integer>(), s.getOrigin());
          global_xg.addNode(cn);
          stm_nodes.setGapifyChoiceNode(s, cn);
        }

        @Override
        public void visitPlugStm(PlugStm s) {
          switch (s.getKind()) {
          case CLOSE:
            SequenceNode sn = new SequenceNode(new ArrayList<Integer>(), s.getOrigin());
            global_xg.addNode(sn);
            stm_nodes.setPlugSequenceNode(s, sn);
            break;
           
          case PLUGMULTI:
          case PLUG: {
            TextNode tn = new TextNode(Automaton.makeEmpty(), s.getOrigin());
            global_xg.addNode(tn);
            stm_nodes.setPlugTextNode(s, tn);
            break;
          }
           
          case PLUGWRAP: {
            ChoiceNode top = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
            SequenceNode empty = new SequenceNode(new ArrayList<Integer>(), s.getOrigin());
            OneOrMoreNode on = new OneOrMoreNode(-1, s.getOrigin());
            ChoiceNode content = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
            TextNode tn = new TextNode(Automaton.makeEmpty(), s.getOrigin());
           
            global_xg.addNode(top);
            global_xg.addNode(empty);
            global_xg.addNode(on);
            global_xg.addNode(content);
            global_xg.addNode(tn);
           
            top.getContents().add(empty.getIndex());
            top.getContents().add(on.getIndex());
            on.setContent(content.getIndex());
            content.getContents().add(tn.getIndex());
           
            stm_nodes.setPlugWrapTopNode(s, top);
            stm_nodes.setPlugWrapContentNode(s, content);
            stm_nodes.setPlugTextNode(s, tn);
            break;
          }
          }
        }
       
        @Override
        public void visitRemoveStm(RemoveStm s) {
          SequenceNode sn = new SequenceNode(new ArrayList<Integer>(), s.getOrigin());
          global_xg.addNode(sn);
          stm_nodes.setRemoveSequenceNode(s, sn);
        }
       
        @Override
        public void visitNodeStm(NodeStm s) {
          switch (s.getKind()) {
          case ATTRIBUTE: {
            SequenceNode seq = new SequenceNode(new LinkedList<Integer>(), s.getOrigin());
            ChoiceNode left = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
            AttributeNode attr = new AttributeNode(s.getName(), 0, s.getOrigin());
            TextNode text = new TextNode(s.getValue(), s.getOrigin());

            global_xg.addNode(seq);
            global_xg.addNode(left);
            global_xg.addNode(text);
            global_xg.addNode(attr);
           
            seq.addContent(left.getIndex());
            left.getContents().add(attr.getIndex());
            attr.setContent(text.getIndex());
           
            stm_nodes.setStmNode(s, seq);
           
            if (s.getNextNode() != null) {
              ChoiceNode next = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
              global_xg.addNode(next);
              seq.addContent(next.getIndex());
              stm_nodes.setStmNextNode(s, next);
            }
            break;
          }
          case ELEMENT: {
            SequenceNode seq = new SequenceNode(new LinkedList<Integer>(), s.getOrigin());
            ChoiceNode left1 = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
            ChoiceNode left2 = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
            SequenceNode left3 = new SequenceNode(new LinkedList<Integer>(), s.getOrigin());
            ElementNode element = new ElementNode(s.getName(), 0, false, s.getOrigin());
           
            global_xg.addNode(seq);
            global_xg.addNode(left1);
            global_xg.addNode(left2);
            global_xg.addNode(left3);
            global_xg.addNode(element);
           
            seq.getContents().add(left1.getIndex());
            left1.getContents().add(element.getIndex());
            element.setContent(left2.getIndex());
            left2.getContents().add(left3.getIndex());
           
            stm_nodes.setStmNode(s, seq);
            if (s.getNextNode() != null) {
              ChoiceNode next = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
              global_xg.addNode(next);
              seq.addContent(next.getIndex());
              stm_nodes.setStmNextNode(s, next);
            }
            if (s.getFirstAttr() != null) {
              ChoiceNode attr = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
              global_xg.addNode(attr);
              left3.addContent(attr.getIndex());
              stm_nodes.setStmFirstAttribute(s, attr);
            }
            if (s.getFirstChild() != null) {
              ChoiceNode child = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
              global_xg.addNode(child);
              left3.addContent(child.getIndex());
              stm_nodes.setStmFirstChild(s, child);
            }
            break;
          }
          case TEXT: {
            SequenceNode seq = new SequenceNode(new ArrayList<Integer>(), s.getOrigin());
            TextNode tn = new TextNode(s.getValue(), s.getOrigin());
           
            global_xg.addNode(seq);
            global_xg.addNode(tn);
           
            seq.addContent(tn.getIndex());
            stm_nodes.setStmNode(s, seq);
           
            if (s.getNextNode() != null) {
              ChoiceNode next = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
              global_xg.addNode(next);
              seq.addContent(next.getIndex());
              stm_nodes.setStmNextNode(s, next);
            }
            break;
          }
          case TEMPLATEGAP:
          case ATTRIBUTEGAP: {
            SequenceNode seq = new SequenceNode(new LinkedList<Integer>(), s.getOrigin());
            ChoiceNode cn = new ChoiceNode(s.getGap(), false, false, new LinkedHashSet<Integer>(), s.getOrigin());

            global_xg.addNode(seq);
            global_xg.addNode(cn);
           
            seq.addContent(cn.getIndex());
            stm_nodes.setStmNode(s, seq);
            stm_nodes.setStmGap(s, cn);
           
            if (s.getNextNode() != null) {
              ChoiceNode next = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
              global_xg.addNode(next);
              seq.addContent(next.getIndex());
              stm_nodes.setStmNextNode(s, next);
            }
            break;
          }
          case COMMENT:
          case PROCESSINGINSTRUCTION: {
            SequenceNode sn = new SequenceNode(new LinkedList<Integer>(), s.getOrigin());
            global_xg.addNode(sn);
            stm_nodes.setStmNode(s, sn);
            if (s.getNextNode() != null) {
              ChoiceNode next = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
              global_xg.addNode(next);
              sn.addContent(next.getIndex());
              stm_nodes.setStmNextNode(s, next);
            }
            break;
          }
          default:
            throw new RuntimeException("unknown node stm kind: " + s.getKind());
          }
        }
       
        @Override
        public void visitCopyStm(CopyStm s) {
          SequenceNode seq = new SequenceNode(new LinkedList<Integer>(), s.getOrigin());
          ChoiceNode left1 = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
          global_xg.addNode(seq);
          global_xg.addNode(left1);
          stm_nodes.setCopyTopNode(s, seq);
          stm_nodes.setCopyLeftChoice(s, left1);
          seq.addContent(left1.getIndex());
         
          if (s.getNextNode() != null) {
            ChoiceNode next = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
            global_xg.addNode(next);
            seq.addContent(next.getIndex());
            stm_nodes.setCopyNextNode(s, next);
          }
          switch (s.getKind()) {
          case ELEMENT: { // element nodes are handled specially
            ChoiceNode left2 = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
            SequenceNode left3 = new SequenceNode(new LinkedList<Integer>(), s.getOrigin());
            ElementNode element = new ElementNode(Automaton.makeEmpty(), 0, false, s.getOrigin());
           
            global_xg.addNode(left2);
            global_xg.addNode(left3);
            global_xg.addNode(element);
           
            stm_nodes.setCopyElementNode(s, element);
           
            left1.getContents().add(element.getIndex());
            element.setContent(left2.getIndex());
            left2.getContents().add(left3.getIndex());
            if (s.getFirstAttr() != null) {
              ChoiceNode attr = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
              global_xg.addNode(attr);
              left3.addContent(attr.getIndex());
              stm_nodes.setCopyFirstAttribute(s, attr);
            }
            if (s.getFirstChild() != null) {
              ChoiceNode child = new ChoiceNode(new LinkedHashSet<Integer>(), s.getOrigin());
              global_xg.addNode(child);
              left3.addContent(child.getIndex());
              stm_nodes.setCopyFirstChild(s, child);
            }
            break;
          }
          case ATTRIBUTE:
          case ATTRNODE:
            break;
          case PROCESSINGINSTRUCTION:
          case COMMENT:
            break;
          case ATTRIBUTEGAP:
          case TEMPLATEGAP:
            break;
          case TEXT:
          case TEMPNODE:
            break;
          }//switch
        }
        @Override
        public void visitValidateStm(ValidateStm s) {
          if (s.getSchema().getGapTypes() != null) {
            for (Map.Entry<String,String> entry : s.getSchema().getGapTypes().entrySet()) {
              ChoiceNode gap = new ChoiceNode(entry.getKey(), false, false, new LinkedHashSet<Integer>(), s.getSchema().getOrigin());
              global_xg.addNode(gap);
              stm_nodes.setValidateGap(s, entry.getKey(), gap);
            }
          }
        }
      });
    }
    // run dataflow analysis   
    Debug.println(2, true, "XML graph nodes: " + global_xg.getNodes().size());
    da = new DataflowAnalyzer<VariableAnalysisElement<XMLGraph>>(fg,
        new VariableAnalysis<XMLGraph>(new XMLGraphAnalysis(global_xg, dummy_root, dummy_root_content,
            fg.getNamespaces(), stm_nodes,
            empty_xpath, check_fails)));
    Debug.println(2, true, "Performing XML graph dataflow analysis");
    da.run();
  }
 
  /**
   * Returns the XML graph for the given variable at the entry of the given statement.
   * An empty XML graph is returned if no information is available for the given input.
   */
  public XMLGraph getIn(Statement s, Variable v) {
    VariableAnalysisElement<XMLGraph> vae = da.getFlowIn(s);
    if (vae == null) {
      Debug.println(10, true, "getFlowIn(" + s + ")==null");
      return global_xg;
    }
    return vae.get(v);
  }

  /**
   * Returns the XML graph for the given variable at the exit of the given statement.
   * An empty XML graph is returned if no information is available for the given input.
   */
  public XMLGraph getOut(Statement s, Variable v) {
    VariableAnalysisElement<XMLGraph> vae = da.getFlowOut(s);
    if (vae == null) {
      Debug.println(10, true, "getFlowOut(" + s + ")==null");
      return global_xg;
    }
    XMLGraph g = vae.get(v);
    if (g == null) {
      Debug.println(10, true, "getFlowOut(" + s + ")(" + v + ")==null");
      return global_xg;
    }
    return g;
  }
 
  /**
   * Returns the global XML graph containing fragments for schemas and constants.
   */
  public XMLGraph getGlobalXMLGraph() {
    return global_xg;
  }

  /**
   * Returns the set of statements where XPath evaluation resulted in the empty node set.
   */
  public Set<Statement> getEmptyXPathStatements() {
    return empty_xpath;
  }
 
  /**
   * Returns the set of node test statements that always fail.
   */
  public Set<Statement> getCheckFailsStatements() {
    return check_fails;
  }
 
  public SequenceNode getEmptySequence() {
    return emptySequence;
  }
}
TOP

Related Classes of dk.brics.xact.analysis.xmlgraph.XMLGraphBuilder

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.