Package org.rascalmpl.parser.uptr.recovery

Source Code of org.rascalmpl.parser.uptr.recovery.Recoverer

/*******************************************************************************
* Copyright (c) 2009-2013 CWI
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:

*   * Jurgen J. Vinju - Jurgen.Vinju@cwi.nl - CWI
*   * Arnold Lankamp - Arnold.Lankamp@cwi.nl
*******************************************************************************/
package org.rascalmpl.parser.uptr.recovery;

import org.eclipse.imp.pdb.facts.IConstructor;
import org.rascalmpl.parser.gtd.recovery.IRecoverer;
import org.rascalmpl.parser.gtd.result.AbstractNode;
import org.rascalmpl.parser.gtd.stack.AbstractStackNode;
import org.rascalmpl.parser.gtd.stack.RecoveryPointStackNode;
import org.rascalmpl.parser.gtd.stack.SkippingStackNode;
import org.rascalmpl.parser.gtd.stack.edge.EdgesSet;
import org.rascalmpl.parser.gtd.util.ArrayList;
import org.rascalmpl.parser.gtd.util.DoubleArrayList;
import org.rascalmpl.parser.gtd.util.DoubleStack;
import org.rascalmpl.parser.gtd.util.IntegerObjectList;
import org.rascalmpl.parser.gtd.util.ObjectKeyedIntegerMap;
import org.rascalmpl.parser.gtd.util.Stack;
import org.rascalmpl.values.uptr.ProductionAdapter;

public class Recoverer implements IRecoverer<IConstructor>{
  // TODO: its a magic constant, and it may clash with other generated constants
  // should generate implementation of static int getLastId() in generated parser to fix this.
  private int recoveryId = 100000;
 
  private final int[][] continuationCharactersList;
 
  private final ObjectKeyedIntegerMap<IConstructor> robust;
 
  public Recoverer(IConstructor[] robustProds, int[][] continuationCharactersList){
    super();
   
    this.continuationCharactersList = continuationCharactersList;
   
    this.robust = new ObjectKeyedIntegerMap<IConstructor>();
   
    for (int i = robustProds.length - 1; i >= 0; --i) {
      robust.put(robustProds[i], i);
    }
  }
 
  private DoubleArrayList<AbstractStackNode<IConstructor>, AbstractNode> reviveNodes(int[] input, int location, DoubleArrayList<AbstractStackNode<IConstructor>, ArrayList<IConstructor>> recoveryNodes){
    DoubleArrayList<AbstractStackNode<IConstructor>, AbstractNode> recoveredNodes = new DoubleArrayList<AbstractStackNode<IConstructor>, AbstractNode>();
   
    for(int i = recoveryNodes.size() - 1; i >= 0; --i) {
      AbstractStackNode<IConstructor> recoveryNode = recoveryNodes.getFirst(i);
      ArrayList<IConstructor> prods = recoveryNodes.getSecond(i);
     
      // Handle every possible continuation associated with the recovery node (there can be more then one because of prefix-sharing).
      for(int j = prods.size() - 1; j >= 0; --j){
        IConstructor prod = prods.get(j);
       
        AbstractStackNode<IConstructor> continuer = new RecoveryPointStackNode<IConstructor>(recoveryId++, prod, recoveryNode);
       
        int startLocation = recoveryNode.getStartLocation();
       
        int[] until = continuationCharactersList[robust.get(prod)];
        AbstractStackNode<IConstructor> recoverLiteral = new SkippingStackNode<IConstructor>(recoveryId++, until, input, startLocation, prod);
        recoverLiteral = recoverLiteral.getCleanCopy(startLocation);
        recoverLiteral.initEdges();
        EdgesSet<IConstructor> edges = new EdgesSet<IConstructor>(1);
        edges.add(continuer);
       
        recoverLiteral.addEdges(edges, startLocation);
       
        continuer.setIncomingEdges(edges);
       
        recoveredNodes.add(recoverLiteral, recoverLiteral.getResult());
      }
    }
   
    return recoveredNodes;
  }
 
  private DoubleArrayList<AbstractStackNode<IConstructor>, AbstractNode> reviveFailedNodes(int[] input, int location, ArrayList<AbstractStackNode<IConstructor>> failedNodes) {
    DoubleArrayList<AbstractStackNode<IConstructor>, ArrayList<IConstructor>> recoveryNodes = new DoubleArrayList<AbstractStackNode<IConstructor>, ArrayList<IConstructor>>();
   
    for(int i = failedNodes.size() - 1; i >= 0; --i){
      findRecoveryNodes(failedNodes.get(i), recoveryNodes);
    }
   
    return reviveNodes(input, location, recoveryNodes);
  }
 
  private static void collectUnexpandableNodes(Stack<AbstractStackNode<IConstructor>> unexpandableNodes, ArrayList<AbstractStackNode<IConstructor>> failedNodes) {
    for(int i = unexpandableNodes.getSize() - 1; i >= 0; --i){
      failedNodes.add(unexpandableNodes.get(i));
    }
  }
 
