| 1 | package de.uka.ipd.sdq.pcm.dialogs.stoex; |
| 2 | |
| 3 | import java.util.ArrayList; |
| 4 | import java.util.Collection; |
| 5 | import java.util.Collections; |
| 6 | |
| 7 | import org.antlr.runtime.ANTLRStringStream; |
| 8 | import org.antlr.runtime.CommonTokenStream; |
| 9 | import org.antlr.runtime.Lexer; |
| 10 | import org.antlr.runtime.RecognitionException; |
| 11 | import org.eclipse.emf.common.util.TreeIterator; |
| 12 | import org.eclipse.emf.ecore.EObject; |
| 13 | import org.eclipse.swt.widgets.Shell; |
| 14 | |
| 15 | import de.uka.ipd.sdq.errorhandling.IIssue; |
| 16 | import de.uka.ipd.sdq.pcm.parameter.VariableCharacterisation; |
| 17 | import de.uka.ipd.sdq.pcm.parameter.VariableUsage; |
| 18 | import de.uka.ipd.sdq.pcm.repository.EventType; |
| 19 | import de.uka.ipd.sdq.pcm.repository.OperationSignature; |
| 20 | import de.uka.ipd.sdq.pcm.repository.Parameter; |
| 21 | import de.uka.ipd.sdq.pcm.repository.RepositoryFactory; |
| 22 | import de.uka.ipd.sdq.pcm.seff.ExternalCallAction; |
| 23 | import de.uka.ipd.sdq.pcm.seff.ResourceDemandingSEFF; |
| 24 | import de.uka.ipd.sdq.pcm.stochasticexpressions.parser.MyPCMStoExLexer; |
| 25 | import de.uka.ipd.sdq.pcm.stochasticexpressions.parser.MyPCMStoExParser; |
| 26 | import de.uka.ipd.sdq.pcm.stochasticexpressions.parser.PCMStoExLexer; |
| 27 | import de.uka.ipd.sdq.stoex.Expression; |
| 28 | import de.uka.ipd.sdq.stoex.RandomVariable; |
| 29 | import de.uka.ipd.sdq.stoex.analyser.exceptions.ExpectedTypeMismatchIssue; |
| 30 | import de.uka.ipd.sdq.stoex.analyser.visitors.ExpressionInferTypeVisitor; |
| 31 | import de.uka.ipd.sdq.stoex.analyser.visitors.NonProbabilisticExpressionInferTypeVisitor; |
| 32 | import de.uka.ipd.sdq.stoex.analyser.visitors.TypeCheckVisitor; |
| 33 | import de.uka.ipd.sdq.stoex.analyser.visitors.TypeEnum; |
| 34 | |
| 35 | public class StochasticExpressionEditDialog extends |
| 36 | AbstractGrammerBasedEditDialog { |
| 37 | |
| 38 | private TypeEnum expectedType; |
| 39 | |
| 40 | public StochasticExpressionEditDialog(Shell parent, TypeEnum expectedType) { |
| 41 | super(parent); |
| 42 | this.expectedType = expectedType; |
| 43 | } |
| 44 | |
| 45 | public StochasticExpressionEditDialog(Shell parent, TypeEnum expectedType, Parameter[] context) { |
| 46 | super(parent,context); |
| 47 | this.expectedType = expectedType; |
| 48 | } |
| 49 | |
| 50 | /** |
| 51 | * @param parent The parent shell |
| 52 | * @param expectedType The type of the expression to be entered |
| 53 | * @param contextObject An EObject from which a parameter context is derived by |
| 54 | * searching for its parent SEFF and taking this SEFFs signature into account |
| 55 | */ |
| 56 | public StochasticExpressionEditDialog(Shell parent, TypeEnum expectedType, EObject contextObject) { |
| 57 | super(parent); |
| 58 | this.expectedType = expectedType; |
| 59 | this.context = getContext(contextObject); |
| 60 | } |
| 61 | |
| 62 | public void setInitialExpression(RandomVariable ex) { |
| 63 | newText = ex.getSpecification(); |
| 64 | } |
| 65 | |
| 66 | @Override |
| 67 | public Expression getResult() { |
| 68 | return (Expression)super.getResult(); |
| 69 | } |
| 70 | |
| 71 | @Override |
| 72 | public String getResultText() { |
| 73 | return super.getResultText(); |
| 74 | } |
| 75 | |
| 76 | @Override |
| 77 | protected String getInitialText() { |
| 78 | return ""; |
| 79 | } |
| 80 | |
| 81 | @Override |
| 82 | protected Lexer getLexer(String text) { |
| 83 | return new MyPCMStoExLexer(new ANTLRStringStream(text)); |
| 84 | } |
| 85 | |
| 86 | @Override |
| 87 | protected String getTitle() { |
| 88 | return "Edit stochastic expression"; |
| 89 | } |
| 90 | |
| 91 | @Override |
| 92 | protected EObject parse(Lexer lexer) throws RecognitionException, StoExParserException { |
| 93 | MyPCMStoExParser parser = new MyPCMStoExParser(new CommonTokenStream(lexer)); |
| 94 | EObject result = parser.expression(); |
| 95 | ArrayList<IIssue> errorList = new ArrayList<IIssue>(); |
| 96 | errorList.addAll(((MyPCMStoExLexer)lexer).getErrors()); |
| 97 | errorList.addAll(parser.getErrors()); |
| 98 | |
| 99 | if (errorList.size() == 0) { |
| 100 | NonProbabilisticExpressionInferTypeVisitor typeVisitor = new NonProbabilisticExpressionInferTypeVisitor(); |
| 101 | typeVisitor.doSwitch(result); |
| 102 | errorList.addAll(checkTypes(result,typeVisitor)); |
| 103 | errorList.addAll(assertType(result,typeVisitor,expectedType)); |
| 104 | } |
| 105 | if (errorList.size() > 0) |
| 106 | throw new StoExParserException(errorList); |
| 107 | return result; |
| 108 | } |
| 109 | |
| 110 | private Collection<? extends IIssue> assertType(EObject result, |
| 111 | ExpressionInferTypeVisitor typeVisitor, TypeEnum expectedType) { |
| 112 | if (!TypeCheckVisitor.typesCompatible(expectedType,typeVisitor.getType((Expression)result))){ |
| 113 | return Collections.singletonList(new ExpectedTypeMismatchIssue( |
| 114 | expectedType, |
| 115 | typeVisitor.getType((Expression)result))); |
| 116 | } |
| 117 | return Collections.emptyList(); |
| 118 | } |
| 119 | |
| 120 | private Collection<IIssue> checkTypes(EObject result, |
| 121 | NonProbabilisticExpressionInferTypeVisitor typeVisitor) { |
| 122 | TypeCheckVisitor typeChecker = new TypeCheckVisitor(typeVisitor); |
| 123 | typeChecker.doSwitch(result); |
| 124 | TreeIterator<EObject> iterator = result.eAllContents(); |
| 125 | for(;iterator.hasNext();){ |
| 126 | EObject treeNode = iterator.next(); |
| 127 | typeChecker.doSwitch(treeNode); |
| 128 | } |
| 129 | return typeChecker.getIssues(); |
| 130 | } |
| 131 | |
| 132 | @Override |
| 133 | protected Class<PCMStoExLexer> getLexerClass() { |
| 134 | return PCMStoExLexer.class; |
| 135 | } |
| 136 | |
| 137 | @Override |
| 138 | protected ITokenMapper getTokenMapper() { |
| 139 | return new StoExTokenMapper(); |
| 140 | } |
| 141 | |
| 142 | /** |
| 143 | * Get the type of an variable characterisation. |
| 144 | * @param ch The characterisation to check. |
| 145 | * @return INT for ByteSize and number of elements, ANY for all others. |
| 146 | */ |
| 147 | public static TypeEnum getTypeFromVariableCharacterisation(VariableCharacterisation ch){ |
| 148 | switch(ch.getType()){ |
| 149 | case BYTESIZE: |
| 150 | case NUMBER_OF_ELEMENTS: |
| 151 | return TypeEnum.INT; |
| 152 | } |
| 153 | return TypeEnum.ANY; |
| 154 | } |
| 155 | |
| 156 | /** |
| 157 | * Get the context the expression edit dialog is working on. |
| 158 | * This provides access to the surrounding seff and the described signature. |
| 159 | * It is used to access provided variables etc. |
| 160 | * |
| 161 | * @param The object to access the environment. |
| 162 | * @return The parameters found in the context. |
| 163 | */ |
| 164 | private Parameter[] getContext(EObject rv) { |
| 165 | Parameter[] parameters = new Parameter[]{}; |
| 166 | |
| 167 | ResourceDemandingSEFF seff = getSEFF(rv); |
| 168 | if (seff != null && seff.getDescribedService__SEFF() != null) { |
| 169 | |
| 170 | // if the seff is about an operation signature |
| 171 | if(seff.getDescribedService__SEFF() instanceof OperationSignature){ |
| 172 | OperationSignature signature= (OperationSignature) seff.getDescribedService__SEFF(); |
| 173 | parameters = (Parameter[]) signature.getParameters__OperationSignature().toArray(); |
| 174 | |
| 175 | // if the seff is an handler for an EventType |
| 176 | } else if(seff.getDescribedService__SEFF() instanceof EventType){ |
| 177 | EventType eventType= (EventType) seff.getDescribedService__SEFF(); |
| 178 | if (eventType.getParameter__EventType() !=null) |
| 179 | parameters = new Parameter[]{eventType.getParameter__EventType()}; |
| 180 | } |
| 181 | |
| 182 | // if the actual context is an ExternalCallAction, that has a return value other than void |
| 183 | // also provide the return parameter in the code complition |
| 184 | ExternalCallAction eca = getParentCallAction(rv); |
| 185 | if (eca != null && isOutputCharacterisation(eca,rv) && eca.getCalledService_ExternalService() != null && |
| 186 | eca.getCalledService_ExternalService().getReturnType__OperationSignature() != null) { |
| 187 | Parameter[] parametersWithReturn = new Parameter[parameters.length+1]; |
| 188 | System.arraycopy(parameters,0,parametersWithReturn,0,parameters.length); |
| 189 | parametersWithReturn[parameters.length] = RepositoryFactory.eINSTANCE.createParameter(); |
| 190 | parametersWithReturn[parameters.length].setDataType__Parameter(eca.getCalledService_ExternalService().getReturnType__OperationSignature()); |
| 191 | parametersWithReturn[parameters.length].setParameterName("RETURN"); |
| 192 | parameters = parametersWithReturn; |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | return parameters; |
| 197 | } |
| 198 | |
| 199 | private boolean isOutputCharacterisation(ExternalCallAction eca, EObject rv) { |
| 200 | for (VariableUsage vu : eca.getReturnVariableUsage__CallReturnAction()){ |
| 201 | if (vu.getVariableCharacterisation_VariableUsage().contains(rv)) |
| 202 | return true; |
| 203 | } |
| 204 | return false; |
| 205 | } |
| 206 | |
| 207 | /** |
| 208 | * Get the RessourceDemandingSeff an object is included in. |
| 209 | * @param a The object to get the RDSEFF for. |
| 210 | * @return The found ressource demanding seff or null if there is none. |
| 211 | */ |
| 212 | private ResourceDemandingSEFF getSEFF(EObject a) { |
| 213 | EObject container = a; |
| 214 | while (container != null && !(container instanceof ResourceDemandingSEFF)) |
| 215 | container = container.eContainer(); |
| 216 | if (container == null || !(container instanceof ResourceDemandingSEFF)) |
| 217 | return null; |
| 218 | ResourceDemandingSEFF seff = (ResourceDemandingSEFF) container; |
| 219 | return seff; |
| 220 | } |
| 221 | |
| 222 | /** |
| 223 | * Check if the actual container of an object is an external call action. |
| 224 | * If this is the case, return the action, otherwise null. |
| 225 | * |
| 226 | * @param a The object to check the container for. |
| 227 | * @return The ExternalCallAction container or null if there is none. |
| 228 | */ |
| 229 | private ExternalCallAction getParentCallAction(EObject a) { |
| 230 | EObject container = a; |
| 231 | while (!(container instanceof ResourceDemandingSEFF) && !(container instanceof ExternalCallAction)) |
| 232 | container = container.eContainer(); |
| 233 | if (!(container instanceof ExternalCallAction)) |
| 234 | return null; |
| 235 | ExternalCallAction call = (ExternalCallAction) container; |
| 236 | return call; |
| 237 | } |
| 238 | |
| 239 | } |