package org.overture.codegen.vdm2java; import java.util.List; import java.util.Set; import org.overture.ast.analysis.AnalysisException; import org.overture.ast.analysis.DepthFirstAnalysisAdaptor; import org.overture.ast.definitions.AClassClassDefinition; import org.overture.ast.definitions.ARenamedDefinition; import org.overture.ast.definitions.AStateDefinition; import org.overture.ast.definitions.SClassDefinition; import org.overture.ast.expressions.AExists1Exp; import org.overture.ast.expressions.AExistsExp; import org.overture.ast.expressions.AForAllExp; import org.overture.ast.expressions.AFuncInstatiationExp; import org.overture.ast.expressions.ALetBeStExp; import org.overture.ast.expressions.ALetDefExp; import org.overture.ast.expressions.AMapCompMapExp; import org.overture.ast.expressions.ASeqCompSeqExp; import org.overture.ast.expressions.ASetCompSetExp; import org.overture.ast.expressions.ATimeExp; import org.overture.ast.expressions.PExp; import org.overture.ast.patterns.ATypeBind; import org.overture.ast.patterns.ATypeMultipleBind; import org.overture.ast.patterns.PMultipleBind; import org.overture.codegen.ir.IRInfo; import org.overture.codegen.ir.VdmNodeInfo; public class VdmAstJavaValidator extends DepthFirstAnalysisAdaptor { private IRInfo info; public VdmAstJavaValidator(IRInfo info) { this.info = info; } @Override public void inAStateDefinition(AStateDefinition node) throws AnalysisException { if (node.getCanBeExecuted() != null && !node.getCanBeExecuted()) { info.addUnsupportedNode(node, String.format("The state definition '%s' is not executable.\n" + "Only an executable state definition can be code generated.", node.getName().getName())); } } @Override public void inAClassClassDefinition(AClassClassDefinition node) throws AnalysisException { if (node.getSupernames().size() > 1) { int nonFullyAbstract = 0; for(SClassDefinition s : node.getSuperDefs()) { if(!info.getDeclAssistant().isFullyAbstract(s, info)) { nonFullyAbstract++; if (nonFullyAbstract > 1) { info.addUnsupportedNode(node, "Multiple inheritance not supported."); } } } } } @Override public void inAFuncInstatiationExp(AFuncInstatiationExp node) throws AnalysisException { if (node.getImpdef() != null) { info.addUnsupportedNode(node, "Implicit functions cannot be instantiated since they are not supported."); } } @Override public void inARenamedDefinition(ARenamedDefinition node) throws AnalysisException { info.addUnsupportedNode(node, "Renaming of imported definitions is not currently supported"); } @Override public void caseAForAllExp(AForAllExp node) throws AnalysisException { validateQuantifiedExp(node, node.getBindList(), "forall expression"); } @Override public void caseAExistsExp(AExistsExp node) throws AnalysisException { validateQuantifiedExp(node, node.getBindList(), "exists expression"); } @Override public void caseAExists1Exp(AExists1Exp node) throws AnalysisException { if (inUnsupportedContext(node)) { info.addUnsupportedNode(node, String.format("Generation of an %s is only supported within operations/functions", "exists1 expression")); } if (node.getBind() instanceof ATypeBind) { info.addUnsupportedNode(node, String.format("Generation of an %s is only supported for set binds or sequence binds", "exists1 expression")); } } private void validateQuantifiedExp(PExp node, List<PMultipleBind> bindings, String nodeStr) throws AnalysisException { if (inUnsupportedContext(node)) { info.addUnsupportedNode(node, String.format("Generation of a %s is only supported within operations/functions", nodeStr)); } for (PMultipleBind mb : bindings) { mb.apply(this); } } @Override public void caseALetDefExp(ALetDefExp node) throws AnalysisException { if (info.getExpAssistant().isAssigned(node)) { info.addUnsupportedNode(node, "Generation of a let expression is not supported in assignments"); } } @Override public void caseALetBeStExp(ALetBeStExp node) throws AnalysisException { if (inUnsupportedContext(node)) { info.addUnsupportedNode(node, "Generation of a let be st expression is only supported within operations/functions"); } node.getBind().apply(this); } @Override public void caseAMapCompMapExp(AMapCompMapExp node) throws AnalysisException { if (inUnsupportedContext(node)) { info.addUnsupportedNode(node, "Generation of a map comprehension is only supported within operations/functions"); } for (PMultipleBind mb : node.getBindings()) { mb.apply(this); } } @Override public void caseASetCompSetExp(ASetCompSetExp node) throws AnalysisException { if (inUnsupportedContext(node)) { info.addUnsupportedNode(node, "Generation of a set comprehension is only supported within operations/functions"); } for (PMultipleBind mb : node.getBindings()) { mb.apply(this); } } @Override public void caseASeqCompSeqExp(ASeqCompSeqExp node) throws AnalysisException { if (inUnsupportedContext(node)) { info.addUnsupportedNode(node, "Generation of a sequence comprehension is only supported within operations/functions"); return; } } @Override public void caseATimeExp(ATimeExp node) throws AnalysisException { info.addUnsupportedNode(node, "The 'time' expression is not supported"); } /** * Single type binds are supported for lambda expression, e.g. (lambda x : int & x) so we cannot report all of * the unsupported. */ @Override public void caseATypeMultipleBind(ATypeMultipleBind node) throws AnalysisException { info.addUnsupportedNode(node, "Type binds are not supported"); } private boolean inUnsupportedContext(org.overture.ast.node.INode node) { return info.getExpAssistant().outsideImperativeContext(node) && !info.getExpAssistant().appearsInModuleStateInv(node); } public boolean hasUnsupportedNodes() { return !info.getUnsupportedNodes().isEmpty(); } public Set<VdmNodeInfo> getUnsupportedNodes() { return info.getUnsupportedNodes(); } }