package org.overture.interpreter.utilities.pattern;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map.Entry;
import java.util.Vector;
import org.overture.ast.analysis.AnalysisException;
import org.overture.ast.analysis.QuestionAnswerAdaptor;
import org.overture.ast.node.INode;
import org.overture.ast.patterns.ABooleanPattern;
import org.overture.ast.patterns.ACharacterPattern;
import org.overture.ast.patterns.AConcatenationPattern;
import org.overture.ast.patterns.AExpressionPattern;
import org.overture.ast.patterns.AIdentifierPattern;
import org.overture.ast.patterns.AIgnorePattern;
import org.overture.ast.patterns.AIntegerPattern;
import org.overture.ast.patterns.AMapPattern;
import org.overture.ast.patterns.AMapUnionPattern;
import org.overture.ast.patterns.AMapletPatternMaplet;
import org.overture.ast.patterns.ANamePatternPair;
import org.overture.ast.patterns.ANilPattern;
import org.overture.ast.patterns.AObjectPattern;
import org.overture.ast.patterns.AQuotePattern;
import org.overture.ast.patterns.ARealPattern;
import org.overture.ast.patterns.ARecordPattern;
import org.overture.ast.patterns.ASeqPattern;
import org.overture.ast.patterns.ASetPattern;
import org.overture.ast.patterns.AStringPattern;
import org.overture.ast.patterns.ATuplePattern;
import org.overture.ast.patterns.AUnionPattern;
import org.overture.ast.patterns.PPattern;
import org.overture.interpreter.assistant.IInterpreterAssistantFactory;
import org.overture.interpreter.assistant.pattern.PPatternAssistantInterpreter;
import org.overture.interpreter.runtime.Context;
import org.overture.interpreter.runtime.PatternMatchException;
import org.overture.interpreter.runtime.ValueException;
import org.overture.interpreter.runtime.VdmRuntime;
import org.overture.interpreter.runtime.VdmRuntimeError;
import org.overture.interpreter.traces.Permutor;
import org.overture.interpreter.values.FieldMap;
import org.overture.interpreter.values.FieldValue;
import org.overture.interpreter.values.MapValue;
import org.overture.interpreter.values.NameValuePair;
import org.overture.interpreter.values.NameValuePairList;
import org.overture.interpreter.values.NameValuePairMap;
import org.overture.interpreter.values.NilValue;
import org.overture.interpreter.values.ObjectValue;
import org.overture.interpreter.values.RecordValue;
import org.overture.interpreter.values.SeqValue;
import org.overture.interpreter.values.SetValue;
import org.overture.interpreter.values.Value;
import org.overture.interpreter.values.ValueList;
import org.overture.interpreter.values.ValueMap;
import org.overture.interpreter.values.ValueSet;
public class AllNamedValuesLocator
extends
QuestionAnswerAdaptor<AllNamedValuesLocator.Newquestion, List<NameValuePairList>>
{
public static class Newquestion
{
Value expval;
Context ctxt;
public Newquestion(Value expval, Context ctxt)
{
this.expval = expval;
this.ctxt = ctxt;
}
}
protected IInterpreterAssistantFactory af;
public AllNamedValuesLocator(IInterpreterAssistantFactory af)
{
this.af = af;
}
@Override
public List<NameValuePairList> caseABooleanPattern(ABooleanPattern pattern,
Newquestion question) throws AnalysisException
{
List<NameValuePairList> result = new Vector<NameValuePairList>();
try
{
if (question.expval.boolValue(question.ctxt) != pattern.getValue().getValue())
{
VdmRuntimeError.patternFail(4106, "Boolean pattern match failed", pattern.getLocation());
}
} catch (ValueException e)
{
VdmRuntimeError.patternFail(e, pattern.getLocation());
}
result.add(new NameValuePairList());
return result;
}
@Override
public List<NameValuePairList> caseACharacterPattern(
ACharacterPattern pattern, Newquestion question)
throws AnalysisException
{
List<NameValuePairList> result = new Vector<NameValuePairList>();
try
{
if (question.expval.charValue(question.ctxt) != pattern.getValue().getValue())
{
VdmRuntimeError.patternFail(4107, "Character pattern match failed", pattern.getLocation());
}
} catch (ValueException e)
{
VdmRuntimeError.patternFail(e, pattern.getLocation());
}
result.add(new NameValuePairList());
return result;
}
@Override
public List<NameValuePairList> caseAConcatenationPattern(
AConcatenationPattern pattern, Newquestion question)
throws AnalysisException
{
ValueList values = null;
try
{
values = question.expval.seqValue(question.ctxt);
} catch (ValueException e)
{
VdmRuntimeError.patternFail(e, pattern.getLocation());
}
int llen = af.createPPatternAssistant().getLength(pattern.getLeft());
int rlen = af.createPPatternAssistant().getLength(pattern.getRight());
int size = values.size();
if (llen == PPatternAssistantInterpreter.ANY && rlen > size
|| rlen == PPatternAssistantInterpreter.ANY && llen > size
|| rlen != PPatternAssistantInterpreter.ANY
&& llen != PPatternAssistantInterpreter.ANY
&& size != llen + rlen)
{
VdmRuntimeError.patternFail(4108, "Sequence concatenation pattern does not match expression", pattern.getLocation());
}
// If the left and right sizes are ANY (ie. flexible) then we have to
// generate a set of splits of the values, and offer these to sub-matches
// to see whether they fit. Otherwise, there is just one split at this level.
List<Integer> leftSizes = new Vector<Integer>();
if (llen == PPatternAssistantInterpreter.ANY)
{
if (rlen == PPatternAssistantInterpreter.ANY)
{
if (size == 0)
{
// Can't match a ^ b with []
} else if (size % 2 == 1)
{
// Odd => add the middle, then those either side
int half = size / 2 + 1;
if (half > 0)
{
leftSizes.add(half);
}
for (int delta = 1; half - delta > 0; delta++)
{
leftSizes.add(half + delta);
leftSizes.add(half - delta);
}
leftSizes.add(0);
} else
{
// Even => add those either side of the middle
int half = size / 2;
if (half > 0)
{
leftSizes.add(half);
}
for (int delta = 1; half - delta > 0; delta++)
{
leftSizes.add(half + delta);
leftSizes.add(half - delta);
}
leftSizes.add(size);
leftSizes.add(0);
}
} else
{
leftSizes.add(size - rlen);
}
} else
{
leftSizes.add(llen);
}
// Now loop through the various splits and attempt to match the l/r
// sub-patterns to the split sequence value.
List<NameValuePairList> finalResults = new Vector<NameValuePairList>();
for (Integer lsize : leftSizes)
{
Iterator<Value> iter = values.iterator();
ValueList head = new ValueList();
for (int i = 0; i < lsize; i++)
{
head.add(iter.next());
}
ValueList tail = new ValueList();
while (iter.hasNext()) // Everything else in second
{
tail.add(iter.next());
}
List<List<NameValuePairList>> nvplists = new Vector<List<NameValuePairList>>();
int psize = 2;
int[] counts = new int[psize];
try
{
List<NameValuePairList> lnvps = af.createPPatternAssistant().getAllNamedValues(pattern.getLeft(), new SeqValue(head), question.ctxt);
nvplists.add(lnvps);
counts[0] = lnvps.size();
List<NameValuePairList> rnvps = af.createPPatternAssistant().getAllNamedValues(pattern.getRight(), new SeqValue(tail), question.ctxt);
nvplists.add(rnvps);
counts[1] = rnvps.size();
} catch (PatternMatchException e)
{
continue;
}
Permutor permutor = new Permutor(counts);
while (permutor.hasNext())
{
try
{
NameValuePairMap results = new NameValuePairMap();
int[] selection = permutor.next();
for (int p = 0; p < psize; p++)
{
for (NameValuePair nvp : nvplists.get(p).get(selection[p]))
{
Value v = results.get(nvp.name);
if (v == null)
{
results.put(nvp);
} else
// Names match, so values must also
{
if (!v.equals(nvp.value))
{
VdmRuntimeError.patternFail(4109, "Values do not match concatenation pattern", pattern.getLocation());
}
}
}
}
finalResults.add(results.asList()); // Consistent set of nvps
} catch (PatternMatchException pme)
{
// try next perm
}
}
}
if (finalResults.isEmpty())
{
VdmRuntimeError.patternFail(4109, "Values do not match concatenation pattern", pattern.getLocation());
}
return finalResults;
}
@Override
public List<NameValuePairList> caseAExpressionPattern(
AExpressionPattern pattern, Newquestion question)
throws AnalysisException
{
List<NameValuePairList> result = new Vector<NameValuePairList>();
try
{
if (!question.expval.equals(pattern.getExp().apply(VdmRuntime.getExpressionEvaluator(), question.ctxt)))
{
VdmRuntimeError.patternFail(4110, "Expression pattern match failed", pattern.getLocation());
}
} catch (AnalysisException e)
{
if (e instanceof PatternMatchException)
{
throw (PatternMatchException) e;
}
e.printStackTrace();
}
result.add(new NameValuePairList());
return result; // NB no values for a match, as there's no definition
}
@Override
public List<NameValuePairList> caseAIdentifierPattern(
AIdentifierPattern pattern, Newquestion question)
throws AnalysisException
{
List<NameValuePairList> result = new Vector<NameValuePairList>();
NameValuePairList list = new NameValuePairList();
list.add(new NameValuePair(pattern.getName(), question.expval));
result.add(list);
return result;
}
@Override
public List<NameValuePairList> caseAIgnorePattern(AIgnorePattern pattern,
Newquestion question) throws AnalysisException
{
List<NameValuePairList> result = new Vector<NameValuePairList>();
result.add(new NameValuePairList());
return result;
}
@Override
public List<NameValuePairList> caseAIntegerPattern(AIntegerPattern pattern,
Newquestion question) throws AnalysisException
{
List<NameValuePairList> result = new Vector<NameValuePairList>();
try
{
if (question.expval.intValue(question.ctxt) != pattern.getValue().getValue())
{
VdmRuntimeError.patternFail(4111, "Integer pattern match failed", pattern.getLocation());
}
} catch (ValueException e)
{
VdmRuntimeError.patternFail(e, pattern.getLocation());
}
result.add(new NameValuePairList());
return result;
}
@Override
public List<NameValuePairList> caseAMapPattern(AMapPattern pattern,
Newquestion question) throws AnalysisException
{
ValueMap values = null;
try
{
values = question.expval.mapValue(question.ctxt);
} catch (ValueException e)
{
VdmRuntimeError.patternFail(e, pattern.getLocation());
}
if (values.size() != pattern.getMaplets().size())
{
VdmRuntimeError.patternFail(4152, "Wrong number of elements for map pattern", pattern.getLocation());
}
// Since the member patterns may indicate specific map members, we
// have to permute through the various map orderings to see
// whether there are any which match both sides. If the members
// are not constrained however, the initial ordering will be
// fine.
List<ValueMap> allMaps;
if (pattern.apply(af.getConstrainedPatternChecker()))
{
allMaps = values.permutedMaps();
} else
{
allMaps = new Vector<ValueMap>();
allMaps.add(values);
}
List<NameValuePairList> finalResults = new Vector<NameValuePairList>();
int psize = pattern.getMaplets().size();
if (pattern.getMaplets().isEmpty())
{
finalResults.add(new NameValuePairList());
return finalResults;
}
for (ValueMap mapPerm : allMaps)
{
Iterator<Entry<Value, Value>> iter = mapPerm.entrySet().iterator();
List<List<NameValuePairList>> nvplists = new Vector<List<NameValuePairList>>();
int[] counts = new int[psize];
int i = 0;
try
{
for (AMapletPatternMaplet p : pattern.getMaplets())
{
List<NameValuePairList> pnvps = af.createAMapPatternMapletAssistant().getAllNamedValues(p, iter.next(), question.ctxt);
nvplists.add(pnvps);
counts[i++] = pnvps.size();
}
} catch (Exception e)
{
continue;
}
Permutor permutor = new Permutor(counts);
while (permutor.hasNext())
{
try
{
NameValuePairMap results = new NameValuePairMap();
int[] selection = permutor.next();
for (int p = 0; p < psize; p++)
{
for (NameValuePair nvp : nvplists.get(p).get(selection[p]))
{
Value v = results.get(nvp.name);
if (v == null)
{
results.put(nvp);
} else
// Names match, so values must also
{
if (!v.equals(nvp.value))
{
VdmRuntimeError.patternFail(4153, "Values do not match map pattern", pattern.getLocation());
}
}
}
}
finalResults.add(results.asList());
} catch (PatternMatchException pme)
{
// Try next perm then...
}
}
}
if (finalResults.isEmpty())
{
VdmRuntimeError.patternFail(4154, "Cannot match map pattern", pattern.getLocation());
}
return finalResults;
}
@Override
public List<NameValuePairList> caseAMapUnionPattern(
AMapUnionPattern pattern, Newquestion question)
throws AnalysisException
{
ValueMap values = null;
try
{
values = question.expval.mapValue(question.ctxt);
} catch (ValueException e)
{
VdmRuntimeError.patternFail(e, pattern.getLocation());
}
int llen = af.createPPatternAssistant().getLength(pattern.getLeft());
int rlen = af.createPPatternAssistant().getLength(pattern.getRight());
int size = values.size();
if (llen == PPatternAssistantInterpreter.ANY && rlen > size
|| rlen == PPatternAssistantInterpreter.ANY && llen > size
|| rlen != PPatternAssistantInterpreter.ANY
&& llen != PPatternAssistantInterpreter.ANY
&& size != llen + rlen)
{
VdmRuntimeError.patternFail(4155, "Map union pattern does not match expression", pattern.getLocation());
}
// If the left and right sizes are zero (ie. flexible) then we have to
// generate a set of splits of the values, and offer these to sub-matches
// to see whether they fit. Otherwise, there is just one split at this level.
List<Integer> leftSizes = new Vector<Integer>();
if (llen == PPatternAssistantInterpreter.ANY)
{
if (rlen == PPatternAssistantInterpreter.ANY)
{
if (size == 0)
{
// Can't match a munion b with {|->}
} else if (size % 2 == 1)
{
// Odd => add the middle, then those either side
int half = size / 2 + 1;
if (half > 0)
{
leftSizes.add(half);
}
for (int delta = 1; half - delta > 0; delta++)
{
leftSizes.add(half + delta);
leftSizes.add(half - delta);
}
leftSizes.add(0);
} else
{
// Even => add those either side of the middle
int half = size / 2;
if (half > 0)
{
leftSizes.add(half);
}
for (int delta = 1; half - delta > 0; delta++)
{
leftSizes.add(half + delta);
leftSizes.add(half - delta);
}
leftSizes.add(size);
leftSizes.add(0);
}
} else
{
leftSizes.add(size - rlen);
}
} else
{
leftSizes.add(llen);
}
// Since the left and right may have specific element members, we
// have to permute through the various map orderings to see
// whether there are any which match both sides. If the patterns
// are not constrained however, the initial ordering will be
// fine.
List<ValueMap> allMaps;
if (pattern.apply(af.getConstrainedPatternChecker()))
{
allMaps = values.permutedMaps();
} else
{
allMaps = new Vector<ValueMap>();
allMaps.add(values);
}
// Now loop through the various splits and attempt to match the l/r
// sub-patterns to the split map value.
List<NameValuePairList> finalResults = new Vector<NameValuePairList>();
for (Integer lsize : leftSizes)
{
for (ValueMap setPerm : allMaps)
{
Iterator<Entry<Value, Value>> iter = setPerm.entrySet().iterator();
ValueMap first = new ValueMap();
for (int i = 0; i < lsize; i++)
{
Entry<Value, Value> e = iter.next();
first.put(e.getKey(), e.getValue());
}
ValueMap second = new ValueMap();
while (iter.hasNext()) // Everything else in second
{
Entry<Value, Value> e = iter.next();
second.put(e.getKey(), e.getValue());
}
List<List<NameValuePairList>> nvplists = new Vector<List<NameValuePairList>>();
int psize = 2;
int[] counts = new int[psize];
try
{
List<NameValuePairList> lnvps = af.createPPatternAssistant().getAllNamedValues(pattern.getLeft(), new MapValue(first), question.ctxt);
nvplists.add(lnvps);
counts[0] = lnvps.size();
List<NameValuePairList> rnvps = af.createPPatternAssistant().getAllNamedValues(pattern.getRight(), new MapValue(second), question.ctxt);
nvplists.add(rnvps);
counts[1] = rnvps.size();
} catch (Exception e)
{
continue;
}
Permutor permutor = new Permutor(counts);
while (permutor.hasNext())
{
try
{
NameValuePairMap results = new NameValuePairMap();
int[] selection = permutor.next();
for (int p = 0; p < psize; p++)
{
for (NameValuePair nvp : nvplists.get(p).get(selection[p]))
{
Value v = results.get(nvp.name);
if (v == null)
{
results.put(nvp);
} else
// Names match, so values must also
{
if (!v.equals(nvp.value))
{
VdmRuntimeError.patternFail(4126, "Values do not match union pattern", pattern.getLocation());
}
}
}
}
finalResults.add(results.asList());
} catch (PatternMatchException pme)
{
// Try next perm then...
}
}
}
}
if (finalResults.isEmpty())
{
VdmRuntimeError.patternFail(4156, "Cannot match map pattern", pattern.getLocation());
}
return finalResults;
}
@Override
public List<NameValuePairList> caseANilPattern(ANilPattern pattern,
Newquestion question) throws AnalysisException
{
// return ANilPatternAssistantInterpreter.getAllNamedValues(pattern, question.expval, question.ctxt);
List<NameValuePairList> result = new Vector<NameValuePairList>();
if (!(question.expval.deref() instanceof NilValue))
{
VdmRuntimeError.patternFail(4106, "Nil pattern match failed", pattern.getLocation());
}
result.add(new NameValuePairList());
return result;
}
@Override
public List<NameValuePairList> caseAQuotePattern(AQuotePattern pattern,
Newquestion question) throws AnalysisException
{
List<NameValuePairList> result = new Vector<NameValuePairList>();
try
{
if (!question.expval.quoteValue(question.ctxt).equals(pattern.getValue().getValue()))
{
VdmRuntimeError.patternFail(4112, "Quote pattern match failed", pattern.getLocation());
}
} catch (ValueException e)
{
VdmRuntimeError.patternFail(e, pattern.getLocation());
}
result.add(new NameValuePairList());
return result;
}
@Override
public List<NameValuePairList> caseARealPattern(ARealPattern pattern,
Newquestion question) throws AnalysisException
{
List<NameValuePairList> result = new Vector<NameValuePairList>();
try
{
if (question.expval.realValue(question.ctxt) != pattern.getValue().getValue())
{
VdmRuntimeError.patternFail(4113, "Real pattern match failed", pattern.getLocation());
}
} catch (ValueException e)
{
VdmRuntimeError.patternFail(e, pattern.getLocation());
}
result.add(new NameValuePairList());
return result;
}
@Override
public List<NameValuePairList> caseARecordPattern(ARecordPattern pattern,
Newquestion question) throws AnalysisException
{
FieldMap fields = null;
RecordValue exprec = null;
try
{
exprec = question.expval.recordValue(question.ctxt);
fields = exprec.fieldmap;
} catch (ValueException e)
{
VdmRuntimeError.patternFail(e, pattern.getLocation());
}
// if (!type.equals(exprec.type))
if (!question.ctxt.assistantFactory.getTypeComparator().compatible(pattern.getType(), exprec.type))
{
VdmRuntimeError.patternFail(4114, "Record type does not match pattern", pattern.getLocation());
}
if (fields.size() != pattern.getPlist().size())
{
VdmRuntimeError.patternFail(4115, "Record expression does not match pattern", pattern.getLocation());
}
Iterator<FieldValue> iter = fields.iterator();
List<List<NameValuePairList>> nvplists = new Vector<List<NameValuePairList>>();
int psize = pattern.getPlist().size();
int[] counts = new int[psize];
int i = 0;
for (PPattern p : pattern.getPlist())
{
List<NameValuePairList> pnvps = af.createPPatternAssistant().getAllNamedValues(p, iter.next().value, question.ctxt);
nvplists.add(pnvps);
counts[i++] = pnvps.size();
}
Permutor permutor = new Permutor(counts);
List<NameValuePairList> finalResults = new Vector<NameValuePairList>();
if (pattern.getPlist().isEmpty())
{
finalResults.add(new NameValuePairList());
return finalResults;
}
while (permutor.hasNext())
{
try
{
NameValuePairMap results = new NameValuePairMap();
int[] selection = permutor.next();
for (int p = 0; p < psize; p++)
{
for (NameValuePair nvp : nvplists.get(p).get(selection[p]))
{
Value v = results.get(nvp.name);
if (v == null)
{
results.put(nvp);
} else
// Names match, so values must also
{
if (!v.equals(nvp.value))
{
VdmRuntimeError.patternFail(4116, "Values do not match record pattern", pattern.getLocation());
}
}
}
}
finalResults.add(results.asList()); // Consistent set of nvps
} catch (PatternMatchException pme)
{
// try next perm
}
}
if (finalResults.isEmpty())
{
VdmRuntimeError.patternFail(4116, "Values do not match record pattern", pattern.getLocation());
}
return finalResults;
}
@Override
public List<NameValuePairList> caseASeqPattern(ASeqPattern pattern,
Newquestion question) throws AnalysisException
{
ValueList values = null;
try
{
values = question.expval.seqValue(question.ctxt);
} catch (ValueException e)
{
VdmRuntimeError.patternFail(e, pattern.getLocation());
}
if (values.size() != pattern.getPlist().size())
{
VdmRuntimeError.patternFail(4117, "Wrong number of elements for sequence pattern", pattern.getLocation());
}
ListIterator<Value> iter = values.listIterator();
List<List<NameValuePairList>> nvplists = new Vector<List<NameValuePairList>>();
int psize = pattern.getPlist().size();
int[] counts = new int[psize];
int i = 0;
for (PPattern p : pattern.getPlist())
{
List<NameValuePairList> pnvps = af.createPPatternAssistant().getAllNamedValues(p, iter.next(), question.ctxt);
nvplists.add(pnvps);
counts[i++] = pnvps.size();
}
Permutor permutor = new Permutor(counts);
List<NameValuePairList> finalResults = new Vector<NameValuePairList>();
if (pattern.getPlist().isEmpty())
{
finalResults.add(new NameValuePairList());
return finalResults;
}
while (permutor.hasNext())
{
try
{
NameValuePairMap results = new NameValuePairMap();
int[] selection = permutor.next();
for (int p = 0; p < psize; p++)
{
for (NameValuePair nvp : nvplists.get(p).get(selection[p]))
{
Value v = results.get(nvp.name);
if (v == null)
{
results.put(nvp);
} else
// Names match, so values must also
{
if (!v.equals(nvp.value))
{
VdmRuntimeError.patternFail(4118, "Values do not match sequence pattern", pattern.getLocation());
}
}
}
}
finalResults.add(results.asList()); // Consistent set of nvps
} catch (PatternMatchException pme)
{
// try next perm
}
}
if (finalResults.isEmpty())
{
VdmRuntimeError.patternFail(4118, "Values do not match sequence pattern", pattern.getLocation());
}
return finalResults;
}
@Override
public List<NameValuePairList> caseASetPattern(ASetPattern pattern,
Newquestion question) throws AnalysisException
{
// return ASetPatternAssistantInterpreter.getAllNamedValues(pattern, question.expval, question.ctxt);
ValueSet values = null;
try
{
values = question.expval.setValue(question.ctxt);
} catch (ValueException e)
{
VdmRuntimeError.patternFail(e, pattern.getLocation());
}
if (values.size() != pattern.getPlist().size())
{
VdmRuntimeError.patternFail(4119, "Wrong number of elements for set pattern", pattern.getLocation());
}
// Since the member patterns may indicate specific set members, we
// have to permute through the various set orderings to see
// whether there are any which match both sides. If the members
// are not constrained however, the initial ordering will be
// fine.
List<ValueSet> allSets;
if (pattern.apply(af.getConstrainedPatternChecker()))
{
allSets = values.permutedSets();
} else
{
allSets = new Vector<ValueSet>();
allSets.add(values);
}
List<NameValuePairList> finalResults = new Vector<NameValuePairList>();
int psize = pattern.getPlist().size();
if (pattern.getPlist().isEmpty())
{
finalResults.add(new NameValuePairList());
return finalResults;
}
for (ValueSet setPerm : allSets)
{
Iterator<Value> iter = setPerm.iterator();
List<List<NameValuePairList>> nvplists = new Vector<List<NameValuePairList>>();
int[] counts = new int[psize];
int i = 0;
try
{
for (PPattern p : pattern.getPlist())
{
List<NameValuePairList> pnvps = af.createPPatternAssistant().getAllNamedValues(p, iter.next(), question.ctxt);
nvplists.add(pnvps);
counts[i++] = pnvps.size();
}
} catch (Exception e)
{
continue;
}
Permutor permutor = new Permutor(counts);
while (permutor.hasNext())
{
try
{
NameValuePairMap results = new NameValuePairMap();
int[] selection = permutor.next();
for (int p = 0; p < psize; p++)
{
for (NameValuePair nvp : nvplists.get(p).get(selection[p]))
{
Value v = results.get(nvp.name);
if (v == null)
{
results.put(nvp);
} else
// Names match, so values must also
{
if (!v.equals(nvp.value))
{
VdmRuntimeError.patternFail(4120, "Values do not match set pattern", pattern.getLocation());
}
}
}
}
finalResults.add(results.asList());
} catch (PatternMatchException pme)
{
// Try next perm then...
}
}
}
if (finalResults.isEmpty())
{
VdmRuntimeError.patternFail(4121, "Cannot match set pattern", pattern.getLocation());
}
return finalResults;
}
@Override
public List<NameValuePairList> caseAStringPattern(AStringPattern pattern,
Newquestion question) throws AnalysisException
{
List<NameValuePairList> result = new Vector<NameValuePairList>();
try
{
if (!question.expval.stringValue(question.ctxt).equals(pattern.getValue().getValue()))
{
VdmRuntimeError.patternFail(4122, "String pattern match failed", pattern.getLocation());
}
} catch (ValueException e)
{
VdmRuntimeError.patternFail(e, pattern.getLocation());
}
result.add(new NameValuePairList());
return result;
}
@Override
public List<NameValuePairList> caseATuplePattern(ATuplePattern pattern,
Newquestion question) throws AnalysisException
{
ValueList values = null;
try
{
values = question.expval.tupleValue(question.ctxt);
} catch (ValueException e)
{
VdmRuntimeError.patternFail(e, pattern.getLocation());
}
if (values.size() != pattern.getPlist().size())
{
VdmRuntimeError.patternFail(4123, "Tuple expression does not match pattern", pattern.getLocation());
}
ListIterator<Value> iter = values.listIterator();
List<List<NameValuePairList>> nvplists = new Vector<List<NameValuePairList>>();
int psize = pattern.getPlist().size();
int[] counts = new int[psize];
int i = 0;
for (PPattern p : pattern.getPlist())
{
List<NameValuePairList> pnvps = af.createPPatternAssistant().getAllNamedValues(p, iter.next(), question.ctxt);
nvplists.add(pnvps);
counts[i++] = pnvps.size();
}
Permutor permutor = new Permutor(counts);
List<NameValuePairList> finalResults = new Vector<NameValuePairList>();
while (permutor.hasNext())
{
try
{
NameValuePairMap results = new NameValuePairMap();
int[] selection = permutor.next();
for (int p = 0; p < psize; p++)
{
for (NameValuePair nvp : nvplists.get(p).get(selection[p]))
{
Value v = results.get(nvp.name);
if (v == null)
{
results.put(nvp);
} else
// Names match, so values must also
{
if (!v.equals(nvp.value))
{
VdmRuntimeError.patternFail(4124, "Values do not match tuple pattern", pattern.getLocation());
}
}
}
}
finalResults.add(results.asList()); // Consistent set of nvps
} catch (PatternMatchException pme)
{
// try next perm
}
}
if (finalResults.isEmpty())
{
VdmRuntimeError.patternFail(4124, "Values do not match tuple pattern", pattern.getLocation());
}
return finalResults;
}
@Override
public List<NameValuePairList> caseAUnionPattern(AUnionPattern pattern,
Newquestion question) throws AnalysisException
{
ValueSet values = null;
try
{
values = question.expval.setValue(question.ctxt);
} catch (ValueException e)
{
VdmRuntimeError.patternFail(e, pattern.getLocation());
}
int llen = af.createPPatternAssistant().getLength(pattern.getLeft());
int rlen = af.createPPatternAssistant().getLength(pattern.getRight());
int size = values.size();
if (llen == PPatternAssistantInterpreter.ANY && rlen > size
|| rlen == PPatternAssistantInterpreter.ANY && llen > size
|| rlen != PPatternAssistantInterpreter.ANY
&& llen != PPatternAssistantInterpreter.ANY
&& size != llen + rlen)
{
VdmRuntimeError.patternFail(4125, "Set union pattern does not match expression", pattern.getLocation());
}
// If the left and right sizes are zero (ie. flexible) then we have to
// generate a set of splits of the values, and offer these to sub-matches
// to see whether they fit. Otherwise, there is just one split at this level.
List<Integer> leftSizes = new Vector<Integer>();
if (llen == PPatternAssistantInterpreter.ANY)
{
if (rlen == PPatternAssistantInterpreter.ANY)
{
if (size == 0)
{
// Can't match a union b with {}
} else if (size % 2 == 1)
{
// Odd => add the middle, then those either side
int half = size / 2 + 1;
if (half > 0)
{
leftSizes.add(half);
}
for (int delta = 1; half - delta > 0; delta++)
{
leftSizes.add(half + delta);
leftSizes.add(half - delta);
}
leftSizes.add(0);
} else
{
// Even => add those either side of the middle
int half = size / 2;
if (half > 0)
{
leftSizes.add(half);
}
for (int delta = 1; half - delta > 0; delta++)
{
leftSizes.add(half + delta);
leftSizes.add(half - delta);
}
leftSizes.add(size);
leftSizes.add(0);
}
} else
{
leftSizes.add(size - rlen);
}
} else
{
leftSizes.add(llen);
}
// Since the left and right may have specific set members, we
// have to permute through the various set orderings to see
// whether there are any which match both sides. If the patterns
// are not constrained however, the initial ordering will be
// fine.
List<ValueSet> allSets;
if (pattern.apply(af.getConstrainedPatternChecker()))
{
allSets = values.permutedSets();
} else
{
allSets = new Vector<ValueSet>();
allSets.add(values);
}
// Now loop through the various splits and attempt to match the l/r
// sub-patterns to the split set value.
List<NameValuePairList> finalResults = new Vector<NameValuePairList>();
for (Integer lsize : leftSizes)
{
for (ValueSet setPerm : allSets)
{
Iterator<Value> iter = setPerm.iterator();
ValueSet first = new ValueSet();
for (int i = 0; i < lsize; i++)
{
first.add(iter.next());
}
ValueSet second = new ValueSet();
while (iter.hasNext()) // Everything else in second
{
second.add(iter.next());
}
List<List<NameValuePairList>> nvplists = new Vector<List<NameValuePairList>>();
int psize = 2;
int[] counts = new int[psize];
try
{
List<NameValuePairList> lnvps = af.createPPatternAssistant().getAllNamedValues(pattern.getLeft(), new SetValue(first), question.ctxt);
nvplists.add(lnvps);
counts[0] = lnvps.size();
List<NameValuePairList> rnvps = af.createPPatternAssistant().getAllNamedValues(pattern.getRight(), new SetValue(second), question.ctxt);
nvplists.add(rnvps);
counts[1] = rnvps.size();
} catch (Exception e)
{
continue;
}
Permutor permutor = new Permutor(counts);
while (permutor.hasNext())
{
try
{
NameValuePairMap results = new NameValuePairMap();
int[] selection = permutor.next();
for (int p = 0; p < psize; p++)
{
for (NameValuePair nvp : nvplists.get(p).get(selection[p]))
{
Value v = results.get(nvp.name);
if (v == null)
{
results.put(nvp);
} else
// Names match, so values must also
{
if (!v.equals(nvp.value))
{
VdmRuntimeError.patternFail(4126, "Values do not match union pattern", pattern.getLocation());
}
}
}
}
finalResults.add(results.asList());
} catch (PatternMatchException pme)
{
// Try next perm then...
}
}
}
}
if (finalResults.isEmpty())
{
VdmRuntimeError.patternFail(4127, "Cannot match set pattern", pattern.getLocation());
}
return finalResults;
}
@Override
public List<NameValuePairList> caseAObjectPattern(AObjectPattern pattern,
Newquestion question) throws AnalysisException
{
ObjectValue objval = null;
try
{
objval = question.expval.objectValue(question.ctxt);
}
catch (ValueException e)
{
VdmRuntimeError.patternFail(e, pattern.getLocation());
}
if (!question.ctxt.assistantFactory.getTypeComparator().isSubType(objval.getType(), pattern.getType()))
{
VdmRuntimeError.patternFail(4114, "Object type does not match pattern", pattern.getLocation());
}
List<List<NameValuePairList>> nvplists = new Vector<List<NameValuePairList>>();
int psize = pattern.getFields().size();
int[] counts = new int[psize];
int i = 0;
for (ANamePatternPair npp : pattern.getFields())
{
Value fval = objval.get(npp.getName(), false);
if (fval == null) // Field does not exist in this object
{
VdmRuntimeError.patternFail(4114, "Object type does not match pattern", pattern.getLocation());
}
List<NameValuePairList> pnvps = af.createPPatternAssistant().getAllNamedValues(npp.getPattern(), fval, question.ctxt);
nvplists.add(pnvps);
counts[i++] = pnvps.size();
}
Permutor permutor = new Permutor(counts);
List<NameValuePairList> finalResults = new Vector<NameValuePairList>();
if (pattern.getFields().isEmpty())
{
finalResults.add(new NameValuePairList());
return finalResults;
}
while (permutor.hasNext())
{
try
{
NameValuePairMap results = new NameValuePairMap();
int[] selection = permutor.next();
for (int p = 0; p < psize; p++)
{
for (NameValuePair nvp : nvplists.get(p).get(selection[p]))
{
Value v = results.get(nvp.name);
if (v == null)
{
results.put(nvp);
}
else
{
if (!v.equals(nvp.value))
{
VdmRuntimeError.patternFail(4116, "Values do not match record pattern", pattern.getLocation());
}
}
}
}
finalResults.add(results.asList()); // Consistent set of nvps
}
catch (PatternMatchException pme)
{
// try next perm
}
}
if (finalResults.isEmpty())
{
VdmRuntimeError.patternFail(4116, "Values do not match record pattern", pattern.getLocation());
}
return finalResults;
}
@Override
public List<NameValuePairList> defaultPPattern(PPattern pattern,
Newquestion question) throws AnalysisException
{
assert false : "Should not happen!";
return null;
}
@Override
public List<NameValuePairList> createNewReturnValue(INode node,
Newquestion question) throws AnalysisException
{
assert false : "Should not happen!";
return null;
}
@Override
public List<NameValuePairList> createNewReturnValue(Object node,
Newquestion question) throws AnalysisException
{
assert false : "Should not happen!";
return null;
}
}