package org.overture.interpreter.utilities.type;
import java.util.List;
import java.util.Vector;
import org.overture.ast.analysis.AnalysisException;
import org.overture.ast.analysis.QuestionAnswerAdaptor;
import org.overture.ast.assistant.pattern.PTypeList;
import org.overture.ast.factory.AstFactory;
import org.overture.ast.lex.LexNameToken;
import org.overture.ast.node.INode;
import org.overture.ast.patterns.PPattern;
import org.overture.ast.types.ABooleanBasicType;
import org.overture.ast.types.AFieldField;
import org.overture.ast.types.AInMapMapType;
import org.overture.ast.types.ANamedInvariantType;
import org.overture.ast.types.ANatOneNumericBasicType;
import org.overture.ast.types.AOptionalType;
import org.overture.ast.types.AParameterType;
import org.overture.ast.types.AProductType;
import org.overture.ast.types.AQuoteType;
import org.overture.ast.types.ARecordInvariantType;
import org.overture.ast.types.SSetType;
import org.overture.ast.types.AUnionType;
import org.overture.ast.types.PType;
import org.overture.ast.types.SBasicType;
import org.overture.ast.types.SInvariantType;
import org.overture.ast.types.SMapType;
import org.overture.ast.types.SNumericBasicType;
import org.overture.config.Settings;
import org.overture.interpreter.assistant.IInterpreterAssistantFactory;
import org.overture.interpreter.runtime.Context;
import org.overture.interpreter.runtime.ValueException;
import org.overture.interpreter.values.BooleanValue;
import org.overture.interpreter.values.InvariantValue;
import org.overture.interpreter.values.MapValue;
import org.overture.interpreter.values.NameValuePair;
import org.overture.interpreter.values.NameValuePairList;
import org.overture.interpreter.values.NilValue;
import org.overture.interpreter.values.NumericValue;
import org.overture.interpreter.values.ParameterValue;
import org.overture.interpreter.values.Quantifier;
import org.overture.interpreter.values.QuantifierList;
import org.overture.interpreter.values.QuoteValue;
import org.overture.interpreter.values.RecordValue;
import org.overture.interpreter.values.SetValue;
import org.overture.interpreter.values.TupleValue;
import org.overture.interpreter.values.Value;
import org.overture.interpreter.values.ValueList;
import org.overture.interpreter.values.ValueMap;
import org.overture.interpreter.values.ValueSet;
import org.overture.parser.config.Properties;
/**
* This class collects all the values exist in a type.
*
* @author gkanos
*/
public class AllValuesCollector extends
QuestionAnswerAdaptor<Context, ValueList>
{
protected IInterpreterAssistantFactory af;
public AllValuesCollector(IInterpreterAssistantFactory af)
{
this.af = af;
}
@Override
public ValueList caseABooleanBasicType(ABooleanBasicType type, Context ctxt)
throws AnalysisException
{
ValueList v = new ValueList();
v.add(new BooleanValue(true));
v.add(new BooleanValue(false));
return v;
}
@Override
public ValueList defaultSNumericBasicType(SNumericBasicType node,
Context question) throws AnalysisException
{
if (Properties.numeric_type_bind_generation)
{
return generateNumbers(Properties.minint, Properties.maxint, question);
}
return super.defaultSNumericBasicType(node, question);
}
@Override
public ValueList caseANatOneNumericBasicType(ANatOneNumericBasicType node,
Context question) throws AnalysisException
{
if (Properties.numeric_type_bind_generation)
{
int min = Properties.minint;
if (min < 1)
{
min = 1;
}
return generateNumbers(min, Properties.maxint, question);
}
return super.caseANatOneNumericBasicType(node, question);
}
/**
* Generator method for numeric type bindings.
*
* @param min
* the minimum number
* @param max
* the maximum number
* @param ctxt
* current context
* @return the newly generated list of values between min and max, including.
* @throws ValueException
*/
protected ValueList generateNumbers(int min, int max, Context ctxt)
throws ValueException
{
ValueList list = new ValueList();
for (int i = min; i < max + 1; i++)
{
list.add(NumericValue.valueOf(i, ctxt));
}
return list;
}
@Override
public ValueList defaultSBasicType(SBasicType type, Context ctxt)
throws AnalysisException
{
throw new ValueException(4, "Cannot get bind values for type " + type, ctxt);
}
@Override
public ValueList caseANamedInvariantType(ANamedInvariantType type,
Context ctxt) throws AnalysisException
{
ValueList raw = type.getType().apply(THIS, ctxt);
boolean checks = Settings.invchecks;
Settings.invchecks = true;
ValueList result = new ValueList();
for (Value v : raw)
{
try
{
result.add(new InvariantValue(type, v, ctxt));
} catch (ValueException e)
{
// Raw value not in type because of invariant
}
}
Settings.invchecks = checks;
return result;
}
@Override
public ValueList caseARecordInvariantType(ARecordInvariantType type,
Context ctxt) throws AnalysisException
{
List<PType> types = new Vector<PType>();
for (AFieldField f : type.getFields())
{
types.add(f.getType());
}
ValueList results = new ValueList();
for (Value v : getAllValues(types, ctxt))
{
try
{
TupleValue tuple = (TupleValue) v;
results.add(new RecordValue(type, tuple.values, ctxt));
} catch (ValueException e)
{
// Value does not match invariant, so ignore it
}
}
return results;
}
@Override
public ValueList defaultSInvariantType(SInvariantType type, Context ctxt)
throws AnalysisException
{
throw new ValueException(4, "Cannot get bind values for type " + type, ctxt);
}
@Override
public ValueList caseAInMapMapType(AInMapMapType type, Context ctxt)
throws AnalysisException
{
// TODO:Here we have a strange behavior from transforming this call to type.apply(THIS,ctxt)
ValueList maps = THIS.defaultSMapType(type, ctxt);// ctxt.assistantFactory.createSMapTypeAssistant().getAllValues(type,
// ctxt);
ValueList result = new ValueList();
for (Value map : maps)
{
MapValue vm = (MapValue) map;
if (vm.values.isInjective())
{
result.add(vm);
}
}
return result;
}
@Override
public ValueList caseAOptionalType(AOptionalType type, Context ctxt)
throws AnalysisException
{
ValueList list = type.getType().apply(THIS, ctxt);
list.add(new NilValue());
return list;
}
@Override
public ValueList caseAProductType(AProductType type, Context ctxt)
throws AnalysisException
{
return getAllValues(type.getTypes(), ctxt);
}
@Override
public ValueList defaultSMapType(SMapType type, Context ctxt)
throws AnalysisException
{
PTypeList tuple = new PTypeList();
tuple.add(type.getFrom());
tuple.add(type.getTo());
ValueList results = new ValueList();
ValueList tuples = getAllValues(tuple, ctxt);
ValueSet set = new ValueSet();
set.addAll(tuples);
List<ValueSet> psets = set.powerSet();
for (ValueSet map : psets)
{
ValueMap result = new ValueMap();
for (Value v : map)
{
TupleValue tv = (TupleValue) v;
result.put(tv.values.get(0), tv.values.get(1));
}
results.add(new MapValue(result));
}
return results;
}
@Override
public ValueList caseAQuoteType(AQuoteType type, Context ctxt)
throws AnalysisException
{
ValueList v = new ValueList();
v.add(new QuoteValue(type.getValue().getValue()));
return v;
}
@Override
public ValueList defaultSSetType(SSetType type, Context ctxt)
throws AnalysisException
{
ValueList list = type.getSetof().apply(THIS, ctxt);
ValueSet set = new ValueSet(list.size());
set.addAll(list);
List<ValueSet> psets = set.powerSet();
list.clear();
for (ValueSet v : psets)
{
list.add(new SetValue(v));
}
return list;
}
@Override
public ValueList caseAUnionType(AUnionType type, Context ctxt)
throws AnalysisException
{
ValueList v = new ValueList();
for (PType utype : type.getTypes())
{
v.addAll(utype.apply(THIS, ctxt));
}
return v;
}
@Override
public ValueList caseAParameterType(AParameterType type, Context ctxt)
throws AnalysisException
{
Value t = ctxt.lookup(type.getName());
if (t == null)
{
throw new ValueException(4008, "No such type parameter @"
+ type.getName() + " in scope", ctxt);
} else if (t instanceof ParameterValue)
{
ParameterValue tv = (ParameterValue) t;
return tv.type.apply(THIS, ctxt);
}
throw new ValueException(4009, "Type parameter/local variable name clash, @"
+ type.getName(), ctxt);
}
@Override
public ValueList createNewReturnValue(INode node, Context question)
throws AnalysisException
{
throw new ValueException(4, "Cannot get bind values for type " + node, question);
}
@Override
public ValueList createNewReturnValue(Object node, Context question)
throws AnalysisException
{
return null;
}
public ValueList getAllValues(List<PType> linkedList, Context ctxt)
throws AnalysisException
{
QuantifierList quantifiers = new QuantifierList();
int n = 0;
for (PType t : linkedList)
{
LexNameToken name = new LexNameToken("#", String.valueOf(n), t.getLocation());
PPattern p = AstFactory.newAIdentifierPattern(name);
Quantifier q = new Quantifier(p, af.createPTypeAssistant().getAllValues(t, ctxt));
quantifiers.add(q);
}
quantifiers.init(ctxt, true);
ValueList results = new ValueList();
while (quantifiers.hasNext())
{
NameValuePairList nvpl = quantifiers.next();
ValueList list = new ValueList();
for (NameValuePair nvp : nvpl)
{
list.add(nvp.value);
}
results.add(new TupleValue(list));
}
return results;
}
}