/*******************************************************************************
*
* Copyright (C) 2008 Fujitsu Services Ltd.
*
* Author: Nick Battle
*
* This file is part of VDMJ.
*
* VDMJ is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* VDMJ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with VDMJ. If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
package org.overture.interpreter.values;
import org.overture.ast.analysis.AnalysisException;
import org.overture.ast.definitions.AStateDefinition;
import org.overture.ast.expressions.AEqualsBinaryExp;
import org.overture.ast.intf.lex.ILexLocation;
import org.overture.ast.types.AFieldField;
import org.overture.ast.types.ARecordInvariantType;
import org.overture.config.Settings;
import org.overture.interpreter.runtime.Context;
import org.overture.interpreter.runtime.ContextException;
import org.overture.interpreter.runtime.Interpreter;
import org.overture.interpreter.runtime.ValueException;
import org.overture.interpreter.runtime.VdmRuntime;
import org.overture.interpreter.runtime.VdmRuntimeError;
public class State implements ValueListener
{
public final AStateDefinition definition;
public final UpdatableValue recordValue;
public final Context context;
public boolean doInvariantChecks = true;
public State(AStateDefinition definition)
{
this.definition = definition;
NameValuePairList fieldvalues = new NameValuePairList();
for (AFieldField f : definition.getFields())
{
fieldvalues.add(new NameValuePair(f.getTagname(), UpdatableValue.factory(new ValueListenerList(this))));
}
ARecordInvariantType rt = (ARecordInvariantType) definition.getRecordType();
this.context = new Context(Interpreter.getInstance().getAssistantFactory(), definition.getLocation(), "module state", null);
this.recordValue = UpdatableValue.factory(new RecordValue(rt, fieldvalues, context), new ValueListenerList(this));
this.context.put(definition.getName(), recordValue);
this.context.putList(fieldvalues);
}
public void initialize(Context globals)
{
try
{
// We can't check the invariant while we're initializing fields
doInvariantChecks = false;
if (definition.getInitPattern() != null)
{
// Note that we don't call the initfunc FunctionValue. This is
// so that calls to init_sigma can test their arguments without
// changing state. See StateInitExpression.
if (!definition.getCanBeExecuted()
|| !(definition.getInitExpression() instanceof AEqualsBinaryExp))
{
throw new ValueException(4144, "State init expression cannot be executed", globals);
}
AEqualsBinaryExp ee = (AEqualsBinaryExp) definition.getInitExpression();
ee.getLocation().hit();
ee.getLeft().getLocation().hit();
Value v = ee.getRight().apply(VdmRuntime.getExpressionEvaluator(), globals);
if (!(v instanceof RecordValue))
{
throw new ValueException(4144, "State init expression cannot be executed", globals);
}
RecordValue iv = (RecordValue) v;
for (AFieldField f : definition.getFields())
{
Value sv = context.get(f.getTagname());
sv.set(ee.getLocation(), iv.fieldmap.get(f.getTag()), globals);
}
}
doInvariantChecks = true;
changedValue(null, null, globals);
}
// catch (ValueException e)
// {
// throw new ContextException(e, definition.getLocation());
// }
catch (AnalysisException e)
{
if (e instanceof ValueException)
{
VdmRuntimeError.abort(definition.getLocation(), (ValueException) e);
}
} finally
{
doInvariantChecks = true;
}
}
public Context getContext()
{
return context;
}
public void changedValue(ILexLocation location, Value changed, Context ctxt)
throws AnalysisException
{
if (doInvariantChecks
&& VdmRuntime.getNodeState(definition).invfunc != null
&& Settings.invchecks)
{
if (location == null)
{
location = VdmRuntime.getNodeState(definition).invfunc.body.getLocation();
}
try
{
if (!VdmRuntime.getNodeState(definition).invfunc.eval(VdmRuntime.getNodeState(definition).invfunc.location, recordValue, ctxt).boolValue(ctxt))
{
throw new ContextException(4131, "State invariant violated: "
+ VdmRuntime.getNodeState(definition).invfunc.name, location, ctxt);
}
} catch (ValueException e)
{
throw new ContextException(e, location);
}
}
}
}