/*******************************************************************************
*
* 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.pog.obligation;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;
import org.overture.ast.analysis.AnalysisException;
import org.overture.ast.definitions.AClassInvariantDefinition;
import org.overture.ast.definitions.AEqualsDefinition;
import org.overture.ast.definitions.AExplicitOperationDefinition;
import org.overture.ast.definitions.AImplicitOperationDefinition;
import org.overture.ast.definitions.AStateDefinition;
import org.overture.ast.definitions.PDefinition;
import org.overture.ast.definitions.SClassDefinition;
import org.overture.ast.expressions.AApplyExp;
import org.overture.ast.expressions.ALetDefExp;
import org.overture.ast.expressions.AVariableExp;
import org.overture.ast.expressions.PExp;
import org.overture.ast.factory.AstExpressionFactory;
import org.overture.ast.lex.LexNameToken;
import org.overture.ast.statements.AAssignmentStm;
import org.overture.ast.statements.AAtomicStm;
import org.overture.ast.types.ABooleanBasicType;
import org.overture.ast.types.AFieldField;
import org.overture.pog.pub.IPOContextStack;
import org.overture.pog.pub.IPogAssistantFactory;
import org.overture.pog.pub.POType;
import org.overture.pog.utility.Substitution;
import org.overture.pog.visitors.IVariableSubVisitor;
public class StateInvariantObligation extends ProofObligation
{
private static final long serialVersionUID = -5828298910806421399L;
public final IPogAssistantFactory assistantFactory;
public StateInvariantObligation(AAssignmentStm ass, IPOContextStack ctxt,
IPogAssistantFactory af) throws AnalysisException
{
super(ass, POType.STATE_INV, ctxt, ass.getLocation(), af);
assistantFactory = af;
if (ass.getClassDefinition() != null)
{
PExp old_invs = invDefs(ass.getClassDefinition());
String hash;
hash = ass.getTarget().apply(af.getStateDesignatorNameGetter());
Substitution sub = new Substitution(new LexNameToken("", hash, null), ass.getExp().clone());
PExp new_invs = old_invs.clone().apply(af.getVarSubVisitor(), sub);
stitch = AstExpressionFactory.newAImpliesBooleanBinaryExp(old_invs, new_invs);
valuetree.setPredicate(ctxt.getPredWithContext(stitch));
} else
{
AStateDefinition def = ass.getStateDefinition();
ALetDefExp letExp = new ALetDefExp();
letExp.setType(def.getInvExpression().getType().clone());
List<PDefinition> invDefs = new Vector<PDefinition>();
AEqualsDefinition local = new AEqualsDefinition();
local.setExpType(def.getRecordType().clone());
local.setPattern(def.getInvPattern().clone());
local.setName(def.getName().clone());
AVariableExp varExp = getVarExp(def.getName(), def.clone());
varExp.setType(def.getRecordType().clone());
local.setTest(varExp);
invDefs.add(local);
letExp.setLocalDefs(invDefs);
letExp.setExpression(def.getInvExpression().clone());
stitch = letExp;
valuetree.setPredicate(ctxt.getPredWithContext(stitch));
}
}
public StateInvariantObligation(AClassInvariantDefinition def,
IPOContextStack ctxt, IPogAssistantFactory af)
throws AnalysisException
{
super(def, POType.STATE_INV_INIT, ctxt, def.getLocation(), af);
assistantFactory = af;
// After instance variable initializers
stitch = invDefs(def.getClassDefinition());
valuetree.setPredicate(ctxt.getPredWithContext(stitch));
}
public StateInvariantObligation(AExplicitOperationDefinition def,
IPOContextStack ctxt, IPogAssistantFactory af)
throws AnalysisException
{
super(def, POType.STATE_INV, ctxt, def.getLocation(), af);
assistantFactory = af;
// After def.getName() constructor body
stitch = invDefs(def.getClassDefinition());
valuetree.setPredicate(ctxt.getPredWithContext(stitch));
}
public StateInvariantObligation(AAtomicStm atom, IPOContextStack ctxt,
IPogAssistantFactory af) throws AnalysisException
{
super(atom, POType.STATE_INV, ctxt, atom.getLocation(), af);
assistantFactory = af;
PExp invApplyExp = makeInvApplyExp(atom);
PExp invApplyExpForSub = invApplyExp.clone();
List<Substitution> subs = new LinkedList<Substitution>();
for (AAssignmentStm asgn : atom.getAssignments())
{
String hash = asgn.getTarget().apply(af.getStateDesignatorNameGetter());
subs.add(new Substitution(hash, asgn.getExp().clone()));
}
IVariableSubVisitor varSubVisitor = af.getVarSubVisitor();
for (Substitution sub : subs)
{
invApplyExpForSub = invApplyExpForSub.apply(varSubVisitor, sub);
}
stitch = AstExpressionFactory.newAImpliesBooleanBinaryExp(invApplyExp, invApplyExpForSub);
valuetree.setPredicate(stitch);
}
private PExp makeInvApplyExp(AAtomicStm atom)
{
AStateDefinition stateDef = atom.getAssignments().get(0).getStateDefinition();
if (stateDef == null)
{
return extractInv(atom);
}
String stateName = getStateName(stateDef);
List<PExp> arglist = new Vector<PExp>();
for (AFieldField f : stateDef.getFields())
{
arglist.add(getVarExp(f.getTagname().clone(), stateDef.clone(),f.getType()));
}
PExp mkExp = AstExpressionFactory.newAMkTypeExp(new LexNameToken("", stateName, null), stateDef.getRecordType().clone(), arglist);
AApplyExp invApplyExp = getApplyExp(getVarExp(stateDef.getInvdef().getName().clone(), stateDef.getInvdef().clone(), stateDef.getInvdef().getType().clone()), new ABooleanBasicType(), mkExp);
invApplyExp.getRoot().setType(stateDef.getInvdef().getType().clone());
return invApplyExp;
}
private String getStateName(PDefinition stateDef)
{
return stateDef.getName().getName();
}
private PExp extractInv(AAtomicStm atom)
{
AAssignmentStm x = atom.getAssignments().get(0);
if (x.getClassDefinition() != null)
{
return invDefs(x.getClassDefinition());
} else
{
return invDefs(x.getStateDefinition());
}
}
public StateInvariantObligation(AImplicitOperationDefinition def,
IPOContextStack ctxt, IPogAssistantFactory af)
throws AnalysisException
{
super(def, POType.STATE_INV, ctxt, def.getLocation(), af);
assistantFactory = af;
if (def.getClassDefinition() == null)
{
stitch = invDefs(def.getClassDefinition());
} else
{
stitch = invDefs(def.getStateDefinition());
}
valuetree.setPredicate(ctxt.getPredWithContext(stitch));
// valuetree.setContext(ctxt.getContextNodeList());
}
private PExp invDefs(SClassDefinition def)
{
PExp root = null;
for (PDefinition d : assistantFactory.createSClassDefinitionAssistant().getInvDefs(def.clone()))
{
AClassInvariantDefinition cid = (AClassInvariantDefinition) d;
root = makeAnd(root, cid.getExpression().clone());
}
return root;
}
private PExp invDefs(PDefinition def)
{
if (def instanceof AStateDefinition)
{
return ((AStateDefinition) def).getInvdef().getBody();
} else
{
PExp root = null;
for (PDefinition d : assistantFactory.createSClassDefinitionAssistant().getInvDefs((SClassDefinition) def))
{
AClassInvariantDefinition cid = (AClassInvariantDefinition) d;
root = makeAnd(root, cid.getExpression().clone());
}
return root;
}
}
}