Package loop

Source Code of loop.Reducer

package loop;

import loop.ast.*;
import loop.ast.script.FunctionDecl;

import java.util.ArrayList;
import java.util.List;

/**
* Takes an AST generated by the parser and strips it of unnecessary elements. Also optimizes the
* AST to be in its most compact form. This is sometimes referred to as reducing the "parse tree"
* to an AST (abstract syntax tree).
*
* Nothing done in this phase affects the semantics of the program.
*/
public class Reducer {
  private Node ast;

  public Reducer(Node ast) {
    this.ast = ast;
  }

  public Node reduce() {
    // Unwrap top level.
    if (shouldUnwrap(ast)) {
      ast = onlyChildOf(ast);
    }

    return reduce(ast, true);
  }

  private Node reduce(Node bloated, boolean tailPath) {
    List<Node> reduced = new ArrayList<Node>();
    List<Node> children = bloated.children();
    int childrenSize = children.size();

    for (int i = 0; i < childrenSize; i++) {
      Node node = children.get(i);
      node = reduce(node, tailPath && isTailPath(i, childrenSize, bloated));

      // Unwrap any redundant wrappers.
      if (shouldUnwrap(node)) {
        reduced.add(onlyChildOf(node));
        continue;
      }

      reduced.add(node);
    }

    // Use this special tree-detection to tell if there are any tail calls.
    if (tailPath && bloated instanceof CallChain) {
      Node last = children.get(childrenSize - 1);
      if (last instanceof Call) {
        // A "last" call is not a tail call if it is preceded by a binary operator.
          ((Call) last).tailCall(true);
      }
    }

    // Reduce non-children sub-nodes (many of these in various special cases).
    if (bloated instanceof IndexIntoList) {
      IndexIntoList indexIntoList = (IndexIntoList) bloated;

      // See if the nodes themselves merit reduction.
      if (null != indexIntoList.from()) {
        reduce(indexIntoList.from(), false);
        if (shouldUnwrap(indexIntoList.from())) {
          indexIntoList.from(onlyChildOf(indexIntoList.from()));
        }
      }
      if (null != indexIntoList.to()) {
        reduce(indexIntoList.to(), false);
        if (shouldUnwrap(indexIntoList.to())) {
          indexIntoList.to(onlyChildOf(indexIntoList.to()));
        }
      }
    } else if (bloated instanceof Comprehension) {
      Comprehension comprehension = (Comprehension) bloated;

      reduce(comprehension.inList(), false);
      if (shouldUnwrap(comprehension.inList())) {
        comprehension.inList(onlyChildOf(comprehension.inList()));
      }

      // the filter clause is optional.
      if (null != comprehension.filter()) {
        reduce(comprehension.filter(), false);
        if (shouldUnwrap(comprehension.filter())) {
          comprehension.filter(onlyChildOf(comprehension.filter()));
        }
      }
    } else if (bloated instanceof Call) {
      Call call = (Call) bloated;

      if (call.args() != null) {
        reduce(call.args(), false);
      }
    }  else if (bloated instanceof ConstructorCall) {
      ConstructorCall call = (ConstructorCall) bloated;

      if (call.args() != null) {
        reduce(call.args(), false);
      }
    } else if (bloated instanceof PatternRule) {
      PatternRule rule = (PatternRule) bloated;

      if (null != rule.rhs)
        reduce(rule.rhs, true);
    } else if (bloated instanceof Guard) {
      Guard guard = (Guard) bloated;

      reduce(guard.expression, false);
      reduce(guard.line, true);
    } else if (bloated instanceof FunctionDecl) {
      FunctionDecl decl = (FunctionDecl) bloated;
      if (!decl.whereBlock().isEmpty()) {
        for (Node node : decl.whereBlock()) {
          reduce(node, true);
        }
      }
    }

    bloated.children().clear();
    bloated.children().addAll(reduced);

    // Run through the entire list again and compress list comprehension nodes.
    reduceComprehension(reduced);

    return bloated;
  }

  private static boolean isTailPath(int i, int childrenSize, Node node) {

    // It's the tail path, if this is the last node and it is not a descendent of a binary op.
    return (i == childrenSize - 1 && (!(node instanceof BinaryOp)))

        // Or this is the "then" part of an if-then-else
        || (node instanceof TernaryIfExpression && i == 1);
  }

  private void reduceComprehension(List<Node> reduced) {
    for (Node node : reduced) {
      List<Node> children = node.children();
      if (!children.isEmpty()) {
        Node last = children.get(children.size() - 1);
        if (last instanceof Comprehension) {
          // Assign all preceding siblings as the "project expression"
          // E.g. (x) (+ 2) (for x in ls) becomes ((x + 2) for x in ls)
          List<Node> nodes = new ArrayList<Node>(children.subList(0, children.size() - 1));
          ((Comprehension) last).projection(nodes);

          // Delete the compressed nodes from the original parent.
          children.removeAll(nodes);
        }
      }
    }
  }

  public static Node onlyChildOf(Node node) {
    return node.children().get(0);
  }

  public static boolean shouldUnwrap(Node node) {
    return (node instanceof CallChain || node instanceof Computation)
        && node.children().size() == 1;
  }
}
TOP

Related Classes of loop.Reducer

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.