package org.overture.interpreter.eval;
import java.util.Collections;
import java.util.List;
import org.overture.ast.analysis.AnalysisException;
import org.overture.ast.expressions.AAbsoluteUnaryExp;
import org.overture.ast.expressions.ACardinalityUnaryExp;
import org.overture.ast.expressions.ADistConcatUnaryExp;
import org.overture.ast.expressions.ADistIntersectUnaryExp;
import org.overture.ast.expressions.ADistMergeUnaryExp;
import org.overture.ast.expressions.ADistUnionUnaryExp;
import org.overture.ast.expressions.AElementsUnaryExp;
import org.overture.ast.expressions.AFloorUnaryExp;
import org.overture.ast.expressions.AHeadUnaryExp;
import org.overture.ast.expressions.AIndicesUnaryExp;
import org.overture.ast.expressions.ALenUnaryExp;
import org.overture.ast.expressions.AMapDomainUnaryExp;
import org.overture.ast.expressions.AMapInverseUnaryExp;
import org.overture.ast.expressions.AMapRangeUnaryExp;
import org.overture.ast.expressions.ANotUnaryExp;
import org.overture.ast.expressions.APowerSetUnaryExp;
import org.overture.ast.expressions.AReverseUnaryExp;
import org.overture.ast.expressions.ATailUnaryExp;
import org.overture.ast.expressions.AUnaryMinusUnaryExp;
import org.overture.ast.expressions.AUnaryPlusUnaryExp;
import org.overture.interpreter.debug.BreakpointManager;
import org.overture.interpreter.runtime.Context;
import org.overture.interpreter.runtime.ContextException;
import org.overture.interpreter.runtime.ValueException;
import org.overture.interpreter.runtime.VdmRuntime;
import org.overture.interpreter.runtime.VdmRuntimeError;
import org.overture.interpreter.values.BooleanValue;
import org.overture.interpreter.values.MapValue;
import org.overture.interpreter.values.NaturalOneValue;
import org.overture.interpreter.values.NaturalValue;
import org.overture.interpreter.values.NumericValue;
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 UnaryExpressionEvaluator extends LiteralEvaluator
{
@Override
public Value caseAAbsoluteUnaryExp(AAbsoluteUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
try
{
return NumericValue.valueOf(Math.abs(node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).realValue(ctxt)), ctxt);
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
}
}
@Override
public Value caseACardinalityUnaryExp(ACardinalityUnaryExp node,
Context ctxt) throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
try
{
return new NaturalValue(node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).setValue(ctxt).size());
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
} catch (ContextException e)
{
throw e; // To avoid case below
} catch (Exception e)
{
return VdmRuntimeError.abort(node.getLocation(), 4065, e.getMessage(), ctxt);
}
}
@Override
public Value caseADistConcatUnaryExp(ADistConcatUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
try
{
ValueList seqseq = node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).seqValue(ctxt);
ValueList result = new ValueList();
for (Value v : seqseq)
{
result.addAll(v.seqValue(ctxt));
}
return new SeqValue(result);
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
}
}
@Override
public Value caseADistIntersectUnaryExp(ADistIntersectUnaryExp node,
Context ctxt) throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
try
{
ValueSet setset = node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).setValue(ctxt);
if (setset.isEmpty())
{
return VdmRuntimeError.abort(node.getLocation(), 4151, "Cannot take dinter of empty set", ctxt);
}
ValueSet result = null;
for (Value v : setset)
{
if (result == null)
{
result = new ValueSet(v.setValue(ctxt));
} else
{
result.retainAll(v.setValue(ctxt));
}
}
return new SetValue(result);
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
}
}
@Override
public Value caseADistMergeUnaryExp(ADistMergeUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
try
{
ValueSet setmap = node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).setValue(ctxt);
ValueMap result = new ValueMap();
for (Value v : setmap)
{
ValueMap m = v.mapValue(ctxt);
for (Value k : m.keySet())
{
Value rng = m.get(k);
Value old = result.put(k, rng);
if (old != null && !old.equals(rng))
{
VdmRuntimeError.abort(node.getLocation(), 4021, "Duplicate map keys have different values: "
+ k, ctxt);
}
}
}
return new MapValue(result);
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
}
}
@Override
public Value caseADistUnionUnaryExp(ADistUnionUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
try
{
ValueSet setset = node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).setValue(ctxt);
ValueSet result = new ValueSet();
for (Value v : setset)
{
result.addAll(v.setValue(ctxt));
}
return new SetValue(result);
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
}
}
@Override
public Value caseAElementsUnaryExp(AElementsUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
try
{
ValueList seq = node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).seqValue(ctxt);
ValueSet set = new ValueSet();
set.addAll(seq);
return new SetValue(set);
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
}
}
@Override
public Value caseAFloorUnaryExp(AFloorUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
try
{
return NumericValue.valueOf(Math.floor(node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).realValue(ctxt)), ctxt);
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
}
}
@Override
public Value caseAHeadUnaryExp(AHeadUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
try
{
ValueList seq = node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).seqValue(ctxt);
if (seq.isEmpty())
{
return VdmRuntimeError.abort(node.getLocation(), 4010, "Cannot take head of empty sequence", ctxt);
}
return seq.get(0);
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
}
}
@Override
public Value caseAIndicesUnaryExp(AIndicesUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
try
{
ValueList seq = node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).seqValue(ctxt);
ValueSet result = new ValueSet();
for (int i = 1; i <= seq.size(); i++)
{
result.addNoCheck(new NaturalOneValue(i));
}
return new SetValue(result);
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
} catch (Exception e)
{
return VdmRuntimeError.abort(node.getLocation(), 4065, e.getMessage(), ctxt);
}
}
@Override
public Value caseALenUnaryExp(ALenUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
try
{
return new NaturalValue(node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).seqValue(ctxt).size());
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
} catch (ContextException e)
{
throw e; // To avoid case below
} catch (Exception e)
{
return VdmRuntimeError.abort(node.getLocation(), 4065, e.getMessage(), ctxt);
}
}
@Override
public Value caseAMapDomainUnaryExp(AMapDomainUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
try
{
ValueMap map = node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).mapValue(ctxt);
ValueSet result = new ValueSet();
result.addAll(map.keySet());
return new SetValue(result);
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
}
}
@Override
public Value caseAMapInverseUnaryExp(AMapInverseUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
try
{
ValueMap map = node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).mapValue(ctxt);
if (!map.isInjective())
{
VdmRuntimeError.abort(node.getLocation(), 4012, "Cannot invert non-injective map", ctxt);
}
ValueMap result = new ValueMap();
for (Value k : map.keySet())
{
result.put(map.get(k), k);
}
return new MapValue(result);
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
}
}
@Override
public Value caseAMapRangeUnaryExp(AMapRangeUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
try
{
ValueMap map = node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).mapValue(ctxt);
ValueSet result = new ValueSet();
result.addAll(map.values());
return new SetValue(result);
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
}
}
@Override
public Value caseANotUnaryExp(ANotUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
try
{
Value v = node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt);
return v.isUndefined() ? v : new BooleanValue(!v.boolValue(ctxt));
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
}
}
@Override
public Value caseAPowerSetUnaryExp(APowerSetUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
try
{
ValueSet values = node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).setValue(ctxt);
List<ValueSet> psets = values.powerSet();
ValueSet rs = new ValueSet(psets.size());
for (ValueSet v : psets)
{
rs.addNoCheck(new SetValue(v));
}
return new SetValue(rs);
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
}
}
@Override
public Value caseAReverseUnaryExp(AReverseUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
ValueList seq = null;
try
{
seq = new ValueList(node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).seqValue(ctxt));
Collections.reverse(seq);
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
}
return new SeqValue(seq);
}
@Override
public Value caseATailUnaryExp(ATailUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
ValueList seq = null;
try
{
seq = new ValueList(node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).seqValue(ctxt));
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
}
if (seq.isEmpty())
{
VdmRuntimeError.abort(node.getLocation(), 4033, "Tail sequence is empty", ctxt);
}
seq.remove(0);
return new SeqValue(seq);
}
@Override
public Value caseAUnaryMinusUnaryExp(AUnaryMinusUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
try
{
double v = node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt).realValue(ctxt);
return NumericValue.valueOf(-v, ctxt);
} catch (ValueException e)
{
return VdmRuntimeError.abort(node.getLocation(), e);
}
}
@Override
public Value caseAUnaryPlusUnaryExp(AUnaryPlusUnaryExp node, Context ctxt)
throws AnalysisException
{
BreakpointManager.getBreakpoint(node).check(node.getLocation(), ctxt);
return node.getExp().apply(VdmRuntime.getExpressionEvaluator(), ctxt);
}
}