/*
* #%~
* VDM Code Generator
* %%
* Copyright (C) 2008 - 2014 Overture
* %%
* This program 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.
*
* This program 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 this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #~%
*/
package org.overture.codegen.visitor;
import java.util.LinkedList;
import java.util.List;
import org.overture.ast.analysis.AnalysisException;
import org.overture.ast.definitions.AAssignmentDefinition;
import org.overture.ast.definitions.AClassInvariantDefinition;
import org.overture.ast.definitions.AExplicitOperationDefinition;
import org.overture.ast.definitions.AInheritedDefinition;
import org.overture.ast.definitions.PDefinition;
import org.overture.ast.definitions.SClassDefinition;
import org.overture.ast.expressions.ASelfExp;
import org.overture.ast.expressions.PExp;
import org.overture.ast.intf.lex.ILexNameToken;
import org.overture.ast.lex.Dialect;
import org.overture.ast.patterns.PMultipleBind;
import org.overture.ast.patterns.PPattern;
import org.overture.ast.statements.AAssignmentStm;
import org.overture.ast.statements.AAtomicStm;
import org.overture.ast.statements.ABlockSimpleBlockStm;
import org.overture.ast.statements.ACallObjectStm;
import org.overture.ast.statements.ACallStm;
import org.overture.ast.statements.ACaseAlternativeStm;
import org.overture.ast.statements.ACasesStm;
import org.overture.ast.statements.AClassInvariantStm;
import org.overture.ast.statements.ACyclesStm;
import org.overture.ast.statements.ADurationStm;
import org.overture.ast.statements.AElseIfStm;
import org.overture.ast.statements.AErrorStm;
import org.overture.ast.statements.AExitStm;
import org.overture.ast.statements.AForAllStm;
import org.overture.ast.statements.AForIndexStm;
import org.overture.ast.statements.AForPatternBindStm;
import org.overture.ast.statements.AIfStm;
import org.overture.ast.statements.ALetBeStStm;
import org.overture.ast.statements.ALetStm;
import org.overture.ast.statements.ANotYetSpecifiedStm;
import org.overture.ast.statements.APeriodicStm;
import org.overture.ast.statements.AReturnStm;
import org.overture.ast.statements.ASkipStm;
import org.overture.ast.statements.AStartStm;
import org.overture.ast.statements.ASubclassResponsibilityStm;
import org.overture.ast.statements.AWhileStm;
import org.overture.ast.statements.PObjectDesignator;
import org.overture.ast.statements.PStateDesignator;
import org.overture.ast.statements.PStm;
import org.overture.ast.types.PType;
import org.overture.ast.types.SSetType;
import org.overture.codegen.ir.IRInfo;
import org.overture.codegen.ir.SExpIR;
import org.overture.codegen.ir.SMultipleBindIR;
import org.overture.codegen.ir.SObjectDesignatorIR;
import org.overture.codegen.ir.SPatternIR;
import org.overture.codegen.ir.SStateDesignatorIR;
import org.overture.codegen.ir.SStmIR;
import org.overture.codegen.ir.STypeIR;
import org.overture.codegen.ir.declarations.AVarDeclIR;
import org.overture.codegen.ir.expressions.AAndBoolBinaryExpIR;
import org.overture.codegen.ir.expressions.AReverseUnaryExpIR;
import org.overture.codegen.ir.expressions.AUndefinedExpIR;
import org.overture.codegen.ir.patterns.AIdentifierPatternIR;
import org.overture.codegen.ir.statements.AAssignmentStmIR;
import org.overture.codegen.ir.statements.AAtomicStmIR;
import org.overture.codegen.ir.statements.ABlockStmIR;
import org.overture.codegen.ir.statements.ACallObjectStmIR;
import org.overture.codegen.ir.statements.ACaseAltStmStmIR;
import org.overture.codegen.ir.statements.ACasesStmIR;
import org.overture.codegen.ir.statements.ACyclesStmIR;
import org.overture.codegen.ir.statements.ADurationStmIR;
import org.overture.codegen.ir.statements.AElseIfStmIR;
import org.overture.codegen.ir.statements.AErrorStmIR;
import org.overture.codegen.ir.statements.AExitStmIR;
import org.overture.codegen.ir.statements.AForAllStmIR;
import org.overture.codegen.ir.statements.AForIndexStmIR;
import org.overture.codegen.ir.statements.AIfStmIR;
import org.overture.codegen.ir.statements.ALetBeStStmIR;
import org.overture.codegen.ir.statements.ANotImplementedStmIR;
import org.overture.codegen.ir.statements.APeriodicStmIR;
import org.overture.codegen.ir.statements.APlainCallStmIR;
import org.overture.codegen.ir.statements.AReturnStmIR;
import org.overture.codegen.ir.statements.ASkipStmIR;
import org.overture.codegen.ir.statements.AStartStmIR;
import org.overture.codegen.ir.statements.AStartlistStmIR;
import org.overture.codegen.ir.statements.ASuperCallStmIR;
import org.overture.codegen.ir.statements.AWhileStmIR;
import org.overture.codegen.ir.types.ABoolBasicTypeIR;
import org.overture.codegen.ir.types.AClassTypeIR;
import org.overture.codegen.ir.utils.AHeaderLetBeStIR;
import org.overture.config.Settings;
public class StmVisitorIR extends AbstractVisitorIR<IRInfo, SStmIR>
{
public StmVisitorIR()
{
}
@Override
public SStmIR caseAExitStm(AExitStm node, IRInfo question)
throws AnalysisException
{
SExpIR expCg = node.getExpression() != null
? node.getExpression().apply(question.getExpVisitor(), question)
: null;
AExitStmIR exitCg = new AExitStmIR();
exitCg.setExp(expCg);
return exitCg;
}
@Override
public SStmIR caseAErrorStm(AErrorStm node, IRInfo question)
throws AnalysisException
{
return new AErrorStmIR();
}
@Override
public SStmIR caseAClassInvariantStm(AClassInvariantStm node,
IRInfo question) throws AnalysisException
{
List<PExp> exps = new LinkedList<PExp>();
for (PDefinition d : node.getInvDefs())
{
if (!(d instanceof AClassInvariantDefinition))
{
log.error("Expected class invariant definition: " + d);
return null;
}
AClassInvariantDefinition invDef = (AClassInvariantDefinition) d;
exps.add(invDef.getExpression());
}
AReturnStmIR returnStmCg = new AReturnStmIR();
if (exps.isEmpty())
{
// Should not really be necessary
returnStmCg.setExp(question.getExpAssistant().consBoolLiteral(true));
} else if (exps.size() == 1)
{
SExpIR expCg = exps.get(0).apply(question.getExpVisitor(), question);
returnStmCg.setExp(expCg);
} else
{
// We have more than one expressions from which we will build an 'and chain'
AAndBoolBinaryExpIR andExpTopCg = new AAndBoolBinaryExpIR();
andExpTopCg.setType(new ABoolBasicTypeIR());
andExpTopCg.setLeft(exps.get(0).apply(question.getExpVisitor(), question));
AAndBoolBinaryExpIR previousAndExpCg = andExpTopCg;
// The remaining ones except the last
for (int i = 1; i < exps.size() - 1; i++)
{
SExpIR nextExpCg = exps.get(i).apply(question.getExpVisitor(), question);
AAndBoolBinaryExpIR nextAndExpCg = new AAndBoolBinaryExpIR();
nextAndExpCg.setType(new ABoolBasicTypeIR());
nextAndExpCg.setLeft(nextExpCg);
previousAndExpCg.setRight(nextAndExpCg);
previousAndExpCg = nextAndExpCg;
}
previousAndExpCg.setRight(exps.get(exps.size()
- 1).apply(question.getExpVisitor(), question));
returnStmCg.setExp(andExpTopCg);
}
return returnStmCg;
}
@Override
public SStmIR caseAPeriodicStm(APeriodicStm node, IRInfo question)
throws AnalysisException
{
String opName = node.getOpname().getName();
APeriodicStmIR periodicStmCg = new APeriodicStmIR();
periodicStmCg.setOpname(opName);
for (PExp exp : node.getArgs())
{
SExpIR expCg = exp.apply(question.getExpVisitor(), question);
if (expCg != null)
{
periodicStmCg.getArgs().add(expCg);
} else
{
return null;
}
}
return periodicStmCg;
}
@Override
public SStmIR caseAAtomicStm(AAtomicStm node, IRInfo question)
throws AnalysisException
{
AAtomicStmIR atomicBlock = new AAtomicStmIR();
for (AAssignmentStm assignment : node.getAssignments())
{
SStmIR stmCg = assignment.apply(question.getStmVisitor(), question);
if (stmCg != null)
{
atomicBlock.getStatements().add(stmCg);
} else
{
return null;
}
}
return atomicBlock;
}
@Override
public SStmIR caseACyclesStm(ACyclesStm node, IRInfo question)
throws AnalysisException
{
PExp cycles = node.getCycles();
PStm stm = node.getStatement();
SExpIR cyclesCg = cycles.apply(question.getExpVisitor(), question);
SStmIR stmCg = stm.apply(question.getStmVisitor(), question);
ACyclesStmIR cycStm = new ACyclesStmIR();
cycStm.setCycles(cyclesCg);
cycStm.setStm(stmCg);
return cycStm;
}
@Override
public SStmIR caseADurationStm(ADurationStm node, IRInfo question)
throws AnalysisException
{
PExp duration = node.getDuration();
PStm stm = node.getStatement();
SExpIR durationCg = duration.apply(question.getExpVisitor(), question);
SStmIR stmCg = stm.apply(question.getStmVisitor(), question);
ADurationStmIR durStm = new ADurationStmIR();
durStm.setDuration(durationCg);
durStm.setStm(stmCg);
;
return durStm;
}
@Override
public SStmIR caseALetBeStStm(ALetBeStStm node, IRInfo question)
throws AnalysisException
{
PMultipleBind multipleBind = node.getBind();
SMultipleBindIR multipleBindCg = multipleBind.apply(question.getMultipleBindVisitor(), question);
PExp suchThat = node.getSuchThat();
PStm stm = node.getStatement();
SExpIR suchThatCg = suchThat != null
? suchThat.apply(question.getExpVisitor(), question) : null;
SStmIR stmCg = stm.apply(question.getStmVisitor(), question);
ALetBeStStmIR letBeSt = new ALetBeStStmIR();
AHeaderLetBeStIR header = question.getExpAssistant().consHeader(multipleBindCg, suchThatCg);
letBeSt.setHeader(header);
letBeSt.setStatement(stmCg);
return letBeSt;
}
@Override
public SStmIR caseAWhileStm(AWhileStm node, IRInfo question)
throws AnalysisException
{
PStm stm = node.getStatement();
PExp exp = node.getExp();
SStmIR bodyCg = stm.apply(question.getStmVisitor(), question);
SExpIR expCg = exp.apply(question.getExpVisitor(), question);
AWhileStmIR whileStm = new AWhileStmIR();
whileStm.setExp(expCg);
whileStm.setBody(bodyCg);
return whileStm;
}
@Override
public SStmIR caseANotYetSpecifiedStm(ANotYetSpecifiedStm node,
IRInfo question) throws AnalysisException
{
return new ANotImplementedStmIR();
}
@Override
public SStmIR caseABlockSimpleBlockStm(ABlockSimpleBlockStm node,
IRInfo question) throws AnalysisException
{
ABlockStmIR blockStm = new ABlockStmIR();
blockStm.setScoped(question.getStmAssistant().isScoped(node));
LinkedList<AAssignmentDefinition> assignmentDefs = node.getAssignmentDefs();
for (AAssignmentDefinition def : assignmentDefs)
{
PType type = def.getType();
String name = def.getName().getName();
PExp exp = def.getExpression();
STypeIR typeCg = type.apply(question.getTypeVisitor(), question);
AIdentifierPatternIR idPattern = new AIdentifierPatternIR();
idPattern.setName(name);
SExpIR expCg = exp.apply(question.getExpVisitor(), question);
AVarDeclIR localDecl = question.getDeclAssistant().consLocalVarDecl(def, typeCg, idPattern, expCg);
if (expCg instanceof AUndefinedExpIR)
{
question.getDeclAssistant().setDefaultValue(localDecl, typeCg);
} else
{
localDecl.setExp(expCg);
}
blockStm.getLocalDefs().add(localDecl);
}
LinkedList<PStm> stms = node.getStatements();
for (PStm pStm : stms)
{
SStmIR stmCg = pStm.apply(question.getStmVisitor(), question);
if (stmCg != null)
{
blockStm.getStatements().add(stmCg);
} else
{
return null;
}
}
return blockStm;
}
@Override
public SStmIR caseAAssignmentStm(AAssignmentStm node, IRInfo question)
throws AnalysisException
{
PStateDesignator target = node.getTarget();
PExp exp = node.getExp();
SStateDesignatorIR targetCg = target.apply(question.getStateDesignatorVisitor(), question);
SExpIR expCg = exp.apply(question.getExpVisitor(), question);
AAssignmentStmIR assignment = new AAssignmentStmIR();
assignment.setTarget(targetCg);
assignment.setExp(expCg);
return assignment;
}
@Override
public SStmIR caseALetStm(ALetStm node, IRInfo question)
throws AnalysisException
{
ABlockStmIR block = new ABlockStmIR();
block.setScoped(question.getStmAssistant().isScoped(node));
question.getDeclAssistant().setFinalLocalDefs(node.getLocalDefs(), block.getLocalDefs(), question);
SStmIR stm = node.getStatement().apply(question.getStmVisitor(), question);
if (stm != null)
{
block.getStatements().add(stm);
}
return block;
}
@Override
public SStmIR caseAReturnStm(AReturnStm node, IRInfo question)
throws AnalysisException
{
PExp exp = node.getExpression();
AExplicitOperationDefinition operation = node.getAncestor(AExplicitOperationDefinition.class);
if (operation != null && operation.getIsConstructor())
{
if (exp instanceof ASelfExp)
{
// The expression of the return statement points to 'null' since the OO AST
// does not allow constructors to return references to explicitly
// created types. Simply 'returning' in a constructor means returning
// a reference for the object currently being created.
return new AReturnStmIR();
} else
{
question.addUnsupportedNode(operation, "Unexpected expression returned by constructor: Values expliclty returned by constructors must be 'self'.");
return null;
}
}
AReturnStmIR returnStm = new AReturnStmIR();
if (exp != null)
{
SExpIR expCg = exp.apply(question.getExpVisitor(), question);
returnStm.setExp(expCg);
}
return returnStm;
}
@Override
public SStmIR caseACallStm(ACallStm node, IRInfo question)
throws AnalysisException
{
PDefinition rootdef = node.getRootdef();
LinkedList<PExp> args = node.getArgs();
List<SExpIR> argsCg = new LinkedList<SExpIR>();
for (PExp arg : args)
{
SExpIR argCg = arg.apply(question.getExpVisitor(), question);
if (argCg != null)
{
argsCg.add(argCg);
} else
{
return null;
}
}
boolean isStaticOrSl = Settings.dialect == Dialect.VDM_SL
|| question.getTcFactory().createPDefinitionAssistant().isStatic(rootdef);
while (rootdef instanceof AInheritedDefinition)
{
rootdef = ((AInheritedDefinition) rootdef).getSuperdef();
}
PType type = node.getType();
ILexNameToken nameToken = node.getName();
String name = nameToken.getName();
AClassTypeIR classType = null;
STypeIR typeCg = type.apply(question.getTypeVisitor(), question);
boolean isConstructorCall = rootdef instanceof AExplicitOperationDefinition
&& ((AExplicitOperationDefinition) rootdef).getIsConstructor();
if (!isConstructorCall && !isStaticOrSl)
{
ILexNameToken enclosingClassName = node.getAncestor(SClassDefinition.class).getName();
if (node.getName().getExplicit()
&& !node.getName().equals(enclosingClassName))
{
ASuperCallStmIR superCall = new ASuperCallStmIR();
superCall.setIsStatic(isStaticOrSl);
superCall.setType(typeCg);
superCall.setName(name);
superCall.setArgs(argsCg);
return superCall;
}
} else if (nameToken != null && nameToken.getExplicit() && isStaticOrSl)
{
String className = nameToken.getModule();
classType = new AClassTypeIR();
classType.setName(className);
}
APlainCallStmIR callStm = new APlainCallStmIR();
callStm.setType(typeCg);
callStm.setIsStatic(isStaticOrSl);
callStm.setName(name);
callStm.setClassType(classType);
callStm.setArgs(argsCg);
return callStm;
}
@Override
public SStmIR caseACallObjectStm(ACallObjectStm node, IRInfo question)
throws AnalysisException
{
PType type = node.getType();
PObjectDesignator objectDesignator = node.getDesignator();
ILexNameToken field = node.getField();
LinkedList<PExp> args = node.getArgs();
STypeIR typeCg = type.apply(question.getTypeVisitor(), question);
SObjectDesignatorIR objectDesignatorCg = objectDesignator.apply(question.getObjectDesignatorVisitor(), question);
if (node.getExplicit())
{
SClassDefinition enclosingClass = node.getAncestor(SClassDefinition.class);
if (enclosingClass != null)
{
if (!field.getModule().equals(enclosingClass.getName().getName()))
{
// A quoted method call is only supported if the explicit
// module name is equal to that of the enclosing class. Say A
// is a sub class of S and 'a' is an instance of A then a.A`op();
// is allowed (although it is the same as a.op()). However,
// a.S`op(); is not allowed.
question.addUnsupportedNode(node, "A quoted object call statement is only supported if the explicit module name is equal to that of the enclosing class");
}
} else
{
log.error("Could not find enclosing the statement of call object statement.");
}
}
String fieldNameCg = field.getName();
ACallObjectStmIR callObject = new ACallObjectStmIR();
callObject.setType(typeCg);
callObject.setDesignator(objectDesignatorCg);
callObject.setFieldName(fieldNameCg);
for (PExp arg : args)
{
SExpIR argCg = arg.apply(question.getExpVisitor(), question);
if (argCg != null)
{
callObject.getArgs().add(argCg);
} else
{
return null;
}
}
return callObject;
}
@Override
public SStmIR caseAElseIfStm(AElseIfStm node, IRInfo question)
throws AnalysisException
{
// Don't visit it but create it directly if needed in the ifStm in order to avoid casting
return null;
}
@Override
public SStmIR caseACasesStm(ACasesStm node, IRInfo question)
throws AnalysisException
{
PExp exp = node.getExp();
PStm others = node.getOthers();
LinkedList<ACaseAlternativeStm> cases = node.getCases();
SExpIR expCg = exp.apply(question.getExpVisitor(), question);
SStmIR othersCg = others != null
? others.apply(question.getStmVisitor(), question) : null;
ACasesStmIR casesStmCg = new ACasesStmIR();
casesStmCg.setExp(expCg);
casesStmCg.setOthers(othersCg);
question.getStmAssistant().handleAlternativesCasesStm(question, exp, cases, casesStmCg.getCases());
return casesStmCg;
}
@Override
public SStmIR caseACaseAlternativeStm(ACaseAlternativeStm node,
IRInfo question) throws AnalysisException
{
PPattern pattern = node.getPattern();
PStm result = node.getResult();
SPatternIR patternCg = pattern.apply(question.getPatternVisitor(), question);
SStmIR resultCg = result.apply(question.getStmVisitor(), question);
ACaseAltStmStmIR caseCg = new ACaseAltStmStmIR();
caseCg.setPattern(patternCg);
caseCg.setResult(resultCg);
return caseCg;
}
@Override
public SStmIR caseAIfStm(AIfStm node, IRInfo question)
throws AnalysisException
{
SExpIR ifExp = node.getIfExp().apply(question.getExpVisitor(), question);
SStmIR thenStm = node.getThenStm().apply(question.getStmVisitor(), question);
AIfStmIR ifStm = new AIfStmIR();
ifStm.setIfExp(ifExp);
ifStm.setThenStm(thenStm);
LinkedList<AElseIfStm> elseIfs = node.getElseIf();
for (AElseIfStm stm : elseIfs)
{
ifExp = stm.getElseIf().apply(question.getExpVisitor(), question);
thenStm = stm.getThenStm().apply(question.getStmVisitor(), question);
AElseIfStmIR elseIfStm = new AElseIfStmIR();
elseIfStm.setElseIf(ifExp);
elseIfStm.setThenStm(thenStm);
ifStm.getElseIf().add(elseIfStm);
}
if (node.getElseStm() != null)
{
SStmIR elseStm = node.getElseStm().apply(question.getStmVisitor(), question);
ifStm.setElseStm(elseStm);
}
return ifStm;
}
@Override
public SStmIR caseASkipStm(ASkipStm node, IRInfo question)
throws AnalysisException
{
return new ASkipStmIR();
}
@Override
public SStmIR caseASubclassResponsibilityStm(
ASubclassResponsibilityStm node, IRInfo question)
throws AnalysisException
{
return null;// Indicates an abstract body
}
@Override
public SStmIR caseAForIndexStm(AForIndexStm node, IRInfo question)
throws AnalysisException
{
ILexNameToken var = node.getVar();
PExp from = node.getFrom();
PExp to = node.getTo();
PExp by = node.getBy();
PStm stm = node.getStatement();
String varCg = var.getName();
SExpIR fromCg = from.apply(question.getExpVisitor(), question);
SExpIR toCg = to.apply(question.getExpVisitor(), question);
SExpIR byCg = by != null ? by.apply(question.getExpVisitor(), question)
: null;
SStmIR bodyCg = stm.apply(question.getStmVisitor(), question);
AForIndexStmIR forStm = new AForIndexStmIR();
forStm.setVar(varCg);
forStm.setFrom(fromCg);
forStm.setTo(toCg);
forStm.setBy(byCg);
forStm.setBody(bodyCg);
return forStm;
}
@Override
public SStmIR caseAForAllStm(AForAllStm node, IRInfo question)
throws AnalysisException
{
// Example: for all x in set {1,2,3} do skip;
PPattern pattern = node.getPattern();
PExp set = node.getSet();
PStm body = node.getStatement();
SPatternIR patternCg = pattern.apply(question.getPatternVisitor(), question);
SExpIR setExpCg = set.apply(question.getExpVisitor(), question);
SStmIR bodyCg = body.apply(question.getStmVisitor(), question);
AForAllStmIR forAll = new AForAllStmIR();
forAll.setPattern(patternCg);
forAll.setExp(setExpCg);
forAll.setBody(bodyCg);
return forAll;
}
@Override
public SStmIR caseAForPatternBindStm(AForPatternBindStm node,
IRInfo question) throws AnalysisException
{
// Example for mk_(a,b) in [mk_(1,2), mk_(3,4)] do skip;
PPattern pattern = node.getPatternBind().getPattern();
PExp exp = node.getExp();
PStm stm = node.getStatement();
Boolean reverse = node.getReverse();
SPatternIR patternCg = pattern.apply(question.getPatternVisitor(), question);
SExpIR seqExpCg = exp.apply(question.getExpVisitor(), question);
SStmIR stmCg = stm.apply(question.getStmVisitor(), question);
AForAllStmIR forAll = new AForAllStmIR();
forAll.setPattern(patternCg);
forAll.setBody(stmCg);
if (reverse != null && reverse)
{
AReverseUnaryExpIR reversedExp = new AReverseUnaryExpIR();
reversedExp.setType(seqExpCg.getType().clone());
reversedExp.setExp(seqExpCg);
forAll.setExp(reversedExp);
} else
{
forAll.setExp(seqExpCg);
}
return forAll;
}
@Override
public SStmIR caseAStartStm(AStartStm node, IRInfo question)
throws AnalysisException
{
PType type = node.getType();
PExp exp = node.getObj();
if (exp.getType() instanceof SSetType)
{
STypeIR typeIR = type.apply(question.getTypeVisitor(), question);
SExpIR expIR = exp.apply(question.getExpVisitor(), question);
AStartlistStmIR s = new AStartlistStmIR();
s.setType(typeIR);
s.setExp(expIR);
return s;
} else
{
STypeIR typeIR = type.apply(question.getTypeVisitor(), question);
SExpIR expIR = exp.apply(question.getExpVisitor(), question);
AStartStmIR thread = new AStartStmIR();
thread.setType(typeIR);
thread.setExp(expIR);
return thread;
}
}
}