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 | } |