blob: 914a16decb2919bc2646b2afc83bdae344bad2ce [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 University of Illinois at Urbana-Champaign and others.
* 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:
* UIUC - Initial API and implementation
*******************************************************************************/
package org.eclipse.rephraserengine.core.preservation;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.eclipse.rephraserengine.core.preservation.ModelDiff.EdgeAdded;
import org.eclipse.rephraserengine.core.preservation.ModelDiff.EdgeDeleted;
import org.eclipse.rephraserengine.core.preservation.ModelDiff.EdgeSinkChanged;
import org.eclipse.rephraserengine.core.vpg.IVPGNode;
import org.eclipse.rephraserengine.core.vpg.VPGEdge;
import org.eclipse.rephraserengine.core.vpg.VPGEdge.Classification;
/**
* Method object implementing the preservation analysis algorithm.
* <p>
* The constructor is given two sorted lists of edges. The positions in the lists are remembered
* between calls to {@link #checkPreservation(int, Classification, ModelDiff)}, so a
* {@link PreservationAnalyzer} can be restarted with a new edge classification or type where it
* left off.
* <p>
* See usage in
* {@link Model#checkPreservation(Model, PreservationRuleset, org.eclipse.core.runtime.IProgressMonitor)}.
*
* @author Jeff Overbey
*/
abstract class PreservationAnalyzer<A, T, R extends IVPGNode<T>> extends PreservationRuleset.Processor
{
@SuppressWarnings("serial")
private static abstract class UnexpectedEdgeException extends Error
{
private VPGEdge<?,?,?> edge;
public UnexpectedEdgeException(VPGEdge<?,?,?> edge)
{
this.edge = edge;
}
@SuppressWarnings("unchecked")
public <A, T, R extends IVPGNode<T>> VPGEdge<A,T,R> getEdge()
{
return (VPGEdge<A,T,R>)edge;
}
}
@SuppressWarnings("serial")
private static class UnexpectedInitialEdge extends UnexpectedEdgeException
{
public UnexpectedInitialEdge(VPGEdge<?,?,?> edge) { super(edge); }
}
@SuppressWarnings("serial")
private static class UnexpectedFinalEdge extends UnexpectedEdgeException
{
public UnexpectedFinalEdge(VPGEdge<?,?,?> edge) { super(edge); }
}
private final Iterable<VPGEdge<A,T,R>> initialEdges;
private final Iterable<VPGEdge<A,T,R>> finalEdges;
private final PreservationRuleset ruleset;
private final Iterator<VPGEdge<A,T,R>> initialIterator;
private final Iterator<VPGEdge<A,T,R>> finalIterator;
private VPGEdge<A,T,R> initialEdge;
private VPGEdge<A,T,R> finalEdge;
private int targetType;
private Classification targetClassification;
public PreservationAnalyzer(
Collection<VPGEdge<A,T,R>> initialEdges,
Collection<VPGEdge<A,T,R>> finalEdges,
PreservationRuleset ruleset)
{
this.initialEdges = initialEdges;
this.finalEdges = finalEdges;
this.ruleset = ruleset;
this.initialIterator = initialEdges.iterator();
this.finalIterator = finalEdges.iterator();
this.initialEdge = initialIterator.hasNext() ? initialIterator.next() : null;
this.finalEdge = finalIterator.hasNext() ? finalIterator.next() : null;
}
public void checkPreservation(int targetType, Classification targetClassification, ModelDiff diff) throws UnexpectedEdgeException
{
this.targetType = targetType;
this.targetClassification = targetClassification;
while (finalEdge() != null || initialEdge() != null)
{
try
{
ruleset.invokeCallback(targetType, targetClassification, this);
}
catch (UnexpectedInitialEdge exception)
{
VPGEdge<A,T,R> entry = exception.getEdge();
System.err.println("Unexpected initial edge " + entry); //$NON-NLS-1$
VPGEdge<A,T,R> otherEntry = findEdgeWithNewSink(entry);
if (otherEntry != null)
{
//that.edges.remove(otherEntry);
diff.add(new EdgeSinkChanged(entry, otherEntry));
}
else
{
// if (that.filesWithNoEdges.contains(entry.getSource().getFilename()))
// diff.recordFileWithNoEdges(entry.getSource().getFilename());
// else if (that.filesWithNoEdges.contains(entry.getSink().getFilename()))
// diff.recordFileWithNoEdges(entry.getSink().getFilename());
// else
diff.add(new EdgeDeleted(entry));
}
}
catch (UnexpectedFinalEdge exception)
{
VPGEdge<A,T,R> edge = exception.getEdge();
System.err.println("Unexpected final edge " + edge); //$NON-NLS-1$
diff.add(new EdgeAdded(edge));
}
}
}
private VPGEdge<A,T,R> finalEdge(){ return getEdge(finalEdge); }
private VPGEdge<A,T,R> initialEdge() { return getEdge(initialEdge); }
private VPGEdge<A,T,R> getEdge(VPGEdge<A,T,R> edge)
{
if (edge == null) return null;
if (edge.getType() < targetType) throw new IllegalStateException("INTERNAL ERROR: Type " + targetType + " processing terminated prematurely"); //$NON-NLS-1$ //$NON-NLS-2$
if (edge.getType() != targetType) return null;
if (!edge.getClassification().equals(targetClassification)) return null;
return edge;
}
@Override void handleIgnore()
{
if (finalEdge() != null) finalEdge = finalIterator.hasNext() ? finalIterator.next() : null;
if (initialEdge() != null) initialEdge = initialIterator.hasNext() ? initialIterator.next() : null;
}
@Override void handlePreserveAll()
{
VPGEdge<A,T,R> finalEdge = finalEdge();
VPGEdge<A,T,R> initialEdge = initialEdge();
if (finalEdge != null && initialEdge == null)
{
this.finalEdge = finalIterator.hasNext() ? finalIterator.next() : null;
throw new UnexpectedFinalEdge(finalEdge);
}
else if (finalEdge == null && initialEdge != null)
{
this.initialEdge = initialIterator.hasNext() ? initialIterator.next() : null;
throw new UnexpectedInitialEdge(initialEdge);
}
else if (finalEdge != null && initialEdge != null)
{
int comparison = finalEdge.compareTo(initialEdge);
if (comparison < 0)
{
this.finalEdge = finalIterator.hasNext() ? finalIterator.next() : null;
throw new UnexpectedFinalEdge(finalEdge);
}
else if (comparison == 0)
{
this.initialEdge = initialIterator.hasNext() ? initialIterator.next() : null;
this.finalEdge = finalIterator.hasNext() ? finalIterator.next() : null;
}
else // (comparison > 0)
{
this.initialEdge = initialIterator.hasNext() ? initialIterator.next() : null;
throw new UnexpectedInitialEdge(finalEdge);
}
}
}
@Override void handlePreserveSubset()
{
VPGEdge<A,T,R> finalEdge = finalEdge();
VPGEdge<A,T,R> initialEdge = initialEdge();
if (finalEdge != null && initialEdge == null)
{
this.finalEdge = finalIterator.hasNext() ? finalIterator.next() : null;
throw new UnexpectedFinalEdge(finalEdge);
}
else if (finalEdge != null && initialEdge != null)
{
int comparison = finalEdge.compareTo(initialEdge);
if (comparison < 0)
{
this.finalEdge = finalIterator.hasNext() ? finalIterator.next() : null;
throw new UnexpectedFinalEdge(finalEdge);
}
else if (comparison == 0)
{
this.initialEdge = initialIterator.hasNext() ? initialIterator.next() : null;
this.finalEdge = finalIterator.hasNext() ? finalIterator.next() : null;
}
else // (comparison > 0)
{
this.initialEdge = initialIterator.hasNext() ? initialIterator.next() : null;
}
}
}
@Override void handlePreserveSuperset()
{
VPGEdge<A,T,R> finalEdge = finalEdge();
VPGEdge<A,T,R> initialEdge = initialEdge();
if (finalEdge == null && initialEdge != null)
{
this.initialEdge = initialIterator.hasNext() ? initialIterator.next() : null;
throw new UnexpectedInitialEdge(initialEdge);
}
else if (finalEdge != null && initialEdge != null)
{
int comparison = finalEdge.compareTo(initialEdge);
if (comparison < 0)
{
this.finalEdge = finalIterator.hasNext() ? finalIterator.next() : null;
throw new UnexpectedFinalEdge(finalEdge);
}
else if (comparison == 0)
{
this.initialEdge = initialIterator.hasNext() ? initialIterator.next() : null;
this.finalEdge = finalIterator.hasNext() ? finalIterator.next() : null;
}
else // (comparison > 0)
{
this.initialEdge = initialIterator.hasNext() ? initialIterator.next() : null;
}
}
}
public boolean hasEdgesRemaining()
{
return initialIterator.hasNext() || finalIterator.hasNext();
}
public void ensureNoEdgesRemaining(int type)
{
if (initialEdge != null
&& initialEdge.getType() == type)
throw new IllegalStateException("INTERNAL ERROR: Type " + type + " processing incomplete - initial edge "+ initialEdge); //$NON-NLS-1$//$NON-NLS-2$
if (finalEdge != null
&& finalEdge.getType() == type)
throw new IllegalStateException("INTERNAL ERROR: Type " + type + " processing incomplete - final edge "+ finalEdge); //$NON-NLS-1$//$NON-NLS-2$
}
private VPGEdge<A,T,R> findEdgeWithNewSink(VPGEdge<A,T,R> initialEdge)
{
for (VPGEdge<A,T,R> finalEdge : finalEdges)
{
if (finalEdge.getSource() != null
&& finalEdge.getSource().equals(initialEdge.getSource())
&& finalEdge.getType() == initialEdge.getType())
{
return finalEdge;
}
}
return null;
}
/** @return the number of edges remaining to be processed */
@SuppressWarnings("rawtypes")
public int countEdgesRemaining()
{
if (initialEdges instanceof List
&& initialIterator instanceof ListIterator
&& finalEdges instanceof List
&& initialIterator instanceof ListIterator)
{
return (((List)initialEdges).size() - ((ListIterator)initialIterator).nextIndex())
+ (((List)finalEdges).size() - ((ListIterator)finalIterator).nextIndex());
}
else return 0;
}
}