Package org.rascalmpl.interpreter.debug

Source Code of org.rascalmpl.interpreter.debug.DebugUpdater$PushDownTreeVisitor

/*******************************************************************************
* Copyright (c) 2012-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:
*   * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI
*******************************************************************************/
package org.rascalmpl.interpreter.debug;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.eclipse.imp.pdb.facts.IConstructor;
import org.eclipse.imp.pdb.facts.IList;
import org.eclipse.imp.pdb.facts.IListWriter;
import org.eclipse.imp.pdb.facts.INode;
import org.eclipse.imp.pdb.facts.ISet;
import org.eclipse.imp.pdb.facts.IString;
import org.eclipse.imp.pdb.facts.IValue;
import org.eclipse.imp.pdb.facts.IValueFactory;
import org.rascalmpl.values.ValueFactoryFactory;
import org.rascalmpl.values.uptr.Factory;
import org.rascalmpl.values.uptr.ProductionAdapter;
import org.rascalmpl.values.uptr.TreeAdapter;
import org.rascalmpl.values.uptr.visitors.TreeVisitor;

public class DebugUpdater {

  /**
   * Transforms an <code>tree</tree> by pushing 'deferred breakable' annotations
   * from an production to the application of the corresponding child.
   *
   * @param tree a parse tree
   * @return tree with pushed-down attributes, unmodified tree in case of error
   */
  public static IConstructor pushDownAttributes(IConstructor tree) {
    return ((IConstructor) tree.accept(new PushDownTreeVisitor<RuntimeException>(false)));
  }
   
  private static class PushDownTreeVisitor<E extends Throwable> extends TreeVisitor<E> {
   
    final static private IValueFactory VF = ValueFactoryFactory.getValueFactory();
   
    final private boolean addBreakable;
   
    public PushDownTreeVisitor(final boolean addBreakable) {
      this.addBreakable = addBreakable;
    }
   
    @Override
    public IConstructor visitTreeCycle(IConstructor arg)
        throws E {
      return arg;
    }
   
    @Override
    public IConstructor visitTreeChar(IConstructor arg) throws E {
      return arg;
    }

    @Override
    public IConstructor visitTreeAmb(IConstructor arg) throws E {
      return arg;
    }
   
    @Override
    public IConstructor visitTreeAppl(IConstructor arg) throws E {
      IConstructor prod = TreeAdapter.getProduction(arg);
     
      if (TreeAdapter.isAppl(arg)
          && !ProductionAdapter.isLayout(prod)
          && !ProductionAdapter.isLiteral(prod)
          && !ProductionAdapter.isCILiteral(prod)
          && !ProductionAdapter.isLexical(prod)) {
       
        boolean isList = ProductionAdapter.isSeparatedList(prod) || ProductionAdapter.isList(prod);

        // 1: does current production application need an annotation?
        if (hasBreakableAttributeTag(prod) || addBreakable && !isList) {
          arg = arg.asAnnotatable().setAnnotation("breakable", VF.bool(true));
        }
       
        // 2: push-down deferred production names.
        Set<Integer> pushdownPositions = getChildProductionPositionsForPushdown(prod);       
                     
        // update children by recursively applying this visitor.
        IListWriter writer = VF.listWriter(Factory.Args.getElementType());

        Iterator<IValue> iter = TreeAdapter.getArgs(arg).iterator();
        for (Integer pos = 0; iter.hasNext(); pos++) {
         
          boolean isDeferred = pushdownPositions.contains(pos) || addBreakable && isList;
         
          IValue oldKid = iter.next();
          IValue newKid = oldKid.accept(new PushDownTreeVisitor<E>(isDeferred));
         
          writer.append(newKid);
        }

        IList children = writer.done();

        // update current tree with processed children
        arg = TreeAdapter.setArgs(arg, children);
      }
   
      return arg;
    }     
   
    /**
     * @return <code>true</code> if has breakable tag, otherwise <code>false</code>
     */
    private static boolean hasBreakableAttributeTag(IConstructor production) {
      ISet attributes = ProductionAdapter.getAttributes(production);
      return attributes != null
          && attributes.contains(VF.constructor(Factory.Attr_Tag,VF.node("breakable")));
    }   
     
    private static String[] getChildProductionNamesForPushDown(IConstructor production) {
      ISet attributes = ProductionAdapter.getAttributes(production);

      String[] result = {};
      for (IValue attributeValue : attributes) {
       
        if (attributeValue.getType().isAbstractData() && !attributeValue.getType().isBottom()) {
          IConstructor attributeConstructor = (IConstructor)attributeValue;

          if (attributeConstructor.getName().equals("tag")) {
       
            for (IValue childValue : attributeConstructor.getChildren()) {
              INode childNode = (INode)childValue;

              // non-empty breakable tag?
              if (childNode.getName().equals("breakable")
                  && childNode.getChildren().iterator().hasNext()) {

                String c = ((IString)childNode.get(0)).getValue();
                String s = c.substring(1,c.length()-1);
                result = s.split(",");
              }
            }
          }
        }
      }
      return result;
    }
   
    private static Set<Integer> getChildProductionPositionsForPushdown(IConstructor production) {
      Set<Integer> result = new HashSet<Integer>();

      Set<String> pushDownProductionNames = new HashSet<String>(
          Arrays.asList(getChildProductionNamesForPushDown(production)));

      if (!pushDownProductionNames.isEmpty()) {
     
        Iterator<IValue> iter = ProductionAdapter.getSymbols(production).iterator();
        for (Integer pos = 0; iter.hasNext(); pos++) {
 
          IValue kidValue = iter.next();
 
          if (kidValue.getType().isAbstractData() && !kidValue.getType().isBottom()) {
            IConstructor kidConstructor = (IConstructor)kidValue;
           
            if (kidConstructor.getName().equals("label")) {
             
              String labelName = ((IString) kidConstructor.get(0)).getValue();
             
              if (pushDownProductionNames.contains(labelName)) {
                result.add(pos);
              }
            }
          }
        }
      }     
      return result;
    }
   
  }
 
}
TOP

Related Classes of org.rascalmpl.interpreter.debug.DebugUpdater$PushDownTreeVisitor

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.