  private static void collectUnmatchableMidProductionNodes(int location, DoubleStack<DoubleArrayList<AbstractStackNode<IConstructor>, AbstractNode>, AbstractStackNode<IConstructor>> unmatchableMidProductionNodes, ArrayList<AbstractStackNode<IConstructor>> failedNodes){
    for(int i = unmatchableMidProductionNodes.getSize() - 1; i >= 0; --i){
      DoubleArrayList<AbstractStackNode<IConstructor>, AbstractNode> failedNodePredecessors = unmatchableMidProductionNodes.getFirst(i);
      AbstractStackNode<IConstructor> failedNode = unmatchableMidProductionNodes.getSecond(i).getCleanCopy(location); // Clone it to prevent by-reference updates of the static version
     
      // Merge the information on the predecessors into the failed node.
      for(int j = failedNodePredecessors.size() - 1; j >= 0; --j){
        AbstractStackNode<IConstructor> predecessor = failedNodePredecessors.getFirst(j);
        AbstractNode predecessorResult = failedNodePredecessors.getSecond(j);
        failedNode.updateNode(predecessor, predecessorResult);
      }
     
      failedNodes.add(failedNode);
    }
  }

  private boolean isRobust(IConstructor prod) {
    return robust.contains(prod);
  }
 
  /**
   * Travels up the parse graph in an attempt to find the closest recoverable parent nodes.
   */
  private void findRecoveryNodes(AbstractStackNode<IConstructor> failer, DoubleArrayList<AbstractStackNode<IConstructor>, ArrayList<IConstructor>> recoveryNodes) {
    ObjectKeyedIntegerMap<AbstractStackNode<IConstructor>> visited = new ObjectKeyedIntegerMap<AbstractStackNode<IConstructor>>();
    Stack<AbstractStackNode<IConstructor>> todo = new Stack<AbstractStackNode<IConstructor>>();
   
    todo.push(failer);
   
    while (!todo.isEmpty()) {
      AbstractStackNode<IConstructor> node = todo.pop();
      if(visited.contains(node)) continue; // Don't follow cycles
     
      visited.put(node, 0);
     
      ArrayList<IConstructor> recoveryProductions = new ArrayList<IConstructor>();
      collectProductions(node, recoveryProductions);
     
      if(recoveryProductions.size() > 0){
        recoveryNodes.add(node, recoveryProductions);
      }
     
      IntegerObjectList<EdgesSet<IConstructor>> edges = node.getEdges();
     
      for(int i = edges.size() - 1; i >= 0; --i){
        EdgesSet<IConstructor> edgesList = edges.getValue(i);

        if (edgesList != null) {
          for(int j = edgesList.size() - 1; j >= 0; --j){
            AbstractStackNode<IConstructor> parent = edgesList.get(j);
           
            todo.push(parent);
          }
        }
      }
    }
  }
 
  // Gathers all productions that are marked for recovery (the given node can be part of a prefix shared production)
  private void collectProductions(AbstractStackNode<IConstructor> node, ArrayList<IConstructor> productions) {
    AbstractStackNode<IConstructor>[] production = node.getProduction();
    if(production == null) return; // The root node does not have a production, so ignore it.
   
    int dot = node.getDot();
   
    if(node.isEndNode()){
      IConstructor parentProduction = node.getParentProduction();
      if(isRobust(parentProduction)){
        productions.add(parentProduction);
       
        if(ProductionAdapter.isList(parentProduction)) return; // Don't follow productions in lists productions, since they are 'cyclic'.
      }
    }
    
    for(int i = dot + 1; i < production.length; ++i){
      AbstractStackNode<IConstructor> currentNode = production[i];
      if(currentNode.isEndNode()){
        IConstructor parentProduction = currentNode.getParentProduction();
        if(isRobust(parentProduction)){
          productions.add(parentProduction);
        }
      }
     
      AbstractStackNode<IConstructor>[][] alternateProductions = currentNode.getAlternateProductions();
      if(alternateProductions != null){
        for(int j = alternateProductions.length - 1; j >= 0; --j){
          collectProductions(alternateProductions[j][i], productions);
        }
      }
    }
  }
 
  public DoubleArrayList<AbstractStackNode<IConstructor>, AbstractNode> reviveStacks(int[] input,
      int location,
      Stack<AbstractStackNode<IConstructor>> unexpandableNodes,
      Stack<AbstractStackNode<IConstructor>> unmatchableLeafNodes,
      DoubleStack<DoubleArrayList<AbstractStackNode<IConstructor>, AbstractNode>, AbstractStackNode<IConstructor>> unmatchableMidProductionNodes,
      DoubleStack<AbstractStackNode<IConstructor>, AbstractNode> filteredNodes) {
    ArrayList<AbstractStackNode<IConstructor>> failedNodes = new ArrayList<AbstractStackNode<IConstructor>>();
    collectUnexpandableNodes(unexpandableNodes, failedNodes);
    collectUnmatchableMidProductionNodes(location, unmatchableMidProductionNodes, failedNodes);
    //collectFilteredNodes(filteredNodes, failedNodes);
   
    return reviveFailedNodes(input, location, failedNodes);
  }
}
TOP

Related Classes of org.rascalmpl.parser.uptr.recovery.Recoverer

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.