package tefkat.model.internal;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.ecore.EClass;
import tefkat.model.CompoundTerm;
import tefkat.model.IfTerm;
import tefkat.model.NotTerm;
import tefkat.model.PatternDefn;
import tefkat.model.PatternUse;
import tefkat.model.StratificationException;
import tefkat.model.TefkatException;
import tefkat.model.Term;
import tefkat.model.TrackingUse;
import tefkat.model.VarScope;
import tefkat.model.util.TefkatSwitch;
/**
* Stratification is determined with respect to the tracking classes
* referenced in TrackingUse terms. Each of readers, writers, neg_readers,
* and neg_writers maps from either a type (EClass) to a set of VarScopes (TRule
* or PatternDefn) that have the associated dependency on that type, or from
* a PatternDefn to a set of VarScopes that have the associated dependency on that
* PatternDefn (to capture transitive dependencies).
*
* @author lawley
*
*/
public class Stratifier extends TefkatSwitch {
public final Map readers = new HashMap();
public final Map writers = new HashMap();
public final Map neg_readers = new HashMap();
public final Map neg_writers = new HashMap();
boolean negated = false;
VarScope scope;
public void check(VarScope scope, Term term) throws TefkatException {
this.negated = false;
this.scope = scope;
try {
check(term);
} catch (IllegalStateException e) {
throw new TefkatException(e.getMessage(), e);
}
}
private void store(Map map, Object key) {
if (!map.containsKey(key)) {
map.put(key, new HashSet());
}
Set set = (Set) map.get(key);
set.add(scope);
}
private Object check(Term term, boolean newNegated) {
boolean oldNegated = negated;
negated = newNegated;
Object result = check(term);
negated = oldNegated;
return result;
}
private Object check(Term term) {
return doSwitch(term);
}
/* (non-Javadoc)
* @see tefkat.model.util.TefkatSwitch#caseNotTerm(tefkat.model.NotTerm)
*/
public Object caseNotTerm(NotTerm object) {
return check((Term) object.getTerm().get(0), true);
}
/* (non-Javadoc)
* @see tefkat.model.util.TefkatSwitch#caseIfTerm(tefkat.model.IfTerm)
*/
public Object caseIfTerm(IfTerm object) {
check((Term) object.getTerm().get(1));
check((Term) object.getTerm().get(2));
return check((Term) object.getTerm().get(0), true);
}
/**
* Return the Set of dependency items to add the current scope (TRule or PatternDefn) to.
* @throws TefkatException
*
* @see tefkat.model.util.TefkatSwitch#caseTrackingUse(tefkat.model.TrackingUse)
*/
public Object caseTrackingUse(TrackingUse object) {
EClass key = object.getTracking();
if (null == key) {
throw new IllegalStateException("Cannot stratify TrackingUse with null tracking reference: " + object);
}
List keys = null;
Map map;
if (negated) {
if (object.isTarget()) {
throw new IllegalStateException("Cannot create a tracking instance inside a negation: " + object);
} else {
map = neg_readers;
// Affected by all superclasses as well
}
} else {
if (object.isTarget()) {
map = writers;
// Affects all subclasses as well
keys = key.getEAllSuperTypes();
} else {
map = readers;
// Affected by all superclasses as well
}
}
store(map, key);
if (null != keys) {
for (final Iterator itr = keys.iterator(); itr.hasNext(); ) {
store(map, itr.next());
}
}
return this;
}
/* (non-Javadoc)
* @see tefkat.model.util.TefkatSwitch#casePatternUse(tefkat.model.PatternUse)
*/
public Object casePatternUse(PatternUse object) {
PatternDefn key = object.getDefn();
if (null == key) {
// special case for "println"
return null;
}
Map map;
/*
* A Rule/Pattern cannot be in a stratum less than that of
* a Pattern that it invokes.
*/
if (negated) {
map = neg_readers;
} else {
// FIXME - need to handle TEMPLATEs specially -- "construct"
// transitive call patterns to propagate direct dependencies.
map = readers;
}
store(map, key);
return this;
}
/* (non-Javadoc)
* @see tefkat.model.util.TefkatSwitch#caseCompoundTerm(tefkat.model.CompoundTerm)
*/
public Object caseCompoundTerm(CompoundTerm object) {
List terms = object.getTerm();
for (final Iterator termItr = terms.iterator(); termItr.hasNext(); ) {
Term term = (Term) termItr.next();
check(term);
}
return null;
}
}