/*******************************************************************************
*
* 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.AImplicitFunctionDefinition;
import org.overture.ast.definitions.AImplicitOperationDefinition;
import org.overture.ast.definitions.AInstanceVariableDefinition;
import org.overture.ast.definitions.AStateDefinition;
import org.overture.ast.definitions.ATypeDefinition;
import org.overture.ast.definitions.PDefinition;
import org.overture.ast.expressions.AApplyExp;
import org.overture.ast.expressions.AExistsExp;
import org.overture.ast.expressions.AImpliesBooleanBinaryExp;
import org.overture.ast.expressions.AVariableExp;
import org.overture.ast.expressions.PExp;
import org.overture.ast.factory.AstExpressionFactory;
import org.overture.ast.intf.lex.ILexNameToken;
import org.overture.ast.lex.LexNameToken;
import org.overture.ast.patterns.AIdentifierPattern;
import org.overture.ast.patterns.APatternListTypePair;
import org.overture.ast.patterns.ATypeMultipleBind;
import org.overture.ast.patterns.PMultipleBind;
import org.overture.ast.patterns.PPattern;
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;
public class SatisfiabilityObligation extends ProofObligation
{
private static final long serialVersionUID = -8922392508326253099L;
private static final ILexNameToken OLD_STATE_ARG = new LexNameToken("", "oldstate", null);
private static final ILexNameToken OLD_SELF_ARG = new LexNameToken("", "oldself", null);
private static final ILexNameToken NEW_STATE_ARG = new LexNameToken("", "newstate", null);
private static final ILexNameToken NEW_SELF_ARG = new LexNameToken("", "newself", null);
public SatisfiabilityObligation(AImplicitFunctionDefinition func,
IPOContextStack ctxt, IPogAssistantFactory af)
throws AnalysisException
{
super(func, POType.FUNC_SATISFIABILITY, ctxt, func.getLocation(), af);
/**
* f: A * B -> R [pre ...] post ... [pre_f(a, b) =>] exists r:R & post_f(a, b, r)
*/
List<PExp> arglist = new Vector<PExp>();
for (APatternListTypePair pltp : func.getParamPatterns())
{
for (PPattern pattern : pltp.getPatterns())
{
arglist.add(patternToExp(pattern));
}
}
AApplyExp preApply = null;
if (func.getPredef() != null)
{
preApply = getApplyExp(getVarExp(func.getPredef().getName().clone(), func.getPredef().clone()), arglist);
preApply.setType(new ABooleanBasicType());
preApply.getRoot().setType(func.getPredef().getType().clone());
}
AExistsExp existsExp = new AExistsExp();
existsExp.setType(new ABooleanBasicType());
List<PExp> postArglist = new Vector<PExp>(arglist);
if (func.getResult().getPattern() instanceof AIdentifierPattern)
{
AIdentifierPattern ip = (AIdentifierPattern) func.getResult().getPattern().clone();
postArglist.add(patternToExp(func.getResult().getPattern()));
existsExp.setBindList(getMultipleTypeBindList(func.getResult().getType().clone(), ip.getName()));
} else
{
throw new RuntimeException("Expecting identifier pattern in function result");
}
AApplyExp postApply = getApplyExp(getVarExp(func.getPostdef().getName(), func.getPostdef()), postArglist);
postApply.setType(new ABooleanBasicType());
postApply.getRoot().setType(func.getPostdef().getType().clone());
existsExp.setPredicate(postApply);
if (preApply != null)
{
AImpliesBooleanBinaryExp implies = AstExpressionFactory.newAImpliesBooleanBinaryExp(preApply, existsExp);
stitch = implies;
valuetree.setPredicate(ctxt.getPredWithContext(implies));
} else
{
stitch = existsExp;
valuetree.setPredicate(ctxt.getPredWithContext(existsExp));
}
// valuetree.setContext(ctxt.getContextNodeList());
}
public SatisfiabilityObligation(AImplicitOperationDefinition op,
PDefinition stateDefinition, IPOContextStack ctxt,
IPogAssistantFactory af) throws AnalysisException
{
super(op, POType.OP_SATISFIABILITY, ctxt, op.getLocation(), af);
/**
* op: A * B ==> R [pre ...] post ... [pre_op(a, b, state) =>] exists r:R, state:Sigma & post_op(a, b, r,
* state~, state) The state argument is either a Sigma(SL) or self(PP).
*/
PExp predExp = buildPredicate(op, stateDefinition);
stitch = predExp;
valuetree.setPredicate(ctxt.getPredWithContext(predExp));
}
public SatisfiabilityObligation(ATypeDefinition node, IPOContextStack ctxt,
IPogAssistantFactory af) throws AnalysisException
{
super(node, POType.TYPE_INV_SAT, ctxt, node.getLocation(), af);
AExistsExp exists_exp = new AExistsExp();
exists_exp.setType(new ABooleanBasicType());
ATypeMultipleBind tmb = new ATypeMultipleBind();
List<PPattern> pats = new LinkedList<PPattern>();
pats.add(node.getInvPattern().clone());
tmb.setPlist(pats);
tmb.setType(node.getInvType().clone());
List<PMultipleBind> binds = new LinkedList<PMultipleBind>();
binds.add(tmb);
exists_exp.setBindList(binds);
exists_exp.setPredicate(node.getInvExpression().clone());
stitch = exists_exp;
valuetree.setPredicate(ctxt.getPredWithContext(exists_exp));
}
public SatisfiabilityObligation(AStateDefinition node,
IPOContextStack ctxt, IPogAssistantFactory af)
throws AnalysisException
{
super(node, POType.STATE_INV_SAT, ctxt, node.getLocation(), af);
AExistsExp exists_exp = new AExistsExp();
exists_exp.setType(new ABooleanBasicType());
List<PMultipleBind> binds = getInvBinds(node);
exists_exp.setBindList(binds);
exists_exp.setPredicate(node.getInvExpression().clone());
stitch = exists_exp;
valuetree.setPredicate(ctxt.getPredWithContext(exists_exp));
}
private List<PMultipleBind> getInvBinds(AStateDefinition node)
{
List<PMultipleBind> r = new Vector<PMultipleBind>();
for (AFieldField f : node.getFields())
{
r.add(getMultipleTypeBind(f.getType().clone(), f.getTagname().clone()));
}
return r;
}
public SatisfiabilityObligation(AClassInvariantDefinition node,
IPOContextStack ctxt, IPogAssistantFactory af)
throws AnalysisException
{
super(node, POType.STATE_INV_SAT, ctxt, node.getLocation(), af);
AExistsExp exists_exp = new AExistsExp();
exists_exp.setType(new ABooleanBasicType());
List<PMultipleBind> binds = stateInvBinds(node);
exists_exp.setBindList(binds);
exists_exp.setPredicate(node.getExpression().clone());
stitch = exists_exp;
valuetree.setPredicate(ctxt.getPredWithContext(exists_exp));
}
protected List<PMultipleBind> stateInvBinds(AClassInvariantDefinition node)
{
List<PMultipleBind> binds = new LinkedList<PMultipleBind>();
for (PDefinition p : node.getClassDefinition().getDefinitions())
{
if (p instanceof AInstanceVariableDefinition)
{
binds.add(getMultipleTypeBind(p.getType().clone(), p.getName().clone()));
}
}
return binds;
}
PExp buildPredicate(AImplicitOperationDefinition op,
PDefinition stateDefinition) throws AnalysisException
{
List<PExp> arglist = new Vector<PExp>();
for (APatternListTypePair pltp : op.getParameterPatterns())
{
for (PPattern pattern : pltp.getPatterns())
{
arglist.add(patternToExp(pattern.clone()));
}
}
if (stateDefinition != null)
{
stateInPre(arglist, stateDefinition);
}
AApplyExp preApply = null;
if (op.getPredef() != null)
{
preApply = getApplyExp(getVarExp(op.getPredef().getName().clone(), op.getPredef()), arglist);
preApply.getRoot().setType(op.getPredef().getType().clone());
preApply.setType(new ABooleanBasicType());
}
PExp mainExp;
// Operation Has a Result. Add it in the post condition.
if (op.getResult() != null)
{
AExistsExp existsExp = new AExistsExp();
existsExp.setType(new ABooleanBasicType());
List<PExp> postArglist = new Vector<PExp>(arglist);
if (op.getResult().getPattern() instanceof AIdentifierPattern)
{
AIdentifierPattern ip = (AIdentifierPattern) op.getResult().getPattern();
postArglist.add(patternToExp(op.getResult().getPattern().clone()));
if (stateDefinition != null)
{
if (stateDefinition instanceof AStateDefinition)
{
AVariableExp varExp = getVarExp(OLD_STATE_ARG,stateDefinition.clone());
varExp.setType(((AStateDefinition) stateDefinition).getRecordType().clone());
postArglist.add(varExp);
AVariableExp varExp2 = getVarExp(NEW_STATE_ARG,stateDefinition.clone());
varExp2.setType(((AStateDefinition) stateDefinition).getRecordType().clone());
postArglist.add(varExp2);
} else
{
AVariableExp varExp = getVarExp(OLD_SELF_ARG,stateDefinition.clone());
postArglist.add(varExp);
varExp.setType(stateDefinition.getType().clone());
AVariableExp varExp2 = getVarExp(NEW_SELF_ARG,stateDefinition.clone());
postArglist.add(varExp2);
varExp2.setType(stateDefinition.getType().clone());
}
}
existsExp.setBindList(getMultipleTypeBindList(op.getResult().getType().clone(), ip.getName().clone()));
} else
{
throw new RuntimeException("Expecting single identifier pattern in operation result");
}
AApplyExp postApply = getApplyExp(getVarExp(op.getPostdef().getName(),op.getPostdef().clone()), postArglist);
postApply.getRoot().setType(op.getPostdef().getType().clone());
postApply.setType(new ABooleanBasicType());
existsExp.setPredicate(postApply);
mainExp = existsExp;
}
// No Result. Just add new state to post condition
else
{
AExistsExp exists_exp = new AExistsExp();
exists_exp.setType(new ABooleanBasicType());
List<PExp> postArglist = new Vector<PExp>(arglist);
List<PMultipleBind> exists_binds = new LinkedList<PMultipleBind>();
if (stateDefinition != null)
{
stateInPost(exists_binds, postArglist, stateDefinition);
}
exists_exp.setBindList(exists_binds);
AApplyExp postApply = getApplyExp(getVarExp(op.getPostdef().getName(),op.getPostdef().clone()), new Vector<PExp>(postArglist));
postApply.setType(new ABooleanBasicType());
postApply.getRoot().setType(op.getPostdef().getType().clone());
exists_exp.setPredicate(postApply);
mainExp = exists_exp;
}
if (preApply != null)
{
return AstExpressionFactory.newAImpliesBooleanBinaryExp(preApply, mainExp);
} else
{
return mainExp;
}
}
protected void stateInPre(List<PExp> args, PDefinition stateDefinition)
{
AVariableExp varExp;
if (stateDefinition instanceof AStateDefinition)
{
varExp = getVarExp(OLD_STATE_ARG,stateDefinition.clone());
varExp.setType(((AStateDefinition) stateDefinition).getRecordType().clone());
} else
{
varExp = getVarExp(OLD_SELF_ARG,stateDefinition.clone());
varExp.setType(stateDefinition.getType().clone());
}
args.add(varExp);
}
protected void stateInPost(List<PMultipleBind> exists_binds,
List<PExp> postArglist, PDefinition stateDefinition)
{
AVariableExp varExp;
// replace with super call
if (stateDefinition instanceof AStateDefinition)
{
varExp = getVarExp(NEW_STATE_ARG,stateDefinition.clone());
AStateDefinition aStateDefinition = (AStateDefinition) stateDefinition;
varExp.setType(aStateDefinition.getRecordType().clone());
exists_binds.addAll(getMultipleTypeBindList(aStateDefinition.getRecordType().clone(), NEW_STATE_ARG));
} else
{
varExp = getVarExp(NEW_SELF_ARG,stateDefinition.clone());
varExp.setType(stateDefinition.getType().clone());
exists_binds.addAll(getMultipleTypeBindList(stateDefinition.getType().clone(), NEW_SELF_ARG));
}
postArglist.add(varExp);
}
}