/**
* Copyright (c) 2009-2011, The HATS Consortium. All rights reserved.
* This file is licensed under the terms of the Modified BSD License.
*/
package abs.frontend.delta;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.common.base.Strings;
import abs.frontend.analyser.SemanticConditionList;
import abs.frontend.ast.DeltaDecl;
import abs.frontend.ast.Product;
import abs.frontend.ast.Model;
/*
* A DeltaTrie (product family generation trie, Damiani & Schaefer 2012) is a representation of all possible products.
* Type checking all possible product variants amounts to traversing the trie and computing the type abstractions
* for all (intermediate) products associated to the nodes of the trie.
*
*/
public class DeltaTrie {
private final Node root;
private final Model model;
/**
* Constructor
*/
public DeltaTrie(Model model, SemanticConditionList errors) {
this.model = model;
root = new Node(errors);
}
// Adds a word to the Trie
public void addWord(List<String> word, Product product) {
// System.out.print("DeltaSequence");
if (word.size() == 0) // no deltas
root.isValidProduct = true;
else
root.addWord(word, product, 0);
// System.out.println();
}
/**********************************************************************************************/
/*
* Trie node
*/
class Node {
private final Map<String, Node> children;
private String deltaID = null;
private boolean isValidProduct = false;
private final ProgramTypeAbstraction ta;
// Constructor for top level root node
public Node(SemanticConditionList errors) {
this.deltaID = "core";
this.children = new HashMap<String, Node>();
this.ta = new ProgramTypeAbstraction(errors);
model.buildCoreTypeAbstraction(ta);
}
// Constructor for child node
public Node(String name, ProgramTypeAbstraction ta) {
this.children = new HashMap<String, Node>();
this.deltaID = name;
this.ta = ta;
}
/** Add a word to the trie
*
* @param word Non-empty List of delta names
* @param product The SPL product that this word represents (or null if none)
* @param d Index of List element to start with (for recursive invocation)
*/
protected void addWord(List<String> word, Product product, int d) {
Node nextNode;
//System.out.print(">>>" + word.get(d));
if (children.containsKey(word.get(d))) {
// node already exists
nextNode = children.get(word.get(d));
} else {
ProgramTypeAbstraction nextTA = new ProgramTypeAbstraction(ta);
nextNode = new Node(word.get(d), nextTA);
// Apply delta to nextNode's program type abstraction
DeltaDecl delta = model.getDeltaDeclsMap().get(nextNode.deltaID);
nextTA.applyDelta(delta, product);
children.put(word.get(d), nextNode);
//System.out.print("*");
}
if (word.size() > d+1)
nextNode.addWord(word, product, d+1);
else {
nextNode.isValidProduct = true;
//System.out.println("TA: \n" + ta);
// TODO type check this product (???)
//System.out.println(".");
}
}
// Getters
public Map<String, Node> getChildren() {
return children;
}
public String getDeltaID() {
return deltaID;
}
public boolean isValidProduct() {
return isValidProduct;
}
public ProgramTypeAbstraction getProgramTypeAbstraction() {
return ta;
}
/*
@Override
public String toString() {
return toString(new StringBuilder(), false);
}
public String toString(StringBuilder s, boolean printTA) {
s.append("Delta: " + deltaID + ". " + "Valid Product: " + isValidProduct + "\n");
if (printTA)
s.append(ta.toString());
for (Node child : children.values())
child.toString(s, printTA);
return s.toString();
}
*/
protected int height() {
int h = 0;
for (Node child : children.values())
h = Math.max(h, child.height());
return 1 + h;
}
protected void traversePreorder(StringBuilder s, int level) {
s.append(Strings.repeat("| ", level));
s.append("|---");
s.append(getDeltaID() + (isValidProduct() ? "\u2713" : "") + "\n");
for (Node child : getChildren().values())
child.traversePreorder(s, level+1);
}
}
/*
* Convenience methods
*/
public Node getRoot() {
return root;
}
/*
* Height of the tree (1=only root node)
*/
public int height() {
return root.height();
}
/*
* Return a textual representation of the tree
* A checkmark next to a node means it represents a valid product.
*/
@Override
public String toString() {
StringBuilder s = new StringBuilder();
root.traversePreorder(s, 0);
return s.toString();
}
}