1 | /* |
---|
2 | Copyright (C) 2009-2013 Modelon AB |
---|
3 | |
---|
4 | This program is free software: you can redistribute it and/or modify |
---|
5 | it under the terms of the GNU General Public License as published by |
---|
6 | the Free Software Foundation, version 3 of the License. |
---|
7 | |
---|
8 | This program is distributed in the hope that it will be useful, |
---|
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
11 | GNU General Public License for more details. |
---|
12 | |
---|
13 | You should have received a copy of the GNU General Public License |
---|
14 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
---|
15 | */ |
---|
16 | |
---|
17 | import java.util.Arrays; |
---|
18 | import java.util.Collections; |
---|
19 | import java.util.Set; |
---|
20 | import java.util.HashSet; |
---|
21 | import java.util.ArrayList; |
---|
22 | import org.jmodelica.util.Criteria; |
---|
23 | import org.jmodelica.util.ErrorCheckType; |
---|
24 | import org.jmodelica.util.problemHandling.ErrorProducerUnlessDisabled; |
---|
25 | import org.jmodelica.util.problemHandling.AbstractErrorProducerUnlessDisabled; |
---|
26 | import org.jmodelica.util.collections.ReverseListIterable; |
---|
27 | |
---|
28 | aspect FlatTypeCheck { |
---|
29 | |
---|
30 | public void ASTNode.typeCheck(ErrorCheckType checkType) {} |
---|
31 | |
---|
32 | public abstract class ErrorChecker { |
---|
33 | public static class TypeChecker extends ErrorChecker { |
---|
34 | public TypeChecker() { |
---|
35 | super("TypeCheck"); |
---|
36 | } |
---|
37 | |
---|
38 | @Override |
---|
39 | public void check(ASTNode node, ErrorCheckType checkType) { |
---|
40 | node.typeCheck(checkType); |
---|
41 | } |
---|
42 | } |
---|
43 | } |
---|
44 | |
---|
45 | private static ErrorChecker ASTNode.TYPE_CHECKER = addErrorChecker(new ErrorChecker.TypeChecker()); |
---|
46 | |
---|
47 | public static final SimpleProblemProducer ASTNode.CLASS_NOT_SUBTYPE_OF_CONSTRAINING_CLASS = |
---|
48 | new SimpleErrorProducer("CLASS_NOT_SUBTYPE_OF_CONSTRAINING_CLASS", ProblemKind.SEMANTIC, |
---|
49 | "In the declaration '%s', the declared class is not a subtype of the " + |
---|
50 | "constraining class,\n because %s"); |
---|
51 | public static final SimpleProblemProducer ASTNode.REPLACING_CLASS_NOT_SUBTYPE_OF_CONSTRAINING_CLASS = |
---|
52 | new SimpleErrorProducer("REPLACING_CLASS_NOT_SUBTYPE_OF_CONSTRAINING_CLASS", ProblemKind.SEMANTIC, |
---|
53 | "In the declaration '%s', the replacing class is not a subtype of the " + |
---|
54 | "constraining class from the declaration '%s',\n because %s"); |
---|
55 | public static final SimpleProblemProducer ASTNode.PREV_REDECLARE_NOT_REPLACEABLE = |
---|
56 | new SimpleWarningProducer("PREV_REDECLARE_NOT_REPLACEABLE", ProblemKind.SEMANTIC, |
---|
57 | "In the declaration '%s', %s can't be redeclared since it has already been " + |
---|
58 | "redeclared without 'replaceable'"); |
---|
59 | |
---|
60 | public void InstComposite.typeCheck(ErrorCheckType checkType) { |
---|
61 | super.typeCheck(checkType); |
---|
62 | // Note that modifiers (including redeclarations) in a constraining clause |
---|
63 | // are applied to the declaration itself and is therefore also type checked. |
---|
64 | if (hasInstConstrainingComponent()) { |
---|
65 | InstNode superType = getInstConstrainingComponent().getInstNode(); |
---|
66 | InstComponentDecl declaredType = this; |
---|
67 | String subTypeMsg = declaredType.subType(superType); |
---|
68 | if (subTypeMsg != null) { |
---|
69 | SrcComponentClause cc = declaredType.myComponentClause(); |
---|
70 | CLASS_NOT_SUBTYPE_OF_CONSTRAINING_CLASS.invoke(declaredType, cc, subTypeMsg); |
---|
71 | } |
---|
72 | } |
---|
73 | } |
---|
74 | |
---|
75 | public void InstReplacingRecord.typeCheck(ErrorCheckType checkType) { |
---|
76 | typeCheckReplacingComponent(getOriginalInstComponent(), checkType); |
---|
77 | } |
---|
78 | |
---|
79 | public void InstReplacingComposite.typeCheck(ErrorCheckType checkType) { |
---|
80 | typeCheckReplacingComponent(getOriginalInstComponent(), checkType); |
---|
81 | } |
---|
82 | |
---|
83 | public void InstReplacingPrimitive.typeCheck(ErrorCheckType checkType) { |
---|
84 | typeCheckReplacingComponent(getOriginalInstComponent(), checkType); |
---|
85 | } |
---|
86 | |
---|
87 | public void InstReplacingExpandableConnectorDecl.typeCheck(ErrorCheckType checkType) { |
---|
88 | typeCheckReplacingComponent(getOriginalInstComponent(), checkType); |
---|
89 | } |
---|
90 | |
---|
91 | public void InstComponentDecl.typeCheckReplacingComponent(InstComponentDecl declaredType, ErrorCheckType checkType) { |
---|
92 | super.typeCheck(checkType); |
---|
93 | |
---|
94 | // Type check the original component |
---|
95 | InstComponentDecl superType = declaredType.constrainingInstComponentDecl(); |
---|
96 | if (declaredType.hasInstConstrainingComponent()) { |
---|
97 | String subTypeMsg = declaredType.subType(superType); |
---|
98 | if (subTypeMsg != null) { |
---|
99 | SrcComponentClause cc = declaredType.myComponentClause(); |
---|
100 | CLASS_NOT_SUBTYPE_OF_CONSTRAINING_CLASS.invoke(declaredType, cc, subTypeMsg); |
---|
101 | } |
---|
102 | } |
---|
103 | |
---|
104 | // The environment should be traversed backwards in order to perform correct |
---|
105 | // subtype tests in redeclaration chains. |
---|
106 | InstComponentRedeclare prevRedeclare = null; |
---|
107 | for (InstComponentRedeclare redeclare : myEnvironment().reverseComponentRedeclares(name())) { |
---|
108 | InstComponentDecl declaredSubType = redeclare.getInstComponentDecl(); |
---|
109 | InstComponentDecl constrainingSubType = declaredSubType.constrainingInstComponentDecl(); |
---|
110 | |
---|
111 | // Check consistency of the redeclaring component |
---|
112 | if (declaredSubType.hasInstConstrainingComponent()) { |
---|
113 | String subTypeMsg = declaredSubType.subType(constrainingSubType); |
---|
114 | if (subTypeMsg != null) { |
---|
115 | SrcComponentClause cc = declaredSubType.myComponentClause(); |
---|
116 | CLASS_NOT_SUBTYPE_OF_CONSTRAINING_CLASS.invoke(declaredSubType, cc, subTypeMsg); |
---|
117 | } |
---|
118 | } |
---|
119 | |
---|
120 | // It is ok to check against the constrainingSubType, since the declaredSubType is a subtype |
---|
121 | // of the constrainingSubType. Then if constrainingSubType is a subtype of superType, then it |
---|
122 | // follows that declaredSubType is a subtype of superType by transitivity. |
---|
123 | String subTypeMsg = constrainingSubType.subType(superType); |
---|
124 | if (subTypeMsg != null) { |
---|
125 | SrcComponentClause cc = constrainingSubType.myComponentClause(); |
---|
126 | SrcComponentClause scc = superType.myComponentClause(); |
---|
127 | REPLACING_CLASS_NOT_SUBTYPE_OF_CONSTRAINING_CLASS.invoke(constrainingSubType, |
---|
128 | cc, scc, subTypeMsg); |
---|
129 | } |
---|
130 | |
---|
131 | // If the redeclaring declaration has a constraining clause, the constraining |
---|
132 | // type of the redeclaring declaration of should be used in following subtype-test |
---|
133 | // instead of the constraining type of the original declaration. |
---|
134 | if (declaredSubType.hasInstConstrainingComponent()) |
---|
135 | superType = constrainingSubType; |
---|
136 | |
---|
137 | // If the previous redeclare is declared without "replaceable", then it is illegal |
---|
138 | // to redeclare further. The check on commonAncestor() checks that this redeclare actually |
---|
139 | // replaces the previous one. |
---|
140 | InstNode containingNode = redeclare.myInstNode(); |
---|
141 | if (prevRedeclare != null && !prevRedeclare.getInstComponentDecl().isReplaceable() && |
---|
142 | prevRedeclare.myInstNode().commonAncestor(containingNode) == containingNode) { |
---|
143 | PREV_REDECLARE_NOT_REPLACEABLE.invoke(declaredSubType, |
---|
144 | declaredSubType.myComponentClause(), declaredSubType.name()); |
---|
145 | } |
---|
146 | |
---|
147 | prevRedeclare = redeclare; |
---|
148 | } |
---|
149 | } |
---|
150 | |
---|
151 | public Iterable<InstComponentRedeclare> Environment.reverseComponentRedeclares(String name) { |
---|
152 | Set<SrcModificationOrRedeclareElement> seen = new HashSet<>(); |
---|
153 | ArrayList<InstComponentRedeclare> list = new ArrayList<>(); |
---|
154 | |
---|
155 | for (InstModification im : this) { |
---|
156 | InstComponentRedeclare red = im.matchInstComponentRedeclare(name); |
---|
157 | if (red != null) { |
---|
158 | SrcModificationOrRedeclareElement mod = red.getSrcModification(); |
---|
159 | if (!seen.contains(mod)) { |
---|
160 | seen.add(mod); |
---|
161 | list.add(red); |
---|
162 | } |
---|
163 | } |
---|
164 | } |
---|
165 | |
---|
166 | return new ReverseListIterable(list); |
---|
167 | } |
---|
168 | |
---|
169 | |
---|
170 | public static final SimpleProblemProducer ASTNode.CANNOT_INFER_ARRAY_SIZE_OF_VARIABLE = |
---|
171 | new SimpleErrorProducer("CANNOT_INFER_ARRAY_SIZE_OF_VARIABLE", ProblemKind.SEMANTIC, |
---|
172 | "Can not infer array size of the variable %s"); |
---|
173 | public static final SimpleProblemProducer ASTNode.CANNOT_INFER_ARRAY_SIZE_OF_FUNCTION_OUTPUT = |
---|
174 | new SimpleErrorProducer("CANNOT_INFER_ARRAY_SIZE_OF_FUNCTION_OUTPUT", ProblemKind.COMPLIANCE, |
---|
175 | "Can not infer array size of the function output %s"); |
---|
176 | public static final SimpleProblemProducer ASTNode.BINDING_EXPRESSION_TYPE_MISMATCH = |
---|
177 | new SimpleErrorProducer("BINDING_EXPRESSION_TYPE_MISMATCH", ProblemKind.SEMANTIC, |
---|
178 | "The binding expression of the variable %s does not match the declared type of the variable"); |
---|
179 | public static final SimpleProblemProducer ASTNode.ASSUMING_EACH = |
---|
180 | new SimpleWarningProducer("ASSUMING_EACH", ProblemKind.SEMANTIC, "Assuming 'each' for the modification '%s'"); |
---|
181 | public static final SimpleProblemProducer ASTNode.IGNORING_EACH = |
---|
182 | new SimpleWarningProducer("IGNORING_EACH", ProblemKind.SEMANTIC, "Ignoring erroneous 'each' for the modification '%s'"); |
---|
183 | public static final ErrorProducerUnlessDisabled ASTNode.ARRAY_SIZE_MISMATCH_IN_DECLARATION = |
---|
184 | new ErrorProducerUnlessDisabled("ARRAY_SIZE_MISMATCH_IN_DECLARATION", ProblemKind.SEMANTIC, |
---|
185 | "Array size mismatch in declaration of %s, size of declaration is %s and size of binding expression is %s"); |
---|
186 | public static final ErrorProducerUnlessDisabled ASTNode.ARRAY_SIZE_MISMATCH_IN_MODIFICATION = |
---|
187 | new ErrorProducerUnlessDisabled("ARRAY_SIZE_MISMATCH_IN_MODIFICATION", ProblemKind.SEMANTIC, |
---|
188 | "Array size mismatch in modification of %s, expected size is %s and size of binding expression is %s"); |
---|
189 | public static final ErrorProducerUnlessDisabled ASTNode.ARRAY_SIZE_MISMATCH_IN_MODIFICATION_DUE_TO_EACH = |
---|
190 | new ErrorProducerUnlessDisabled("ARRAY_SIZE_MISMATCH_IN_MODIFICATION_DUE_TO_EACH", ProblemKind.SEMANTIC, |
---|
191 | "Array size mismatch in modification of %s, expected size is (due to 'each') %s and size of binding expression is %s"); |
---|
192 | public static final SimpleProblemProducer ASTNode.NON_SCALAR_CONDITIONAL_GUARD = |
---|
193 | new SimpleErrorProducer("NON_SCALAR_CONDITIONAL_GUARD", ProblemKind.SEMANTIC, |
---|
194 | "The guard expression of a conditional component should be a scalar expression"); |
---|
195 | public static final SimpleProblemProducer ASTNode.NON_BOOLEAN_CONDITIONAL_GUARD = |
---|
196 | new SimpleErrorProducer("NON_BOOLEAN_CONDITIONAL_GUARD", ProblemKind.SEMANTIC, |
---|
197 | "The guard expression of a conditional component should be a boolean expression"); |
---|
198 | public static final SimpleProblemProducer ASTNode.NON_FIXED_CONDITIONAL_GUARD = |
---|
199 | new SimpleErrorProducer("NON_FIXED_CONDITIONAL_GUARD", ProblemKind.SEMANTIC, |
---|
200 | "The guard expression of a conditional component should have parameter or constant variability"); |
---|
201 | |
---|
202 | public void InstAssignable.typeCheck(ErrorCheckType checkType) { |
---|
203 | FExp bexp = myBindingInstExp(); |
---|
204 | boolean function = inFunction(); |
---|
205 | boolean record = inRecordDecl(); |
---|
206 | boolean output = isOutput(); |
---|
207 | boolean incompleteAllowed = (function && !output) || record; |
---|
208 | boolean unknownAllowed = function || record; |
---|
209 | Size componentSize = size(); |
---|
210 | if (!componentSize.isComplete() && !incompleteAllowed && !checkType.allowIncompleteSizes()) { |
---|
211 | if (function && output) { |
---|
212 | CANNOT_INFER_ARRAY_SIZE_OF_FUNCTION_OUTPUT.invoke(surroundingInstClass(), qualifiedName()); |
---|
213 | } else { |
---|
214 | CANNOT_INFER_ARRAY_SIZE_OF_VARIABLE.invoke(this, name()); |
---|
215 | } |
---|
216 | } |
---|
217 | if (bexp != null && !inRecordWithBindingExp() && !bexp.type().isUnknown() && checkType.checkTypes()) { |
---|
218 | Index arrayIndex = indexInModification(); |
---|
219 | |
---|
220 | CommonType expectedBT = expectedBindingType(); |
---|
221 | CommonType actualBT = actualBindingType(); |
---|
222 | |
---|
223 | boolean reportedError = false; |
---|
224 | if (!expectedBT.size().equivalent(actualBT.size(), unknownAllowed)) { |
---|
225 | InstValueModification ivm = myInstValueMod(); |
---|
226 | InstModification needsEach = ivm.findModificationLackingEach(actualBT.size()); |
---|
227 | if (!expectedBT.scalarType().typeCompatible(actualBT.scalarType())) { |
---|
228 | BINDING_EXPRESSION_TYPE_MISMATCH.invoke(bexp, name()); |
---|
229 | reportedError = true; |
---|
230 | } else if (needsEach != null) { |
---|
231 | ASSUMING_EACH.invoke(needsEach, needsEach); |
---|
232 | actualBT = actualBT.expand(expectedBT.size().contractLeft(expectedBT.ndims() - actualBT.ndims())); |
---|
233 | } else if (ivm.expectedSizeNoEach().equivalent(actualBT.size(), unknownAllowed)) { |
---|
234 | InstModification parIM = ivm.parentInstModification(); |
---|
235 | IGNORING_EACH.invoke(parIM, parIM); |
---|
236 | expectedBT = expectedBindingTypeNoEach(); |
---|
237 | arrayIndex = indexInModificationNoEach(); |
---|
238 | } else { |
---|
239 | ErrorProducerUnlessDisabled reporter; |
---|
240 | if (ivm.myInstNode() == this) { |
---|
241 | reporter = ARRAY_SIZE_MISMATCH_IN_DECLARATION; |
---|
242 | } else if (ivm.hasEach()) { |
---|
243 | reporter = ARRAY_SIZE_MISMATCH_IN_MODIFICATION_DUE_TO_EACH; |
---|
244 | } else { |
---|
245 | reporter = ARRAY_SIZE_MISMATCH_IN_MODIFICATION; |
---|
246 | } |
---|
247 | reporter.invokeWithCondition(bexp, expectedBT.ndims() == actualBT.ndims(), name(), expectedBT.size(), actualBT.size()); |
---|
248 | reportedError = true; |
---|
249 | } |
---|
250 | } |
---|
251 | |
---|
252 | if (!reportedError) { |
---|
253 | if (expectedBT.size().isEmpty() || expectedBT.size().isUnknown() || actualBT.size().isUnknown()) { |
---|
254 | typeCheckCell(expectedBT.scalarType(), actualBT.scalarType(), bexp, unknownAllowed); |
---|
255 | } else { |
---|
256 | Size arraySize = expectedBT.size().contractLeft(expectedBT.ndims() - arrayIndex.ndims()); |
---|
257 | for (Index index : Indices.create(arraySize)) { |
---|
258 | index = arrayIndex.expand(index); |
---|
259 | CommonType expected = expectedBT.cell(index); |
---|
260 | CommonType actual = actualBT.cell(index); |
---|
261 | |
---|
262 | typeCheckCell(expected, actual, bexp, unknownAllowed); |
---|
263 | } |
---|
264 | } |
---|
265 | } |
---|
266 | } |
---|
267 | |
---|
268 | if (hasConditionalAttribute()) { |
---|
269 | FExp cond = getConditionalAttribute(); |
---|
270 | if (!cond.type().isUnknown()) { |
---|
271 | if (!cond.type().isScalar()) |
---|
272 | NON_SCALAR_CONDITIONAL_GUARD.invoke(this); |
---|
273 | if (!cond.type().isBoolean()) |
---|
274 | NON_BOOLEAN_CONDITIONAL_GUARD.invoke(this); |
---|
275 | if (!cond.variability().parameterOrLess()) { |
---|
276 | NON_FIXED_CONDITIONAL_GUARD.invoke(this); |
---|
277 | } else { |
---|
278 | cond.markAsStructuralParameter(checkType); |
---|
279 | } |
---|
280 | } |
---|
281 | } |
---|
282 | |
---|
283 | typeCheckAttributes(); |
---|
284 | super.typeCheck(checkType); |
---|
285 | } |
---|
286 | |
---|
287 | private void InstAssignable.typeCheckCell(CommonType expectedBT, CommonType actualBT, FExp bexp, boolean unknownAllowed) { |
---|
288 | if (!expectedBT.typeCompatible(actualBT, unknownAllowed) && !expectedBT.isUnknown()) { |
---|
289 | if (!expectedBT.scalarType().typeCompatible(actualBT.scalarType())) { |
---|
290 | BINDING_EXPRESSION_TYPE_MISMATCH.invoke(bexp, name()); |
---|
291 | } |
---|
292 | } |
---|
293 | } |
---|
294 | |
---|
295 | inh InstModification InstModification.parentInstModification(); |
---|
296 | eq InstComponentModification.getChild().parentInstModification() = this; |
---|
297 | eq InstNode.getElementInstModification(int i).parentInstModification() = getElementInstModification(i); |
---|
298 | eq InstComponentDecl.getInstModification().parentInstModification() = getInstModification(); |
---|
299 | eq InstComponentDecl.getAnnotation().parentInstModification() = getAnnotation(); |
---|
300 | eq InstClassDecl.getClassAnnotation().parentInstModification() = getClassAnnotation(); |
---|
301 | eq InstConstraining.getInstClassModification().parentInstModification() = getInstClassModification(); |
---|
302 | eq InstRecordConstructor.getInstModification(int i).parentInstModification() = getInstModification(i); |
---|
303 | |
---|
304 | inh boolean InstComponentDecl.inRecordWithBindingExp(); |
---|
305 | eq InstRecord.getChild().inRecordWithBindingExp() = myBindingInstExp() != null; |
---|
306 | eq InstArrayComponentDecl.getChild().inRecordWithBindingExp() = inRecordWithBindingExp(); |
---|
307 | eq InstComponentDecl.getChild().inRecordWithBindingExp() = false; |
---|
308 | eq InstClassDecl.getChild().inRecordWithBindingExp() = false; |
---|
309 | eq Root.getChild().inRecordWithBindingExp() = false; |
---|
310 | |
---|
311 | public void InstAssignable.typeCheckAttributes() {} |
---|
312 | |
---|
313 | public void InstPrimitive.typeCheckAttributes() { |
---|
314 | for (InstModification im : totalMergedEnvironment()) |
---|
315 | im.typeCheckAttribute(this); |
---|
316 | } |
---|
317 | |
---|
318 | public void InstModification.typeCheckAttribute(InstNode owner) {} |
---|
319 | |
---|
320 | public static final SimpleProblemProducer ASTNode.TYPE_MISMATCH_IN_ATTRIBUTE_MODIFICATION = |
---|
321 | new SimpleErrorProducer("TYPE_MISMATCH_IN_ATTRIBUTE_MODIFICATION", ProblemKind.SEMANTIC, |
---|
322 | "The type of the binding expression of the attribute %s for the %s %s does not match the declared type of the variable"); |
---|
323 | public static final ErrorProducerUnlessDisabled ASTNode.ARRAY_SIZE_MISMATCH_IN_ATTRIBUTE_MODIFICATION = |
---|
324 | new ErrorProducerUnlessDisabled("ARRAY_SIZE_MISMATCH_IN_ATTRIBUTE_MODIFICATION", ProblemKind.SEMANTIC, |
---|
325 | "Array size mismatch in modification of the attribute %s for the %s %s, expected size is %s and size of %s expression is %s"); |
---|
326 | public static final ErrorProducerUnlessDisabled ASTNode.ARRAY_SIZE_MISMATCH_IN_ATTRIBUTE_MODIFICATION_DUE_TO_EACH = |
---|
327 | new ErrorProducerUnlessDisabled("ARRAY_SIZE_MISMATCH_IN_ATTRIBUTE_MODIFICATION_DUE_TO_EACH", ProblemKind.SEMANTIC, |
---|
328 | "Array size mismatch in modification of the attribute %s for the %s %s, expected size is (due to 'each') %s and size of %s expression is %s"); |
---|
329 | |
---|
330 | public void InstComponentModification.typeCheckAttribute(InstNode owner) { |
---|
331 | if (hasInstModification() && getInstModification().hasInstValueMod()) { |
---|
332 | FExp valMod = getInstModification().instValueMod(); |
---|
333 | if (!type().isUnknown() && !valMod.type().isUnknown()) { |
---|
334 | Size attrSize = expectedSize(); |
---|
335 | Size modSize = valMod.size(); |
---|
336 | if (!type().typeCompatible(valMod.type().scalarType())) { |
---|
337 | TYPE_MISMATCH_IN_ATTRIBUTE_MODIFICATION.invoke(this, name(), owner.kindDescription(), owner.name()); |
---|
338 | } else if (!attrSize.equivalent(modSize, true)) { |
---|
339 | InstModification im = findModificationLackingEach(modSize); |
---|
340 | if (im != null) { |
---|
341 | ASSUMING_EACH.invoke(im, im); |
---|
342 | } else if (expectedSizeNoEach().equivalent(modSize, false)) { |
---|
343 | IGNORING_EACH.invoke(this, this); |
---|
344 | } else { |
---|
345 | ErrorProducerUnlessDisabled producer; |
---|
346 | if (hasEach()) { |
---|
347 | producer = ARRAY_SIZE_MISMATCH_IN_ATTRIBUTE_MODIFICATION_DUE_TO_EACH; |
---|
348 | } else { |
---|
349 | producer = ARRAY_SIZE_MISMATCH_IN_ATTRIBUTE_MODIFICATION; |
---|
350 | } |
---|
351 | producer.invokeWithCondition(this, attrSize.ndims() != valMod.ndims(), name(), |
---|
352 | owner.kindDescription(), owner.name(), attrSize, name(), modSize); |
---|
353 | } |
---|
354 | } else { |
---|
355 | if (name().equals("nominal")) { |
---|
356 | checkNominalAttribute(owner, valMod); |
---|
357 | } |
---|
358 | } |
---|
359 | } |
---|
360 | } |
---|
361 | } |
---|
362 | |
---|
363 | public static final SimpleProblemProducer ASTNode.NOMINAL_EQUAL_TO_ZERO = |
---|
364 | new SimpleErrorProducer("NOMINAL_EQUAL_TO_ZERO", ProblemKind.SEMANTIC, |
---|
365 | "The attribute nominal for the %s %s is set to %s, evaluating to 0.0. A nominal value of zero is not meaningful. Please set the nominal value to the expected magnitude of the variable."); |
---|
366 | public static final SimpleProblemProducer ASTNode.NOMINAL_ELEMENT_EQUAL_TO_ZERO = |
---|
367 | new SimpleErrorProducer("NOMINAL_ELEMENT_EQUAL_TO_ZERO", ProblemKind.SEMANTIC, |
---|
368 | "The attribute nominal for the %s %s is set to %s, where element %s evaluates to 0.0. A nominal value of zero is not meaningful. Please set the nominal value to the expected magnitude of the variable."); |
---|
369 | |
---|
370 | public void InstComponentModification.checkNominalAttribute(InstNode owner, FExp valMod) { |
---|
371 | try { |
---|
372 | CValue val = valMod.ceval(); |
---|
373 | if (val.isArray()) { |
---|
374 | CValueArray arr = (CValueArray) val; |
---|
375 | for (Index i : arr.indices()) { |
---|
376 | CValue cell = arr.getCell(i); |
---|
377 | if (cell.hasRealValue() && cell.realValue() == 0.0) { |
---|
378 | NOMINAL_ELEMENT_EQUAL_TO_ZERO.invoke(this, owner.kindDescription(), owner.name(), valMod, i); |
---|
379 | break; |
---|
380 | } |
---|
381 | } |
---|
382 | } else { |
---|
383 | if (val.hasRealValue() && val.realValue() == 0.0) { |
---|
384 | NOMINAL_EQUAL_TO_ZERO.invoke(this, owner.kindDescription(), owner.name(), valMod); |
---|
385 | } |
---|
386 | } |
---|
387 | } catch (ConstantEvaluationException e) {} |
---|
388 | } |
---|
389 | |
---|
390 | syn String InstNode.kindDescription() { |
---|
391 | throw new UnsupportedOperationException(); |
---|
392 | } |
---|
393 | eq InstComponentDecl.kindDescription() = myInstClass().kindDescription() + " instance"; |
---|
394 | eq InstPrimitive.kindDescription() = "variable"; |
---|
395 | eq InstBaseClassDecl.kindDescription() = getInstRestriction().toString(); |
---|
396 | |
---|
397 | public static final SimpleProblemProducer ASTNode.EACH_APPLIED_ON_SCALAR = |
---|
398 | new SimpleWarningProducer("EACH_APPLIED_ON_SCALAR", ProblemKind.SEMANTIC, |
---|
399 | "The 'each' keyword should not be applied to a modification of a scalar component: %s"); |
---|
400 | |
---|
401 | public void InstArgument.typeCheck(ErrorCheckType checkType) { |
---|
402 | if (checkType.checkTypes() && getEach() && expectedSizeFromParent() == Size.SCALAR) |
---|
403 | EACH_APPLIED_ON_SCALAR.invoke(this, this); |
---|
404 | } |
---|
405 | |
---|
406 | inh boolean InstNode.isInRedeclareMod(); |
---|
407 | eq InstElementRedeclare.getChild().isInRedeclareMod() = true; |
---|
408 | eq InstClassDecl.getChild().isInRedeclareMod() = false; |
---|
409 | eq InstRoot.getChild().isInRedeclareMod() = false; |
---|
410 | eq Root.getChild().isInRedeclareMod() = false; |
---|
411 | |
---|
412 | public static final ErrorProducerUnlessDisabled ASTNode.ARRAY_SIZE_MISMATCH_IN_EQUATION = |
---|
413 | new ErrorProducerUnlessDisabled("ARRAY_SIZE_MISMATCH_IN_EQUATION", ProblemKind.SEMANTIC, |
---|
414 | "The array sizes of right and left hand side of equation are not compatible, size of left-hand side is %s, and size of right-hand side is %s"); |
---|
415 | public static final SimpleProblemProducer ASTNode.TYPE_MISMATCH_IN_EQUATION = |
---|
416 | new SimpleErrorProducer("TYPE_MISMATCH_IN_EQUATION", ProblemKind.SEMANTIC, |
---|
417 | "The right and left expression types of equation are not compatible, type of left-hand side is %s, and type of right-hand side is %s"); |
---|
418 | |
---|
419 | public void FEquation.typeCheck(ErrorCheckType checkType) { |
---|
420 | typeCheckLocalIteration(checkType); |
---|
421 | FType left = getLeft().type(); |
---|
422 | FType right = getRight().type(); |
---|
423 | if (!left.isUnknown() && !right.isUnknown()) { |
---|
424 | if (!left.equivalentTo(right)) { |
---|
425 | if (left.equivalentExceptLengths(right)) { |
---|
426 | if (!lockBranch(checkType)) |
---|
427 | ARRAY_SIZE_MISMATCH_IN_EQUATION.invoke(this, left.size(), right.size()); |
---|
428 | } else { |
---|
429 | TYPE_MISMATCH_IN_EQUATION.invoke(this, left, right); |
---|
430 | } |
---|
431 | } |
---|
432 | } |
---|
433 | } |
---|
434 | |
---|
435 | public static final SimpleProblemProducer ASTNode.CONNECT_WITH_INVALID_TYPE = |
---|
436 | new SimpleErrorProducer("CONNECT_WITH_INVALID_TYPE", ProblemKind.SEMANTIC, |
---|
437 | "Connecting to an instance of a non-connector type is not allowed"); |
---|
438 | public static final SimpleProblemProducer ASTNode.CONNECT_EXPANDABLE_AND_NON_EXPANDABLE_TYPE = |
---|
439 | new SimpleErrorProducer("CONNECT_EXPANDABLE_AND_NON_EXPANDABLE_TYPE", ProblemKind.SEMANTIC, |
---|
440 | "Connecting an expandable connector to a non-expandable connector is not allowed"); |
---|
441 | public static final SimpleProblemProducer ASTNode.TYPE_MISMATCH_IN_CONNECT = |
---|
442 | new SimpleErrorProducer("TYPE_MISMATCH_IN_CONNECT", ProblemKind.SEMANTIC, |
---|
443 | "Types of connected components do not match"); |
---|
444 | public static final ErrorProducerUnlessDisabled ASTNode.ARRAY_SIZE_MISMATCH_IN_CONNECT = |
---|
445 | new ErrorProducerUnlessDisabled("ARRAY_SIZE_MISMATCH_IN_CONNECT", ProblemKind.SEMANTIC, |
---|
446 | "Sizes do not match in connection, size of '%s' is %s and size of '%s' is %s"); |
---|
447 | |
---|
448 | public void FConnectClause.typeCheck(ErrorCheckType checkType) { |
---|
449 | InstAccess left = getConnector1(); |
---|
450 | InstAccess right = getConnector2(); |
---|
451 | boolean checkTypes = !isDisabled(); |
---|
452 | boolean expandableSame = true; |
---|
453 | for (InstAccess access = left; access != null; access = (access == left) ? right : null) { |
---|
454 | if (!access.isExpandableConnectorPart() && !access.isUnknown() && !access.myInstComponentDecl().myInstClass().isUnknown()) { |
---|
455 | if (!access.myInstComponentDecl().isConnector()) |
---|
456 | CONNECT_WITH_INVALID_TYPE.invoke(access); |
---|
457 | } else { |
---|
458 | checkTypes = false; |
---|
459 | } |
---|
460 | if (access.myInstComponentDecl().isExpandableConnector()) |
---|
461 | expandableSame = !expandableSame; |
---|
462 | } |
---|
463 | if (!expandableSame && !left.isUnknown() && !right.isUnknown()) |
---|
464 | CONNECT_EXPANDABLE_AND_NON_EXPANDABLE_TYPE.invoke(this); |
---|
465 | if (checkTypes) { |
---|
466 | InstComponentDecl leftComp = left.lookupEvaluatingIndices(); |
---|
467 | InstComponentDecl rightComp = right.lookupEvaluatingIndices(); |
---|
468 | if (!leftComp.connectableTo(rightComp)) { |
---|
469 | TYPE_MISMATCH_IN_CONNECT.invoke(this); |
---|
470 | } else if (!left.size().equivalent(right.size(), false)) { |
---|
471 | ARRAY_SIZE_MISMATCH_IN_CONNECT.invokeWithCondition(this, left.ndims() == right.ndims(), |
---|
472 | left, left.size(), right, right.size()); |
---|
473 | } |
---|
474 | } |
---|
475 | } |
---|
476 | |
---|
477 | // Generic typeCheck(checkType) that calls typeError() if type is unknown and no FExp child has unknown type |
---|
478 | public void FExp.typeCheck(ErrorCheckType checkType) { |
---|
479 | if (generateTypeError()) { |
---|
480 | for (FExp exp : childFExps()) |
---|
481 | if (exp.type().isUnknown()) |
---|
482 | return; |
---|
483 | typeError(checkType); |
---|
484 | } else { |
---|
485 | size().markAsStructuralParameter(checkType, this); |
---|
486 | } |
---|
487 | } |
---|
488 | |
---|
489 | syn boolean FExp.generateTypeError() = type().isUnknown(); |
---|
490 | eq FEqRelExp.generateTypeError() = super.generateTypeError() || |
---|
491 | (getLeft().type().isReal() || getRight().type().isReal()) && !inFunction(); |
---|
492 | |
---|
493 | public void InstIfExp.typeCheck(ErrorCheckType checkType) { |
---|
494 | if (!generateTypeError()) { |
---|
495 | if (!getThenExp().type().equivalentTo(getElseExp().type())) { |
---|
496 | getIfExp().markAsStructuralParameter(checkType); |
---|
497 | } |
---|
498 | } |
---|
499 | super.typeCheck(checkType); |
---|
500 | } |
---|
501 | |
---|
502 | public void Size.markAsStructuralParameter(ErrorCheckType checkType, FExp src) {} |
---|
503 | |
---|
504 | public void MutableSize.markAsStructuralParameter(ErrorCheckType checkType, FExp src) { |
---|
505 | if (src.errorCheckUnknownSize()) { |
---|
506 | for (int i = 0; i < ndims(); i++) { |
---|
507 | FExp exp = exps[i]; |
---|
508 | if (exp != null) { |
---|
509 | exp.markAsStructuralParameter(checkType); |
---|
510 | if (!exp.variability().parameterOrLess()) { |
---|
511 | ASTNode.NON_PARAMETER_SIZE_IN_EXPRESSION.invoke(src, exp, i, src); |
---|
512 | } |
---|
513 | } |
---|
514 | } |
---|
515 | } |
---|
516 | } |
---|
517 | |
---|
518 | syn boolean FExp.errorCheckUnknownSize() = !inFunction() && !allowUnknownSize(); |
---|
519 | |
---|
520 | syn boolean BaseNode.allowUnknownSize() = false; |
---|
521 | eq InstFunctionArgument.allowUnknownSize() = inAllowUnknownSize(); |
---|
522 | eq FIfExp.allowUnknownSize() = inAllowUnknownSize(); |
---|
523 | eq InstFunctionCall.allowUnknownSize() = inAllowUnknownSize() && callsExternal(); |
---|
524 | eq FFunctionCall.allowUnknownSize() = inAllowUnknownSize() && callsExternal(); |
---|
525 | |
---|
526 | inh boolean BaseNode.inAllowUnknownSize(); |
---|
527 | eq BaseNode.getChild().inAllowUnknownSize() = allowUnknownSize(); |
---|
528 | eq InstFunctionCall.getChild().inAllowUnknownSize() = allowUnknownSize() || callsExternal(); |
---|
529 | eq FFunctionCall.getChild().inAllowUnknownSize() = allowUnknownSize() || callsExternal(); |
---|
530 | |
---|
531 | class FFunctionDecl { |
---|
532 | public enum FunctionType { |
---|
533 | EXTERNAL, LOADRESOURCE; |
---|
534 | |
---|
535 | public boolean containsFunction(CommonCallable cc) { |
---|
536 | if (this == EXTERNAL) { |
---|
537 | return cc.isExternalFunction(); |
---|
538 | } else { |
---|
539 | return cc.containsFunction(this); |
---|
540 | } |
---|
541 | } |
---|
542 | } |
---|
543 | } |
---|
544 | |
---|
545 | interface CommonCallable { |
---|
546 | public boolean containsFunction(FFunctionDecl.FunctionType ft); |
---|
547 | public boolean isExternalFunction(); |
---|
548 | } |
---|
549 | |
---|
550 | syn boolean InstPartialFunction.isExternalFunction() = false; |
---|
551 | syn boolean FFunctionVariable.isExternalFunction() = false; |
---|
552 | |
---|
553 | syn boolean InstClassDecl.isExternalFunction() = findFunctionExternal() != null; |
---|
554 | syn boolean FFunctionDecl.isExternalFunction() = getFirstExternalStmt() != null; |
---|
555 | |
---|
556 | syn FExternalStmt FFunctionDecl.getFirstExternalStmt() { |
---|
557 | for (FStatement stmt : getFAlgorithm().getFStatements()) { |
---|
558 | if (stmt.isExternalStatement()) { |
---|
559 | return (FExternalStmt) stmt; |
---|
560 | } |
---|
561 | } |
---|
562 | return null; |
---|
563 | } |
---|
564 | |
---|
565 | syn boolean FStatement.isExternalStatement() = false; |
---|
566 | eq FExternalStmt.isExternalStatement() = true; |
---|
567 | |
---|
568 | syn boolean FAbstractFunctionCall.callsExternal() = |
---|
569 | FFunctionDecl.FunctionType.EXTERNAL.containsFunction(myCommonCallable()); |
---|
570 | syn boolean FAbstractFunctionCall.callsLoadResource() = |
---|
571 | FFunctionDecl.FunctionType.LOADRESOURCE.containsFunction(myCommonCallable()); |
---|
572 | |
---|
573 | syn boolean ASTNode.containsFunction(FFunctionDecl.FunctionType ft) { |
---|
574 | for (ASTNode n : this) { |
---|
575 | if (n.containsFunction(ft)) { |
---|
576 | return true; |
---|
577 | } |
---|
578 | } |
---|
579 | return false; |
---|
580 | } |
---|
581 | |
---|
582 | @Override |
---|
583 | syn boolean InstNode.containsFunction(FFunctionDecl.FunctionType ft) = |
---|
584 | getInstComponentDecls().containsFunction(ft) || getInstExtendss().containsFunction(ft) || |
---|
585 | getFAbstractEquations().containsFunction(ft) || super.containsFunction(ft); |
---|
586 | |
---|
587 | eq InstComponentDecl.containsFunction(FFunctionDecl.FunctionType ft) = |
---|
588 | (hasInstModification() && getInstModification().containsFunction(ft)) || super.containsFunction(ft); |
---|
589 | eq InstValueModification.containsFunction(FFunctionDecl.FunctionType ft) = |
---|
590 | getFExp().containsFunction(ft) || super.containsFunction(ft); |
---|
591 | eq InstFunctionCall.containsFunction(FFunctionDecl.FunctionType ft) = |
---|
592 | ft.containsFunction(myCommonCallable()) || super.containsFunction(ft); |
---|
593 | eq FFunctionCall.containsFunction(FFunctionDecl.FunctionType ft) = |
---|
594 | ft.containsFunction(myCommonCallable()) || super.containsFunction(ft); |
---|
595 | eq FLoadResource.containsFunction(FFunctionDecl.FunctionType ft) = |
---|
596 | ft == FFunctionDecl.FunctionType.LOADRESOURCE || super.containsFunction(ft); |
---|
597 | |
---|
598 | syn lazy boolean InstClassDecl.containsFunction(FFunctionDecl.FunctionType ft) circular [false] = |
---|
599 | super.containsFunction(ft); |
---|
600 | eq InstSimpleShortClassDecl.containsFunction(FFunctionDecl.FunctionType ft) = |
---|
601 | actualInstClass().containsFunction(ft); |
---|
602 | |
---|
603 | public static final ErrorProducerUnlessDisabled ASTNode.NON_PARAMETER_SIZE_IN_EXPRESSION = |
---|
604 | new ErrorProducerUnlessDisabled("NON_PARAMETER_SIZE_IN_EXPRESSION", ProblemKind.COMPLIANCE, |
---|
605 | "Non-parameter expression sizes not supported, '%s', dimension %d in '%s'"); |
---|
606 | |
---|
607 | @Override |
---|
608 | public void FLoadResource.typeCheck(ErrorCheckType checkType) { |
---|
609 | super.complianceCheck(checkType); |
---|
610 | getFExp().forceVariability(checkType, Variability.LOADRESOURCEPARAMETER); |
---|
611 | } |
---|
612 | |
---|
613 | public class FExp { |
---|
614 | public static class ExpTypeErrorProducer extends AbstractErrorProducerUnlessDisabled<ReporterNode> { |
---|
615 | private final String message; |
---|
616 | |
---|
617 | public ExpTypeErrorProducer(String identifier, String message) { |
---|
618 | super(identifier, ProblemKind.SEMANTIC); |
---|
619 | this.message = message; |
---|
620 | } |
---|
621 | |
---|
622 | public void invoke(FExp node) { |
---|
623 | StringBuilder buf = new StringBuilder(message); |
---|
624 | buf.append(": "); |
---|
625 | buf.append(node); |
---|
626 | for (FExp exp : node.childFExps()) { |
---|
627 | buf.append("\n type of '"); |
---|
628 | buf.append(exp); |
---|
629 | buf.append("' is "); |
---|
630 | buf.append(exp.type()); |
---|
631 | } |
---|
632 | super.invokeWithCondition(node, node.typeErrorOnlyLengths(), buf.toString()); |
---|
633 | } |
---|
634 | |
---|
635 | @Override |
---|
636 | public String description() { |
---|
637 | return message; |
---|
638 | } |
---|
639 | |
---|
640 | } |
---|
641 | } |
---|
642 | |
---|
643 | public static final FExp.ExpTypeErrorProducer ASTNode.TYPE_MISMATCH_IN_EXPRESSION = |
---|
644 | new FExp.ExpTypeErrorProducer("TYPE_MISMATCH_IN_EXPRESSION", "Type error in expression"); |
---|
645 | |
---|
646 | public void FExp.typeError(ErrorCheckType checkType) { |
---|
647 | TYPE_MISMATCH_IN_EXPRESSION.invoke(this); |
---|
648 | } |
---|
649 | |
---|
650 | /** |
---|
651 | * Check if type error is only in array lengths. |
---|
652 | */ |
---|
653 | syn boolean FExp.typeErrorOnlyLengths() = typeErrorOnlyLengths(childFExps()); |
---|
654 | eq FAbstractCat.typeErrorOnlyLengths() = typeErrorOnlyLengths(getFExps()); |
---|
655 | |
---|
656 | /** |
---|
657 | * Check if type error is only in array lengths. |
---|
658 | */ |
---|
659 | syn boolean FExp.typeErrorOnlyLengths(Iterable<FExp> exps) { |
---|
660 | FType first = null; |
---|
661 | for (FExp exp : exps) { |
---|
662 | FType cur = exp.type(); |
---|
663 | if (first == null) { |
---|
664 | first = cur; |
---|
665 | } else if (!first.equivalentExceptLengths(cur)) { |
---|
666 | return false; |
---|
667 | } |
---|
668 | } |
---|
669 | return true; |
---|
670 | } |
---|
671 | |
---|
672 | /** |
---|
673 | * The message to use in default type error. |
---|
674 | */ |
---|
675 | public static final FExp.ExpTypeErrorProducer ASTNode.EQUALITY_COMPARISON_OF_REAL = |
---|
676 | new FExp.ExpTypeErrorProducer("EQUALITY_COMPARISON_OF_REALS", "Equality comparisons do not allow real operands"); |
---|
677 | |
---|
678 | @Override |
---|
679 | public void FEqRelExp.typeError(ErrorCheckType checkType) { |
---|
680 | if ((getLeft().type().isRealScalar() || getRight().type().isRealScalar()) && !inFunction()) { |
---|
681 | EQUALITY_COMPARISON_OF_REAL.invoke(this); |
---|
682 | } else { |
---|
683 | super.typeError(checkType); |
---|
684 | } |
---|
685 | } |
---|
686 | |
---|
687 | public void FLinspace.typeCheck(ErrorCheckType checkType) { |
---|
688 | getN().markAsStructuralParameter(checkType); |
---|
689 | super.typeCheck(checkType); |
---|
690 | } |
---|
691 | |
---|
692 | public void FLinspace.typeError(ErrorCheckType checkType) { |
---|
693 | boolean badVar = !getN().variability().fixedParameterOrLess(); |
---|
694 | boolean canCeval = getN().canCeval(); |
---|
695 | boolean badVal = canCeval && getN().ceval().intValue() < 2; |
---|
696 | if (badVar || !canCeval || badVal) { |
---|
697 | String msg = "Third argument of linspace() must be a scalar parameter Integer expression that is greater than 1"; |
---|
698 | if (badVar) |
---|
699 | error("%s\n '%s' is of %s variability", msg, getN(), getN().variability().toStringLiteral()); |
---|
700 | else if (canCeval && !lockBranch(checkType)) |
---|
701 | errorUnlessDisabled("%s\n '%s' evaluates to %d", msg, getN(), getN().ceval().intValue()); |
---|
702 | } else { |
---|
703 | super.typeError(checkType); |
---|
704 | } |
---|
705 | } |
---|
706 | |
---|
707 | public void FIdentity.typeCheck(ErrorCheckType checkType) { |
---|
708 | getFExp().markAsStructuralParameter(checkType); |
---|
709 | super.typeCheck(checkType); |
---|
710 | } |
---|
711 | |
---|
712 | public void FIdentity.typeError(ErrorCheckType checkType) { |
---|
713 | if (!getFExp().variability().parameterOrLess()) |
---|
714 | error("Argument of identity() must be a scalar parameter Integer expression\n '%s' is of %s variability", |
---|
715 | getFExp(), getFExp().variability().toStringLiteral()); |
---|
716 | else |
---|
717 | super.typeError(checkType); |
---|
718 | } |
---|
719 | |
---|
720 | public void FSizeExp.typeCheck(ErrorCheckType checkType) { |
---|
721 | if (hasDim()) |
---|
722 | getDim().markAsStructuralParameter(checkType); |
---|
723 | super.typeCheck(checkType); |
---|
724 | } |
---|
725 | |
---|
726 | public void FSizeExp.typeError(ErrorCheckType checkType) { |
---|
727 | if (hasDim()) { |
---|
728 | if (!getDim().type().isIntegerScalar()) |
---|
729 | return; // Error is reported for argument in this case |
---|
730 | boolean badVar = !getDim().variability().parameterOrLess(); |
---|
731 | boolean canCeval = getDim().canCeval(); |
---|
732 | int dimVal = canCeval ? getDim().ceval().intValue() : 1; |
---|
733 | int ndims = getFExp().ndims(); |
---|
734 | if (badVar || !canCeval || dimVal < 1 || dimVal > ndims) { |
---|
735 | String msg = "Second argument of size() must be a scalar parameter Integer expression that evaluates to a valid dimension of the first argument"; |
---|
736 | if (badVar) |
---|
737 | error("%s\n '%s' is of %s variability", msg, getDim(), getDim().variability().toStringLiteral()); |
---|
738 | else if (canCeval) |
---|
739 | error("%s\n '%s' evaluates to %d, and '%s' has %d dimensions", msg, getDim(), dimVal, getFExp(), ndims); |
---|
740 | return; |
---|
741 | } |
---|
742 | } |
---|
743 | super.typeError(checkType); |
---|
744 | } |
---|
745 | |
---|
746 | public void CommonAccess.typeError(ErrorCheckType checkType, CommonAccessExp access) { |
---|
747 | access.typeError(checkType); |
---|
748 | } |
---|
749 | |
---|
750 | public void InstAccess.typeError(ErrorCheckType checkType, CommonAccessExp access) { |
---|
751 | typeError(); |
---|
752 | } |
---|
753 | |
---|
754 | public void InstAccess.typeError() { |
---|
755 | typeError(this); |
---|
756 | } |
---|
757 | |
---|
758 | protected void InstAccess.typeError(InstAccess top) {} |
---|
759 | |
---|
760 | protected void InstDot.typeError(InstAccess top) { |
---|
761 | getLastInstAccess().typeError(top); |
---|
762 | } |
---|
763 | |
---|
764 | protected void InstGlobalAccess.typeError(InstAccess top) { |
---|
765 | getInstAccess().typeError(top); |
---|
766 | } |
---|
767 | |
---|
768 | protected void InstComponentAccess.typeError(InstAccess top) { |
---|
769 | InstComponentDecl icd = myInstComponentDecl(); |
---|
770 | if (!icd.isUnknown() && !icd.myInstClass().isUnknown() && !inCardinality()) { |
---|
771 | if (!icd.isPrimitive() && !icd.isRecord()) { |
---|
772 | top.error("Accesses to composite components other than records are not allowed: " + top.name()); |
---|
773 | } |
---|
774 | } |
---|
775 | } |
---|
776 | |
---|
777 | protected void InstComponentArrayAccess.typeError(InstAccess top) { |
---|
778 | InstComponentDecl icd = myInstComponentDecl(); |
---|
779 | if (!icd.isUnknown() && !icd.myInstClass().isUnknown() && !inCardinality()) { |
---|
780 | if (!icd.isPrimitive() && !icd.isRecord()) { |
---|
781 | top.error("Accesses to composite components other than records are not allowed: " + top.name()); |
---|
782 | } |
---|
783 | } |
---|
784 | } |
---|
785 | |
---|
786 | inh boolean InstAccess.inCardinality(); |
---|
787 | eq FCardinality.getChild().inCardinality() = true; |
---|
788 | eq InstNode.getChild().inCardinality() = false; |
---|
789 | eq Root.getChild().inCardinality() = false; |
---|
790 | |
---|
791 | protected void InstClassAccess.typeError(InstAccess top) { |
---|
792 | if (!isComponentSizeClass() || !isInstComponentSize()) |
---|
793 | top.error("Illegal access to class in expression: " + top.name()); |
---|
794 | } |
---|
795 | |
---|
796 | public void InstIfExp.typeError(ErrorCheckType checkType) { |
---|
797 | FType thenType = getThenExp().type(); |
---|
798 | FType elseType = getElseExp().type(); |
---|
799 | FType scalar = thenType.scalarType().typePromotion(elseType.scalarType()); |
---|
800 | |
---|
801 | if (!getIfExp().isOKTestExp()) { |
---|
802 | getIfExp().error("Test expression of if expression must be scalar boolean:\n %s is %s", |
---|
803 | getIfExp(), getIfExp().type()); |
---|
804 | } else if (thenType.ndims() != elseType.ndims()) { |
---|
805 | error("Branches of if expression have different number of array dimensions:" + |
---|
806 | "\n %s has size %s\n %s has size %s", |
---|
807 | getThenExp(), thenType.size(), getElseExp(), elseType.size()); |
---|
808 | } else if (scalar.isUnknown()) { |
---|
809 | error("Branches of if expression have incompatible types:\n %s is %s\n %s is %s", |
---|
810 | getThenExp(), thenType, getElseExp(), elseType); |
---|
811 | } else { |
---|
812 | if (isParameterIf()) |
---|
813 | error("Failed to evaluate test expression in if expression with branches that have different array sizes:" + |
---|
814 | "\n %s has size %s\n %s has size %s", |
---|
815 | getThenExp(), thenType.size(), getElseExp(), elseType.size()); |
---|
816 | else |
---|
817 | error("If expression with branches that have different array sizes must have parameter test expression:" + |
---|
818 | "\n %s has size %s\n %s has size %s", |
---|
819 | getThenExp(), thenType.size(), getElseExp(), elseType.size()); |
---|
820 | } |
---|
821 | } |
---|
822 | |
---|
823 | public void CommonAccessExp.typeCheck(ErrorCheckType checkType) { |
---|
824 | if (!getAccess().isUnknown() && type().isUnknown() && !accessToModelOK()) |
---|
825 | getAccess().typeError(checkType, this); |
---|
826 | } |
---|
827 | |
---|
828 | public void CommonAccess.typeCheck(ErrorCheckType checkType) { |
---|
829 | if (inAlgorithm() && useIsAssignment()) { |
---|
830 | if (variability().constantVariability()) { |
---|
831 | error("Assignments to constants is not allowed in algorithms"); |
---|
832 | } else if (variability().parameterVariability()) { |
---|
833 | if (isForIndex()) { |
---|
834 | error("Can not assign a value to a for loop index"); |
---|
835 | } else if (!(myFAlgorithm().getType().isInitial())) { |
---|
836 | error("Assignments to parameters in algorithms is only allowed in initial algorithms"); |
---|
837 | } |
---|
838 | } |
---|
839 | } |
---|
840 | } |
---|
841 | |
---|
842 | inh boolean CommonAccessExp.accessToModelOK(); |
---|
843 | inh boolean InstFunctionArgument.accessToModelOK(); |
---|
844 | eq BaseNode.getChild().accessToModelOK() = false; |
---|
845 | eq InstFunctionArgument.getChild().accessToModelOK() = accessToModelOK(); |
---|
846 | eq FSizeExp.getFExp().accessToModelOK() = true; |
---|
847 | eq FSizeExp.getOriginalArg(int i).accessToModelOK() = i == 0; |
---|
848 | |
---|
849 | |
---|
850 | /** |
---|
851 | * Check if the FExp of this FIterExp must be scalar. |
---|
852 | */ |
---|
853 | inh boolean FIterExp.iterExpMustBeScalar(); |
---|
854 | eq FExp.getChild().iterExpMustBeScalar() = false; |
---|
855 | eq Root.getChild().iterExpMustBeScalar() = false; |
---|
856 | eq InstNode.getChild().iterExpMustBeScalar() = false; |
---|
857 | eq FMinMaxExp.getChild().iterExpMustBeScalar() = true; |
---|
858 | // TODO: Add product() when it is implemented |
---|
859 | |
---|
860 | public void FMulExp.typeCheck(ErrorCheckType checkType) { |
---|
861 | if (type().isOperatorRecord() && !isElementWise()) { |
---|
862 | int left = getLeft().size().get(1); |
---|
863 | int inner = (left == Size.UNKNOWN) ? getRight().size().get(0) : left; |
---|
864 | if ((inner == 0 || inner == Size.UNKNOWN) && type().matchOverloadedZero() == null) |
---|
865 | error("Matrix multiplication of operator records with an inner dimension of 0 or : requires that an '0' operator is defined"); |
---|
866 | } |
---|
867 | super.typeCheck(checkType); |
---|
868 | } |
---|
869 | |
---|
870 | public void FIterExp.typeCheck(ErrorCheckType checkType) { |
---|
871 | super.typeCheck(checkType); |
---|
872 | if (iterExpMustBeScalar() && !getFExp().type().isUnknown() && getFExp().ndims() != 0) |
---|
873 | error("The expression of a reduction-expression must be scalar, except for sum(): " + |
---|
874 | getFExp() + " has " + getFExp().ndims() + " dimension(s)"); |
---|
875 | } |
---|
876 | |
---|
877 | public void FStreamBuiltIn.typeCheck(ErrorCheckType checkType) { |
---|
878 | if (!getFExp().isAccessToStream()) |
---|
879 | error("Argument of " + builtInName() + "() must be a stream variable"); |
---|
880 | } |
---|
881 | |
---|
882 | /** |
---|
883 | * Returns true if this expression can be interpreted as some form of Access |
---|
884 | */ |
---|
885 | syn boolean FExp.isAccessLikeExp() = false; |
---|
886 | eq CommonAccessExp.isAccessLikeExp() = true; |
---|
887 | |
---|
888 | syn boolean FExp.isAccess() = false; |
---|
889 | eq CommonAccessExp.isAccess()= true; |
---|
890 | syn CommonAccess FExp.asCommonAccess() { |
---|
891 | throw new UnsupportedOperationException("asCommonAccess() is not supported for class type " + getClass().getSimpleName()); |
---|
892 | } |
---|
893 | eq CommonAccessExp.asCommonAccess() = getAccess(); |
---|
894 | |
---|
895 | syn CommonAccessExp FExp.asCommonAccessExp() { |
---|
896 | throw new UnsupportedOperationException("asCommonAccessExp() is not supported for class type " + getClass().getSimpleName()); |
---|
897 | } |
---|
898 | eq CommonAccessExp.asCommonAccessExp() = this; |
---|
899 | |
---|
900 | syn FAccessExp FExp.asFAccessExp() { |
---|
901 | throw new UnsupportedOperationException("asFAccessExp() is not supported for class type " + getClass().getSimpleName()); |
---|
902 | } |
---|
903 | eq FAccessExp.asFAccessExp() = this; |
---|
904 | |
---|
905 | syn boolean CommonAccess.isInstAccess() = false; |
---|
906 | eq InstAccess.isInstAccess() = true; |
---|
907 | syn boolean CommonAccess.isFAccess() = false; |
---|
908 | eq FAccess.isFAccess() = true; |
---|
909 | |
---|
910 | syn InstAccess FExp.asInstAccess() { |
---|
911 | throw new UnsupportedOperationException(); |
---|
912 | } |
---|
913 | eq InstAccessExp.asInstAccess() = getInstAccess(); |
---|
914 | |
---|
915 | syn InstAccess CommonAccess.asInstAccess() { |
---|
916 | throw new UnsupportedOperationException(); |
---|
917 | } |
---|
918 | eq InstAccess.asInstAccess() = this; |
---|
919 | |
---|
920 | syn boolean FExp.isAccessToStream() = false; |
---|
921 | eq CommonAccessExp.isAccessToStream()= getAccess().isAccessToStream(); |
---|
922 | |
---|
923 | syn boolean CommonAccess.isAccessToStream() = false; |
---|
924 | eq InstAccess.isAccessToStream() = myInstComponentDecl().isStream(); |
---|
925 | |
---|
926 | |
---|
927 | |
---|
928 | public void InstForIndexWithExp.typeCheck(ErrorCheckType checkType) { |
---|
929 | if (!getFExp().type().isUnknown() && getFExp().ndims() != 1) |
---|
930 | error("The expression of for index " + name() + " must be a vector expression: " + |
---|
931 | getFExp() + " has " + getFExp().ndims() + " dimension(s)"); |
---|
932 | } |
---|
933 | |
---|
934 | public void InstForIndexNoExp.typeCheck(ErrorCheckType checkType) { |
---|
935 | hasFExp(); // Force eval of NTA, thus checking if a consistent range can be computed |
---|
936 | } |
---|
937 | |
---|
938 | public static final SimpleErrorProducer InstForIndexNoExp.IMPLICIT_FOR_RANGE_NON_INTEGER = |
---|
939 | new SimpleErrorProducer("IMPLICIT_FOR_RANGE_NON_INTEGER", ProblemKind.COMPLIANCE, |
---|
940 | "Non-integer for iteration range not supported"); |
---|
941 | |
---|
942 | public static final SimpleErrorProducer InstForIndexNoExp.IMPLICIT_FOR_RANGE_INCONSISTENT = |
---|
943 | new SimpleErrorProducer("IMPLICIT_FOR_RANGE_INCONSISTENT", ProblemKind.SEMANTIC, |
---|
944 | "For index with implicit iteration range used for inconsistent sizes, here used for size %s and earlier for size %s"); |
---|
945 | |
---|
946 | public static final SimpleErrorProducer InstForIndexNoExp.IMPLICIT_FOR_RANGE_NOT_USED = |
---|
947 | new SimpleErrorProducer("IMPLICIT_FOR_RANGE_NOT_USED", ProblemKind.SEMANTIC, |
---|
948 | "For index with implicit iteration range must be used as array index"); |
---|
949 | |
---|
950 | // TODO: handle other index types than integer (see #3597) |
---|
951 | syn lazy Opt<FExp> InstForIndexNoExp.getFExpOpt() { |
---|
952 | Size size = null; |
---|
953 | for (FExpSubscript use : mySubscriptUses()) { |
---|
954 | Size useSize = use.mySize(); |
---|
955 | if (!use.myIndexType().isInteger()) { |
---|
956 | IMPLICIT_FOR_RANGE_NON_INTEGER.invoke(use); |
---|
957 | } |
---|
958 | if (size == null) { |
---|
959 | size = useSize; |
---|
960 | } else if (!size.equivalent(useSize, true)) { |
---|
961 | IMPLICIT_FOR_RANGE_INCONSISTENT.invoke(use, useSize, size); |
---|
962 | } |
---|
963 | } |
---|
964 | if (size == null) { |
---|
965 | IMPLICIT_FOR_RANGE_NOT_USED.invoke(this); |
---|
966 | return new Opt(); |
---|
967 | } else { |
---|
968 | return new Opt(size.createRangeExp(0)); |
---|
969 | } |
---|
970 | } |
---|
971 | |
---|
972 | syn lazy Collection<FExpSubscript> InstForIndexNoExp.mySubscriptUses() = mySubscriptUses(name()); |
---|
973 | |
---|
974 | inh Collection<FExpSubscript> InstForIndexNoExp.mySubscriptUses(String name); |
---|
975 | eq InstForClauseE.getInstForIndex(int i).mySubscriptUses(String name) = collectSubscriptUses(name); |
---|
976 | eq InstForStmt.getInstForIndex(int i).mySubscriptUses(String name) = collectSubscriptUses(name); |
---|
977 | eq FIterExp.getForIndex(int i).mySubscriptUses(String name) = collectSubscriptUses(name); |
---|
978 | |
---|
979 | public Collection<FExpSubscript> ASTNode.collectSubscriptUses(String name) { |
---|
980 | Collection<FExpSubscript> nodes = new ArrayList<FExpSubscript>(); |
---|
981 | collectSubscriptUses(name, nodes); |
---|
982 | return nodes; |
---|
983 | } |
---|
984 | |
---|
985 | public void ASTNode.collectSubscriptUses(String name, Collection<FExpSubscript> nodes) { |
---|
986 | for (ASTNode n : this) { |
---|
987 | n.collectSubscriptUses(name, nodes); |
---|
988 | } |
---|
989 | } |
---|
990 | |
---|
991 | public void FExpSubscript.collectSubscriptUses(String name, Collection<FExpSubscript> nodes) { |
---|
992 | if (getFExp().isIdentifier(name)) { |
---|
993 | nodes.add(this); |
---|
994 | } |
---|
995 | super.collectSubscriptUses(name, nodes); |
---|
996 | } |
---|
997 | |
---|
998 | public void FSubscript.typeCheckAsSize(ErrorCheckType checkType) { |
---|
999 | if (ndims() > 0) { |
---|
1000 | error("Array size must be scalar expression: " + toString()); |
---|
1001 | } else if (!type().isUnknown() && !canBeComponentSize()) { |
---|
1002 | error("Array size must be Integer expression, Boolean type or enumeration type: " + toString()); |
---|
1003 | } else if (!inFunction()) { |
---|
1004 | if (!variability().parameterOrLess()) { |
---|
1005 | error("Array size must be constant or parameter: " + toString()); |
---|
1006 | } else if (!checkType.allowIncompleteSizes()) { |
---|
1007 | boolean ok = false; |
---|
1008 | try { |
---|
1009 | ok = ceval().hasIntValue(); |
---|
1010 | } catch (ConstantEvaluationException e) {} |
---|
1011 | if (!ok) { |
---|
1012 | error("Could not evaluate array size expression: " + toString()); |
---|
1013 | } |
---|
1014 | } |
---|
1015 | } |
---|
1016 | } |
---|
1017 | |
---|
1018 | public void FSubscript.typeCheckAsIndex(ErrorCheckType checkType) { |
---|
1019 | if (ndims() > 1) { |
---|
1020 | error("Array index must be scalar or vector expression: " + toString()); |
---|
1021 | } else if (!type().isUnknown() && !type().canBeIndex()) { |
---|
1022 | error("Array index must be Integer, Boolean, or enumeration expression: " + toString()); |
---|
1023 | } else if (!type().isUnknown() && !myIndexType().isUnknown() && !type().scalarType().typeCompatible(myIndexType())) { |
---|
1024 | error("Expected array index of type '%s' found '%s'", myIndexType().name(), type().scalarType().name()); |
---|
1025 | } else if (!inFunction()) { |
---|
1026 | if (!variability().fixedParameterOrLess()) { |
---|
1027 | warning("Variable array index in equation can result in slow simulation time"); |
---|
1028 | } else if (!inUnknownAccess() && !mySize().isUnknown()) { |
---|
1029 | typeCheckOutOfBounds(checkType); |
---|
1030 | } |
---|
1031 | } |
---|
1032 | } |
---|
1033 | |
---|
1034 | public void FSubscript.typeCheckOutOfBounds(ErrorCheckType checkType) {} |
---|
1035 | public void FExpSubscript.typeCheckOutOfBounds(ErrorCheckType checkType) { |
---|
1036 | if (!reportedOutOfBound) { |
---|
1037 | // Check array bounds |
---|
1038 | // TODO: Perform bounds check in functions if index has parameter variability or lower? |
---|
1039 | try { |
---|
1040 | int max = mySize().get(0); |
---|
1041 | for (FExp e : getFExp().getArray().iterable()) { |
---|
1042 | CValue cval = e.ceval(); |
---|
1043 | if (cval.hasIntValue()) { |
---|
1044 | int i = cval.intValue(); |
---|
1045 | if (i < 1 || i > max) { |
---|
1046 | if (!lockBranch(checkType)) { |
---|
1047 | errorUnlessDisabled("Array index out of bounds: " + i + |
---|
1048 | ", index expression: " + getFExp()); |
---|
1049 | } |
---|
1050 | reportedOutOfBound = true; |
---|
1051 | return; |
---|
1052 | } |
---|
1053 | } |
---|
1054 | } |
---|
1055 | } catch (ConstantEvaluationException e) { |
---|
1056 | } |
---|
1057 | } |
---|
1058 | } |
---|
1059 | public void FIntegerSubscript.typeCheckOutOfBounds(ErrorCheckType checkType) { |
---|
1060 | int max = mySize().get(0); |
---|
1061 | int i = getValue(); |
---|
1062 | if ((i < 1 || i > max) && !lockBranch(checkType)) { |
---|
1063 | errorUnlessDisabled("Array index out of bounds: " + i + |
---|
1064 | ", index expression: " + i); |
---|
1065 | } |
---|
1066 | } |
---|
1067 | |
---|
1068 | syn FType FSubscript.myIndexType() = myIndexType(myDim()); |
---|
1069 | inh FType FSubscript.myIndexType(int i); |
---|
1070 | eq Root.getChild().myIndexType(int i) = fUnknownType(); |
---|
1071 | eq InstArrayAccess.getFArraySubscripts().myIndexType(int i) = fUnknownType(); |
---|
1072 | eq InstComponentArrayAccess.getFArraySubscripts().myIndexType(int i) = myInstComponentDecl().myIndexType(i); |
---|
1073 | |
---|
1074 | syn FType InstComponentDecl.myIndexType(int dim) { |
---|
1075 | FArraySubscripts fas = getFArraySubscripts(); |
---|
1076 | if (fas != null && fas.ndims() > dim) |
---|
1077 | return fas.subscript(dim).type().scalarType(); |
---|
1078 | else |
---|
1079 | return fUnknownType(); |
---|
1080 | } |
---|
1081 | |
---|
1082 | private boolean FExpSubscript.reportedOutOfBound = false; |
---|
1083 | |
---|
1084 | |
---|
1085 | public void FSubscript.typeCheck(ErrorCheckType checkType) { |
---|
1086 | if (isInstComponentSize()) |
---|
1087 | typeCheckAsSize(checkType); |
---|
1088 | else |
---|
1089 | typeCheckAsIndex(checkType); |
---|
1090 | } |
---|
1091 | public void FColonSubscript.typeCheck(ErrorCheckType checkType) {} |
---|
1092 | |
---|
1093 | inh boolean FSubscript.inUnknownAccess(); |
---|
1094 | eq FAccess.getChild().inUnknownAccess() = myFV().isUnknown(); |
---|
1095 | eq InstScalarAccess.getChild().inUnknownAccess() = myInstComponentDecl().isUnknown(); |
---|
1096 | eq InstArrayAccess.getChild().inUnknownAccess() = myInstComponentDecl().isUnknown(); |
---|
1097 | eq FlatRoot.getChild().inUnknownAccess() = false; |
---|
1098 | eq InstRoot.getChild().inUnknownAccess() = false; |
---|
1099 | |
---|
1100 | syn boolean FExp.canBeComponentSize() = type().isInteger(); |
---|
1101 | eq CommonAccessExp.canBeComponentSize()= type().isInteger() || getAccess().isComponentSizeClass(); |
---|
1102 | |
---|
1103 | syn boolean FSubscript.canBeComponentSize() = true; |
---|
1104 | eq FExpSubscript.canBeComponentSize() = getFExp().canBeComponentSize(); |
---|
1105 | |
---|
1106 | syn boolean CommonAccess.isComponentSizeClass() = false; |
---|
1107 | eq InstAccess.isComponentSizeClass() = myInstClassDecl().isComponentSizeClass(); |
---|
1108 | |
---|
1109 | syn boolean InstClassDecl.isComponentSizeClass() = isBoolean(); |
---|
1110 | eq InstEnumClassDecl.isComponentSizeClass() = true; |
---|
1111 | |
---|
1112 | inh boolean InstClassAccess.isInstComponentSize(); |
---|
1113 | inh boolean CommonAccessExp.isInstComponentSize(); |
---|
1114 | inh boolean FSubscript.isInstComponentSize(); |
---|
1115 | inh boolean FArraySubscripts.isInstComponentSize(); |
---|
1116 | eq InstComponentDecl.getLocalFArraySubscripts().isInstComponentSize() = true; |
---|
1117 | eq InstComponentDecl.getFArraySubscripts().isInstComponentSize() = true; |
---|
1118 | eq InstShortClassDecl.getFArraySubscripts().isInstComponentSize() = true; |
---|
1119 | eq InstAccess.getChild().isInstComponentSize() = false; |
---|
1120 | eq FAccessPart.getChild().isInstComponentSize() = false; |
---|
1121 | eq CommonAccess.getChild().isInstComponentSize() = false; |
---|
1122 | eq FExp.getChild().isInstComponentSize() = false; |
---|
1123 | eq CommonAccessExp.getChild().isInstComponentSize() = isInstComponentSize(); |
---|
1124 | eq FAbstractVariable.getChild().isInstComponentSize() = false; |
---|
1125 | eq FAbstractEquation.getChild().isInstComponentSize() = false; |
---|
1126 | eq InstNode.getChild().isInstComponentSize() = false; |
---|
1127 | eq FlatRoot.getChild().isInstComponentSize() = false; |
---|
1128 | |
---|
1129 | syn boolean FArraySubscripts.isFullSize() = false; |
---|
1130 | eq FArrayExpSubscripts.isFullSize() { |
---|
1131 | for (FSubscript fs : getFSubscripts()) |
---|
1132 | if (!fs.isColon()) |
---|
1133 | return false; |
---|
1134 | return true; |
---|
1135 | } |
---|
1136 | |
---|
1137 | public void FAssignStmt.typeCheck(ErrorCheckType checkType) { |
---|
1138 | FType left = getLeft().type(); |
---|
1139 | FType right = getRight().type(); |
---|
1140 | if (!left.isUnknown() && !right.isUnknown()) { |
---|
1141 | if (!left.typeCompatible(right, true)) { |
---|
1142 | if (left.typeCompatibleExceptLengths(right)) { |
---|
1143 | // TODO: should use lockBranch() here as well, but no support yet |
---|
1144 | errorUnlessDisabled("The array sizes of right and left hand side of assignment are not compatible, " + |
---|
1145 | "size of left-hand side is %s, and size of right-hand side is %s", left.size(), right.size()); |
---|
1146 | } else { |
---|
1147 | error("The right and left expression types of assignment are not compatible, " + |
---|
1148 | "type of left-hand side is %s, and type of right-hand side is %s", left, right); |
---|
1149 | } |
---|
1150 | } |
---|
1151 | } |
---|
1152 | } |
---|
1153 | |
---|
1154 | public void FWhileStmt.typeCheck(ErrorCheckType checkType) { |
---|
1155 | if (!getTest().type().isUnknown() && !fBooleanScalarType().typeCompatible(getTest().type())) |
---|
1156 | error("Type of test expression of while statement is not Boolean"); |
---|
1157 | } |
---|
1158 | |
---|
1159 | public void FIfClause.typeCheck(ErrorCheckType checkType) { |
---|
1160 | if (!getTest().type().isUnknown() && !fBooleanScalarType().typeCompatible(getTest().type())) |
---|
1161 | error("Type of test expression of if statement is not Boolean"); |
---|
1162 | } |
---|
1163 | |
---|
1164 | public void FWhenClause.typeCheck(ErrorCheckType checkType) { |
---|
1165 | if (!getTest().type().isUnknown()) { |
---|
1166 | if (!getTest().type().isBoolean() || getTest().type().ndims() > 1) |
---|
1167 | error("Test expression of when statement isn't Boolean scalar or vector expression"); |
---|
1168 | } |
---|
1169 | } |
---|
1170 | |
---|
1171 | public void FIfEquation.typeCheck(ErrorCheckType checkType) { |
---|
1172 | if (!getTest().type().isUnknown() && !fBooleanScalarType().typeCompatible(getTest().type())) |
---|
1173 | error("Type of test expression of if equation is not Boolean"); |
---|
1174 | } |
---|
1175 | |
---|
1176 | public void FWhenEquation.typeCheck(ErrorCheckType checkType) { |
---|
1177 | if (!getTest().type().isUnknown()) { |
---|
1178 | if (!getTest().type().isBoolean() || getTest().type().ndims() > 1) |
---|
1179 | error("Test expression of when equation isn't Boolean scalar or vector expression"); |
---|
1180 | } |
---|
1181 | } |
---|
1182 | |
---|
1183 | |
---|
1184 | public void FInfArgsFunctionCall.typeCheck(ErrorCheckType checkType) { |
---|
1185 | super.typeCheck(checkType); |
---|
1186 | if (numArgs() < minNumArgs()) |
---|
1187 | error("Too few arguments to " + builtInName() + "(), must have at least " + minNumArgs()); |
---|
1188 | else |
---|
1189 | typeCheckFExps(); |
---|
1190 | } |
---|
1191 | |
---|
1192 | public void FInfArgsFunctionCall.typeCheckFExps() { |
---|
1193 | for (FExp exp : getFExps()) { |
---|
1194 | if (!exp.type().isUnknown() && !typeOfArgIsOK(exp)) { |
---|
1195 | exp.error("Argument of " + builtInName() + "() is not " + |
---|
1196 | getOKArgTypeString() + ": " + exp); |
---|
1197 | } else if (!variabilityOfArgIsOK(exp)) { |
---|
1198 | exp.error("Argument of " + builtInName() + "() does not have " + |
---|
1199 | getOKArgVariabilityString() + " variability: " + exp); |
---|
1200 | } |
---|
1201 | } |
---|
1202 | } |
---|
1203 | |
---|
1204 | public void FCatExp.typeCheckFExps() { |
---|
1205 | if (!getDim().type().isUnknown() && !fIntegerScalarType().typeCompatible(getDim().type())) |
---|
1206 | error("Dimension argument of cat() is not compatible with Integer: " + getDim()); |
---|
1207 | else if (!getDim().type().isUnknown() && !getDim().variability().parameterOrLess()) |
---|
1208 | error("Dimension argument of cat() does not have constant variability: " + getDim()); |
---|
1209 | } |
---|
1210 | |
---|
1211 | public void FAbstractCat.typeCheckFExps() {} |
---|
1212 | |
---|
1213 | public void FAbstractCat.typeError(ErrorCheckType checkType) { |
---|
1214 | errorUnlessDisabledAnd(typeErrorOnlyLengths(), "Types do not match in array concatenation"); |
---|
1215 | } |
---|
1216 | |
---|
1217 | syn int FInfArgsFunctionCall.minNumArgs() = 1; |
---|
1218 | eq FFillExp.minNumArgs() = 2; |
---|
1219 | eq FCatExp.minNumArgs() = 2; |
---|
1220 | eq FAbstractCat.minNumArgs() = 0; |
---|
1221 | |
---|
1222 | syn int FInfArgsFunctionCall.numArgs() = getNumFExp(); |
---|
1223 | eq FFillExp.numArgs() = getNumFExp() + 1; |
---|
1224 | eq FCatExp.numArgs() = getNumFExp() + 1; |
---|
1225 | |
---|
1226 | syn boolean FInfArgsFunctionCall.typeOfArgIsOK(FExp exp) = |
---|
1227 | fIntegerScalarType().typeCompatible(exp.type()); |
---|
1228 | syn boolean FInfArgsFunctionCall.variabilityOfArgIsOK(FExp exp) = |
---|
1229 | exp.variability().parameterOrLess() || inFunction(); |
---|
1230 | syn String FInfArgsFunctionCall.getOKArgTypeString() = |
---|
1231 | "compatible with Integer"; |
---|
1232 | syn String FInfArgsFunctionCall.getOKArgVariabilityString() = |
---|
1233 | "constant or parameter"; |
---|
1234 | |
---|
1235 | public void FBuiltInFunctionCall.typeCheck(ErrorCheckType checkType) { |
---|
1236 | if (checkTypeAsExpression()) { |
---|
1237 | super.typeCheck(checkType); |
---|
1238 | } else if (!inFunction()) { |
---|
1239 | size().markAsStructuralParameter(checkType, this); |
---|
1240 | } |
---|
1241 | int n = builtInNumOutput(); |
---|
1242 | if (myLefts().size() > n) |
---|
1243 | error("Too many components assigned from function call: " + builtInName() + |
---|
1244 | "() has " + n + " output(s)"); |
---|
1245 | else if (!isFunctionCallClause() && n == 0) |
---|
1246 | error("Function " + builtInName() + "() has no outputs, but is used in expression"); |
---|
1247 | } |
---|
1248 | |
---|
1249 | public void FSemiLinearExp.typeCheck(ErrorCheckType checkType) { |
---|
1250 | checkVectorizedSizes(checkType); |
---|
1251 | super.typeCheck(checkType); |
---|
1252 | } |
---|
1253 | |
---|
1254 | public void FBuiltInFunctionCall.checkVectorizedSizes(ErrorCheckType checkType) { |
---|
1255 | if (isArray()) { |
---|
1256 | boolean error = false; |
---|
1257 | boolean onlyLengths = true; |
---|
1258 | Size s = size(); |
---|
1259 | for (FExp arg : myArgs()) { |
---|
1260 | if (arg.isArray() && !arg.size().equivalent(s, false)) { |
---|
1261 | error = true; |
---|
1262 | if (arg.ndims() != s.ndims()) { |
---|
1263 | onlyLengths = false; |
---|
1264 | break; |
---|
1265 | } |
---|
1266 | } |
---|
1267 | } |
---|
1268 | if (error) { |
---|
1269 | errorUnlessDisabledAnd(onlyLengths, |
---|
1270 | "Mismatching sizes in %s. All non-scalar arguments need matching sizes", builtInName()); |
---|
1271 | } |
---|
1272 | } |
---|
1273 | } |
---|
1274 | |
---|
1275 | public void FEnumIntegerExp.typeCheck(ErrorCheckType checkType) { |
---|
1276 | super.typeCheck(checkType); |
---|
1277 | // We can't define the function Integer in PredefinedTypes.jrag - conflict with the type Integer |
---|
1278 | int n = getNumOriginalArg(); |
---|
1279 | if (n != 1) |
---|
1280 | error("Calling function Integer(): too " + (n > 1 ? "many" : "few") + " arguments"); |
---|
1281 | } |
---|
1282 | |
---|
1283 | public void InstPreExp.typeCheck(ErrorCheckType checkType) { |
---|
1284 | if (!getFExp().isAccess()) { |
---|
1285 | error("Calling function pre(): argument must be variable access"); |
---|
1286 | return; |
---|
1287 | } |
---|
1288 | } |
---|
1289 | |
---|
1290 | public void FAssert.typeCheck(ErrorCheckType checkType) { |
---|
1291 | if (hasLevel()) { |
---|
1292 | if (getLevel().isParameterExp()) |
---|
1293 | getLevel().markAsStructuralParameter(checkType); |
---|
1294 | else if (!getLevel().isConstantExp()) |
---|
1295 | error("Level of assert() must be constant or parameter"); |
---|
1296 | } |
---|
1297 | } |
---|
1298 | |
---|
1299 | public void FReinit.typeCheck(ErrorCheckType checkType) { |
---|
1300 | if (!getVar().isAccess() || !getVar().type().isReal()) |
---|
1301 | error("First argument to reinit() must be an access to a Real variable"); |
---|
1302 | else if (!getVar().type().typeCompatible(getFExp().type())) |
---|
1303 | error("Arguments to reinit() must be of compatible types"); |
---|
1304 | } |
---|
1305 | |
---|
1306 | public void FEdgeExp.typeCheck(ErrorCheckType checkType) { |
---|
1307 | if (!getFExp().isAccess() || !getFExp().type().isBoolean()) |
---|
1308 | error("Calling function edge(): argument must be a boolean variable access"); |
---|
1309 | } |
---|
1310 | |
---|
1311 | public void FChangeExp.typeCheck(ErrorCheckType checkType) { |
---|
1312 | if (!getFExp().isAccess()) |
---|
1313 | error("Calling function change(): argument must be a variable access"); |
---|
1314 | } |
---|
1315 | |
---|
1316 | public static final SimpleProblemProducer ASTNode.DELAY_MAX_NOT_PARAMETER = |
---|
1317 | new SimpleErrorProducer("DELAY_MAX_NOT_PARAMETER", ProblemKind.SEMANTIC, |
---|
1318 | "Calling function delay(): third argument must be of parameter variability: %s"); |
---|
1319 | public static final SimpleProblemProducer ASTNode.DELAY_NOT_PARAMETER = |
---|
1320 | new SimpleErrorProducer("DELAY_NOT_PARAMETER", ProblemKind.SEMANTIC, |
---|
1321 | "Calling function delay(): second argument must be of parameter variability when third argument is not given: %s"); |
---|
1322 | public static final SimpleProblemProducer ASTNode.DELAY_OVER_MAX = |
---|
1323 | new SimpleErrorProducer("DELAY_OVER_MAX", ProblemKind.SEMANTIC, |
---|
1324 | "Calling function delay(): second argument may not be larger than third argument: %s = %s > %s = %s"); |
---|
1325 | public static final SimpleProblemProducer ASTNode.DELAY_NEGATIVE = |
---|
1326 | new SimpleErrorProducer("DELAY_NEGATIVE", ProblemKind.SEMANTIC, |
---|
1327 | "Calling function delay(): second argument may not be negative: %s = %s < 0"); |
---|
1328 | public static final SimpleProblemProducer ASTNode.DELAY_MAX_NEGATIVE = |
---|
1329 | new SimpleErrorProducer("DELAY_MAX_NEGATIVE", ProblemKind.SEMANTIC, |
---|
1330 | "Calling function delay(): third argument may not be negative: %s = %s < 0"); |
---|
1331 | |
---|
1332 | public void FDelayExp.typeCheck(ErrorCheckType checkType) { |
---|
1333 | boolean max = hasMax(); |
---|
1334 | boolean maxParam = max ? getMax().variability().parameterOrLess() : false; |
---|
1335 | boolean delayParam = getDelay().variability().parameterOrLess(); |
---|
1336 | if (max && !maxParam) { |
---|
1337 | DELAY_MAX_NOT_PARAMETER.invoke(this, getMax()); |
---|
1338 | } |
---|
1339 | if (!max && !delayParam) { |
---|
1340 | DELAY_NOT_PARAMETER.invoke(this, getDelay()); |
---|
1341 | } |
---|
1342 | |
---|
1343 | double maxVal = 0.0; |
---|
1344 | boolean maxEval = false; |
---|
1345 | if (max && maxParam) { |
---|
1346 | try { |
---|
1347 | CValue maxCVal = getMax().ceval(); |
---|
1348 | if (maxCVal.hasRealValue()) { |
---|
1349 | maxVal = maxCVal.realValue(); |
---|
1350 | maxEval = true; |
---|
1351 | } |
---|
1352 | } catch (ConstantEvaluationException e) {} |
---|
1353 | } |
---|
1354 | double delayVal = 0.0; |
---|
1355 | boolean delayEval = false; |
---|
1356 | if (delayParam) { |
---|
1357 | try { |
---|
1358 | CValue delayCVal = getDelay().ceval(); |
---|
1359 | if (delayCVal.hasRealValue()) { |
---|
1360 | delayVal = delayCVal.realValue(); |
---|
1361 | delayEval = true; |
---|
1362 | } |
---|
1363 | } catch (ConstantEvaluationException e) {} |
---|
1364 | } |
---|
1365 | if (maxEval && delayEval && delayVal > maxVal) { |
---|
1366 | DELAY_OVER_MAX.invoke(this, getDelay(), delayVal, getMax(), maxVal); |
---|
1367 | } |
---|
1368 | if (delayEval && delayVal < 0.0) { |
---|
1369 | DELAY_NEGATIVE.invoke(this, getDelay(), delayVal); |
---|
1370 | } |
---|
1371 | if (maxEval && maxVal < 0.0) { |
---|
1372 | DELAY_MAX_NEGATIVE.invoke(this, getMax(), maxVal); |
---|
1373 | } |
---|
1374 | } |
---|
1375 | |
---|
1376 | public void FSpatialDistExp.typeCheck(ErrorCheckType checkType) { |
---|
1377 | super.typeCheck(checkType); |
---|
1378 | if (!getIn0().size().equivalent(getIn1().size(), true)) { |
---|
1379 | errorUnlessDisabledAnd(getIn0().ndims() == getIn1().ndims(), |
---|
1380 | "Calling function spatialDistribution(): first and second arguments 'in0' and 'in1' needs equivalent sizes"); |
---|
1381 | } |
---|
1382 | if (isArray()) { |
---|
1383 | if (getX().isArray()) { |
---|
1384 | error("Calling function spatialDistribution(): third argument 'x' cannot be vectorized"); |
---|
1385 | } |
---|
1386 | if (getPositiveVelocity().isArray()) { |
---|
1387 | error("Calling function spatialDistribution(): fourth argument 'positiveVelocity' cannot be vectorized"); |
---|
1388 | } |
---|
1389 | } |
---|
1390 | } |
---|
1391 | |
---|
1392 | public void FStringExp.typeCheck(ErrorCheckType checkType) { |
---|
1393 | FType valueType = getValue().type(); |
---|
1394 | if (hasSignificantDigits() && !valueType.isReal()) |
---|
1395 | error("Calling function String(): named argument significantDigits can only be used when first argument is real"); |
---|
1396 | if (hasFormat() && (hasMinimumLength() || hasLeftJustified() || hasSignificantDigits())) |
---|
1397 | error("Calling function String(): named argument format can not be used together with minimumLength, leftJustified or significantDigits"); |
---|
1398 | } |
---|
1399 | |
---|
1400 | public void FHomotopyExp.typeCheck(ErrorCheckType checkType) { |
---|
1401 | checkVectorizedSizes(checkType); |
---|
1402 | super.typeCheck(checkType); |
---|
1403 | } |
---|
1404 | |
---|
1405 | public void InstDerExp.typeCheck(ErrorCheckType checkType) { |
---|
1406 | FType type = getFExp().type(); |
---|
1407 | if (!(type.isReal() && (type.isScalar() || type.isArray()))) |
---|
1408 | error("Only real typed expressions are allowed in der() operator"); |
---|
1409 | } |
---|
1410 | |
---|
1411 | syn int FBuiltInFunctionCall.builtInNumOutput() = 1; |
---|
1412 | eq FIgnoredBuiltIn.builtInNumOutput() = 0; |
---|
1413 | eq FConnectionsOp.builtInNumOutput() = 0; |
---|
1414 | eq FConnBoolOp.builtInNumOutput() = 1; |
---|
1415 | eq FSpatialDistExp.builtInNumOutput() = 2; |
---|
1416 | |
---|
1417 | syn boolean FBuiltInFunctionCall.checkTypeAsExpression() = false; |
---|
1418 | eq FSizeExp.checkTypeAsExpression() = true; |
---|
1419 | eq FMinMaxExp.checkTypeAsExpression() = true; |
---|
1420 | eq FIdentity.checkTypeAsExpression() = true; |
---|
1421 | eq FLinspace.checkTypeAsExpression() = true; |
---|
1422 | eq FAbstractCat.checkTypeAsExpression() = dimensionIsOk(); |
---|
1423 | |
---|
1424 | syn boolean FAbstractCat.dimensionIsOk(); |
---|
1425 | eq FCatExp.dimensionIsOk() = getDim().isConstantExp() && |
---|
1426 | getDim().type().isInteger() && getDim().type().isScalar(); |
---|
1427 | eq FMatrix.dimensionIsOk() = true; |
---|
1428 | eq FMatrixRow.dimensionIsOk() = true; |
---|
1429 | public static final SimpleProblemProducer ASTNode.CANNOT_INFER_ARRAY_SIZE_OF_OUTPUT = |
---|
1430 | new SimpleErrorProducer("CANNOT_INFER_ARRAY_SIZE_OF_OUTPUT", ProblemKind.SEMANTIC, |
---|
1431 | "Could not evaluate array size of output %s"); |
---|
1432 | |
---|
1433 | public void InstFunctionCall.typeCheck(ErrorCheckType checkType) { |
---|
1434 | if (!isFunctionCallClause() && !getName().myInstClassDecl().isRecord() && !hasOutputs() && !isPartialFunctionCall()) { |
---|
1435 | error("Function " + getName().name() + "() has no outputs, but is used in expression"); |
---|
1436 | } else if (!isFunctionCallClause() && size().isUnknown() && errorCheckUnknownSize()) { |
---|
1437 | CANNOT_INFER_ARRAY_SIZE_OF_OUTPUT.invoke(this, expOutput().name()); |
---|
1438 | } |
---|
1439 | if (myCallOutputs().size() < myLefts().size()) { |
---|
1440 | error("Too many components assigned from function call: " + getName().name() + |
---|
1441 | "() has " + myCallOutputs().size() + " output(s)"); |
---|
1442 | } |
---|
1443 | if (isFunctionCallClause()) { |
---|
1444 | for (int i = 0, n = myCallOutputs().size(); i < n; i++) { |
---|
1445 | sizeOfOutput(i).markAsStructuralParameter(checkType, this); |
---|
1446 | } |
---|
1447 | } else { |
---|
1448 | size().markAsStructuralParameter(checkType, this); |
---|
1449 | } |
---|
1450 | if (callsLoadResource()) { |
---|
1451 | getArgs().forceUsesVariability(checkType, Variability.LOADRESOURCEPARAMETER); |
---|
1452 | } |
---|
1453 | } |
---|
1454 | |
---|
1455 | syn boolean InstFunctionCall.isPartialFunctionCall() = false; |
---|
1456 | eq InstPartialFunctionCall.isPartialFunctionCall() = true; |
---|
1457 | |
---|
1458 | public void FFunctionCallLeft.typeCheck(ErrorCheckType checkType) { |
---|
1459 | if (hasFExp() && !myOutput().isUnknown() && !type().isUnknown()) { // Avoid duplicate error |
---|
1460 | if (getFExp() instanceof CommonAccessExp) { // Should never be false - add check? |
---|
1461 | CommonAccess use = getFExp().asCommonAccess(); |
---|
1462 | FType useType = getFExp().type(); |
---|
1463 | FType outType = type(); |
---|
1464 | if (!use.isForIndex()) { |
---|
1465 | if (outType.size().isUnknown() && !inFunction() && !checkType.allowIncompleteSizes()) { |
---|
1466 | error(functionCallDecription() + ": could not evaluate array size of output " + |
---|
1467 | myOutput().name()); |
---|
1468 | } else if (!useType.typeCompatible(outType, true)) { |
---|
1469 | if (useType.typeCompatibleExceptLengths(outType)) { |
---|
1470 | if (!lockBranch(checkType)) |
---|
1471 | errorUnlessDisabled("%s: component %s is of size %s and output %s is of size %s - they are not compatible", |
---|
1472 | functionCallDecription(), use.name(), useType.size(), myOutput().name(), outType.size()); |
---|
1473 | } else { |
---|
1474 | error("%s: component %s is of type %s and output %s is of type %s - they are not compatible", |
---|
1475 | functionCallDecription(), use.name(), useType, myOutput().name(), outType); |
---|
1476 | } |
---|
1477 | } |
---|
1478 | } |
---|
1479 | } |
---|
1480 | } |
---|
1481 | } |
---|
1482 | |
---|
1483 | inh String InstFunctionArgument.functionCallDecription(); |
---|
1484 | inh String FFunctionCallLeft.functionCallDecription(); |
---|
1485 | eq FAbstractFunctionCall.getChild().functionCallDecription() = functionCallDecription(); |
---|
1486 | eq FFunctionCallEquation.getChild().functionCallDecription() = getCall().functionCallDecription(); |
---|
1487 | eq FFunctionCallStmt.getChild().functionCallDecription() = getCall().functionCallDecription(); |
---|
1488 | |
---|
1489 | public void InstFunctionArgument.typeCheck(ErrorCheckType checkType) { |
---|
1490 | boolean typeOk = true; |
---|
1491 | FType type = getFExp().type(); |
---|
1492 | if (!type.isUnknown()) { |
---|
1493 | if (argumentDefinedTypeValid()) { |
---|
1494 | FType boundType = getBoundInput().type(); |
---|
1495 | if (!boundType.isUnknown()) { |
---|
1496 | if (isVectorized()) |
---|
1497 | boundType = boundType.sizedType(boundType.size().expand(vectorizedSize())); |
---|
1498 | else if (isDestructorArgument()) |
---|
1499 | boundType = boundType.sizedType(type.size()); |
---|
1500 | typeOk = boundType.typeCompatible(type, true) || lockBranch(checkType); |
---|
1501 | } |
---|
1502 | } else { |
---|
1503 | typeOk = argumentTypeValid(type); |
---|
1504 | } |
---|
1505 | } |
---|
1506 | if (!typeOk) { |
---|
1507 | String msg = argumentTypeError(); |
---|
1508 | if (msg != null) { |
---|
1509 | error(msg); |
---|
1510 | } else { |
---|
1511 | error("%s: types of %s and input %s are not compatible\n" + |
---|
1512 | " type of '%s' is %s\n" + |
---|
1513 | " expected type is %s", |
---|
1514 | functionCallDecription(), argumentDesc(), getBoundInput().name(), |
---|
1515 | getFExp(), getFExp().type(), |
---|
1516 | argumentDefinedTypeValid() ? getBoundInput().type().toString() : expectedArgumentType()); |
---|
1517 | } |
---|
1518 | } |
---|
1519 | } |
---|
1520 | |
---|
1521 | public void InstBadArgument.typeCheck(ErrorCheckType checkType) { |
---|
1522 | if (!isDestructorArgument()) { |
---|
1523 | error(functionCallDecription() + ": " + errorString() + " " + getBoundInput().name()); |
---|
1524 | } |
---|
1525 | } |
---|
1526 | |
---|
1527 | syn String InstBadArgument.errorString(); |
---|
1528 | eq InstMissingArgument .errorString() = "missing argument for required input"; |
---|
1529 | eq InstUnknownArgument .errorString() = "could not resolve argument for required input"; |
---|
1530 | eq InstMultipleBoundArgument.errorString() = "multiple arguments matches input"; |
---|
1531 | |
---|
1532 | inh boolean InstFunctionArgument.isDestructorArgument(); |
---|
1533 | eq InstFunctionCall.getArg().isDestructorArgument() = isDestructorCall(); |
---|
1534 | eq BaseNode.getChild().isDestructorArgument() = false; |
---|
1535 | |
---|
1536 | inh boolean InstClassDecl.inExternalObject(); |
---|
1537 | eq InstNode.getChild().inExternalObject() = isExternalObject(); |
---|
1538 | eq InstRecordConstructor.getChild().inExternalObject() = false; |
---|
1539 | |
---|
1540 | public void InstDefaultArgument.typeCheck(ErrorCheckType checkType) {} |
---|
1541 | |
---|
1542 | inh String InstFunctionArgument.argumentTypeError(); |
---|
1543 | eq FExp.getChild().argumentTypeError() = null; |
---|
1544 | eq FCardinality.getChild().argumentTypeError() = "The argument of cardinality() must be a scalar reference to a connector"; |
---|
1545 | |
---|
1546 | syn String InstFunctionArgument.argumentDesc() = null; |
---|
1547 | eq InstPositionalArgument.argumentDesc() = "positional argument " + (getPos() + 1); |
---|
1548 | eq InstNamedArgument.argumentDesc() = "named argument " + getName(); |
---|
1549 | |
---|
1550 | public void InstAccess.typeCheck(ErrorCheckType checkType) { |
---|
1551 | if (myInstComponentDecl().size().isUndefined() && myInstComponentDecl().inFunction() && |
---|
1552 | !myInstComponentDecl().isInput() && !checkType.allowIncompleteSizes()) { |
---|
1553 | compliance("Using variables with undefined size is not supported"); |
---|
1554 | } |
---|
1555 | super.typeCheck(checkType); |
---|
1556 | } |
---|
1557 | |
---|
1558 | public boolean Size.isUndefined() { |
---|
1559 | for (int i = 0; i < ndims(); i++) { |
---|
1560 | if (size[i] == Size.UNKNOWN) { |
---|
1561 | return true; |
---|
1562 | } |
---|
1563 | } |
---|
1564 | return false; |
---|
1565 | } |
---|
1566 | |
---|
1567 | public boolean MutableSize.isUndefined() { |
---|
1568 | for (int i = 0; i < ndims(); i++) { |
---|
1569 | if (size[i] == Size.UNKNOWN && (exps[i] == null || exps[i] instanceof FColonSizeExp)) { |
---|
1570 | return true; |
---|
1571 | } |
---|
1572 | } |
---|
1573 | return false; |
---|
1574 | } |
---|
1575 | |
---|
1576 | public static final SimpleProblemProducer ASTNode.ACCESS_TO_CLASS_THROUGH_COMPONENT = |
---|
1577 | new SimpleErrorProducer("ACCESS_TO_CLASS_THROUGH_COMPONENT", ProblemKind.SEMANTIC, |
---|
1578 | "Can not access non-function class through component access: '%s'"); |
---|
1579 | public static final SimpleProblemProducer ASTNode.ACCESS_TO_FUNCTION_THROUGH_MULTIPLE_COMPONENTS = |
---|
1580 | new SimpleErrorProducer("ACCESS_TO_FUNCTION_THROUGH_MULTIPLE_COMPONENTS", ProblemKind.SEMANTIC, |
---|
1581 | "Can not access function through component unless only the first part of the name is a component: '%s'"); |
---|
1582 | public static final SimpleProblemProducer ASTNode.ACCESS_TO_FUNCTION_THROUGH_ARRAY_COMPONENT = |
---|
1583 | new SimpleErrorProducer("ACCESS_TO_FUNCTION_THROUGH_ARRAY_COMPONENT", ProblemKind.SEMANTIC, |
---|
1584 | "Can not access function through array component access: '%s'"); |
---|
1585 | |
---|
1586 | public void InstDot.typeCheck(ErrorCheckType checkType) { |
---|
1587 | // Check for accesses to component in class or class in component |
---|
1588 | int n = getNumInstAccess(); |
---|
1589 | for (int i = 0; i < n - 1; i++) |
---|
1590 | getInstAccess(i).checkMixedAccessLeft(getInstAccess(i + 1), this, checkType, i, n); |
---|
1591 | super.typeCheck(checkType); |
---|
1592 | } |
---|
1593 | |
---|
1594 | public void InstAccess.checkMixedAccessLeft( |
---|
1595 | InstAccess right, InstAccess top, ErrorCheckType checkType, int i, int n) {} |
---|
1596 | |
---|
1597 | public void InstClassAccess.checkMixedAccessLeft( |
---|
1598 | InstAccess right, InstAccess top, ErrorCheckType checkType, int i, int n) { |
---|
1599 | right.checkMixedAccessRight(myInstClassDecl(), top, checkType, i, n); |
---|
1600 | } |
---|
1601 | |
---|
1602 | public void InstComponentAccess.checkMixedAccessLeft( |
---|
1603 | InstAccess right, InstAccess top, ErrorCheckType checkType, int i, int n) { |
---|
1604 | right.checkMixedAccessRight(myInstComponentDecl(), top, checkType, isArray(), i, n); |
---|
1605 | } |
---|
1606 | |
---|
1607 | public void InstComponentArrayAccess.checkMixedAccessLeft( |
---|
1608 | InstAccess right, InstAccess top, ErrorCheckType checkType, int i, int n) { |
---|
1609 | right.checkMixedAccessRight(myInstComponentDecl(), top, checkType, true, i, n); |
---|
1610 | } |
---|
1611 | |
---|
1612 | public void InstAccess.checkMixedAccessRight( |
---|
1613 | InstClassDecl left, InstAccess top, ErrorCheckType checkType, int i, int n) {} |
---|
1614 | |
---|
1615 | public void InstComponentAccess.checkMixedAccessRight( |
---|
1616 | InstClassDecl left, InstAccess top, ErrorCheckType checkType, int i, int n) { |
---|
1617 | checkMixedAccessRightForComponent(left, top, checkType, i, n); |
---|
1618 | } |
---|
1619 | |
---|
1620 | public void InstComponentArrayAccess.checkMixedAccessRight( |
---|
1621 | InstClassDecl left, InstAccess top, ErrorCheckType checkType, int i, int n) { |
---|
1622 | checkMixedAccessRightForComponent(left, top, checkType, i, n); |
---|
1623 | } |
---|
1624 | |
---|
1625 | public void InstAccess.checkMixedAccessRightForComponent( |
---|
1626 | InstClassDecl left, InstAccess top, ErrorCheckType checkType, int i, int n) { |
---|
1627 | String type = null; |
---|
1628 | if (left.extendsEnum()) { |
---|
1629 | if (!myInstComponentDecl().isEnumLiteral()) |
---|
1630 | type = "attribute of primitive with dot notation"; |
---|
1631 | } else if (left.isPackage()) { |
---|
1632 | left.checkRestriction(checkType); |
---|
1633 | } else if (!left.isOkPackage()) { |
---|
1634 | type = "component in non-package class"; |
---|
1635 | } |
---|
1636 | if (type != null) { |
---|
1637 | top.error("Can not access " + type + ": " + top.name()); |
---|
1638 | } |
---|
1639 | } |
---|
1640 | |
---|
1641 | public void InstAccess.checkMixedAccessRight( |
---|
1642 | InstComponentDecl left, InstAccess top, ErrorCheckType checkType, boolean array, int i, int n) {} |
---|
1643 | |
---|
1644 | public void InstClassAccess.checkMixedAccessRight( |
---|
1645 | InstComponentDecl left, InstAccess top, ErrorCheckType checkType, boolean array, int i, int n) { |
---|
1646 | if (!top.myInstClassDecl().isFunction()) { |
---|
1647 | ACCESS_TO_CLASS_THROUGH_COMPONENT.invoke(top, top); |
---|
1648 | } else if (i != 0) { |
---|
1649 | ACCESS_TO_FUNCTION_THROUGH_MULTIPLE_COMPONENTS.invoke(top, top); |
---|
1650 | } else if (array) { |
---|
1651 | ACCESS_TO_FUNCTION_THROUGH_ARRAY_COMPONENT.invoke(top, top); |
---|
1652 | } |
---|
1653 | } |
---|
1654 | |
---|
1655 | public void InstComponentAccess.checkMixedAccessRight( |
---|
1656 | InstComponentDecl left, InstAccess top, ErrorCheckType checkType, boolean array, int i, int n) { |
---|
1657 | checkMixedAccessRightForComponent(left, top, checkType, array, i, n); |
---|
1658 | } |
---|
1659 | |
---|
1660 | public void InstComponentArrayAccess.checkMixedAccessRight( |
---|
1661 | InstComponentDecl left, InstAccess top, ErrorCheckType checkType, boolean array, int i, int n) { |
---|
1662 | checkMixedAccessRightForComponent(left, top, checkType, array, i, n); |
---|
1663 | } |
---|
1664 | |
---|
1665 | public void InstAccess.checkMixedAccessRightForComponent( |
---|
1666 | InstComponentDecl left, InstAccess top, ErrorCheckType checkType, boolean array, int i, int n) { |
---|
1667 | if (left.isPrimitive()) { |
---|
1668 | top.error("Can not access attribute of primitive with dot notation: " + top.name()); |
---|
1669 | } |
---|
1670 | } |
---|
1671 | |
---|
1672 | /** |
---|
1673 | * Check if the type defined for this argument in the built-in function list |
---|
1674 | * is valid. |
---|
1675 | */ |
---|
1676 | inh boolean InstFunctionArgument.argumentDefinedTypeValid(); |
---|
1677 | eq FAbstractFunctionCall.getChild().argumentDefinedTypeValid() = true; |
---|
1678 | eq FTranspose.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1679 | eq FSymmetric.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1680 | eq FMinMaxExp.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1681 | eq FReductionExp.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1682 | eq FHomotopyExp.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1683 | eq FSemiLinearExp.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1684 | eq FNdimsExp.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1685 | eq FInfArgsFunctionCall.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1686 | eq FEnumIntegerExp.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1687 | eq FVectUnaryBuiltIn.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1688 | eq FDimensionConvert.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1689 | eq FEventGenExp.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1690 | eq FCardinality.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1691 | eq FDecouple.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1692 | eq FMathematicalFunctionCall.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1693 | eq FConnectionsOp.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1694 | eq FStringExp.getOriginalArg(int i).argumentDefinedTypeValid() = i > 0; |
---|
1695 | eq FConnPotentialRoot.getOriginalArg(int i).argumentDefinedTypeValid() = i == 1; |
---|
1696 | eq FSizeExp.getOriginalArg(int i).argumentDefinedTypeValid() = i != 0; |
---|
1697 | eq FSmoothExp.getOriginalArg(int i).argumentDefinedTypeValid() = i == 0; |
---|
1698 | eq InstPreExp.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1699 | eq FEdgeExp.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1700 | eq FChangeExp.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1701 | eq FReinit.getOriginalArg().argumentDefinedTypeValid() = false; |
---|
1702 | |
---|
1703 | /** |
---|
1704 | * Check if the type supplied is valid for this argument. |
---|
1705 | * |
---|
1706 | * Only used if argumentDefinedTypeValid() returns <code>false</code>. |
---|
1707 | */ |
---|
1708 | inh boolean InstFunctionArgument.argumentTypeValid(FType type); |
---|
1709 | eq FAbstractFunctionCall.getChild().argumentTypeValid(FType type) = type.isPrimitive(); |
---|
1710 | eq FTranspose.getChild().argumentTypeValid(FType type) = type.ndims() >= 2 && type.isPrimitive(); |
---|
1711 | eq FSymmetric.getChild().argumentTypeValid(FType type) = |
---|
1712 | type.ndims() == 2 && type.size().get(0) == type.size().get(1); |
---|
1713 | eq FReductionExp.getChild().argumentTypeValid(FType type) = type.ndims() > 0 && type.hasAdd(); |
---|
1714 | eq FSemiLinearExp.getChild().argumentTypeValid(FType type) = type.isNumeric(); |
---|
1715 | eq FAbsExp.getChild().argumentTypeValid(FType type) = type.isNumeric(); |
---|
1716 | eq FSignExp.getChild().argumentTypeValid(FType type) = type.isNumeric(); |
---|
1717 | eq FEnumIntegerExp.getChild().argumentTypeValid(FType type) = type.isEnum(); |
---|
1718 | eq FEventGenExp.getChild().argumentTypeValid(FType type) = type.isNumeric(); |
---|
1719 | eq FMathematicalFunctionCall.getChild().argumentTypeValid(FType type) = type.isNumeric(); |
---|
1720 | eq FMinMaxExp.getOriginalArg(int i).argumentTypeValid(FType type) = |
---|
1721 | hasY() != getOriginalArg(i).getFExp().isArray() && type.isPrimitive(); |
---|
1722 | eq FSmoothExp.getChild().argumentTypeValid(FType type) = type.onlyContainsReal(); |
---|
1723 | eq FDimensionConvert.getChild().argumentTypeValid(FType type) = argumentSizeValid(type.size()); |
---|
1724 | eq FCardinality.getChild().argumentTypeValid(FType type) = |
---|
1725 | type.isScalar() && getFExp().isComponentReference(ALLOWED_COMPONENTS); |
---|
1726 | eq FDecouple.getChild().argumentTypeValid(FType type) = true; |
---|
1727 | eq FConnectionsOp.getOriginalArg(int i).argumentTypeValid(FType type) = |
---|
1728 | getOriginalArg(i).getFExp().isComponentReference(ALLOWED_COMPONENTS); |
---|
1729 | eq FStringExp.getChild().argumentTypeValid(FType type) = |
---|
1730 | type.isScalar() && (type.isReal() || type.isInteger() || type.isBoolean() || type.isEnum()); |
---|
1731 | eq FInfArgsFunctionCall.getChild().argumentTypeValid(FType type) = true; // Type checked in FInfArgsFunctionCall.typeCheck() |
---|
1732 | eq FReinit.getChild().argumentTypeValid(FType type) = true; // Type checked in Reinit.typeCheck() |
---|
1733 | eq FHomotopyExp.getChild().argumentTypeValid(FType type) = type.isNumeric(); |
---|
1734 | // All types allowed for these: |
---|
1735 | eq FNoEventExp.getChild().argumentTypeValid(FType type) = true; |
---|
1736 | eq FSizeExp.getChild().argumentTypeValid(FType type) = true; |
---|
1737 | |
---|
1738 | /** |
---|
1739 | * Description of expexted type of argument. |
---|
1740 | * |
---|
1741 | * Should be defined for cases where argumentDefinedTypeValid() returns and |
---|
1742 | * argumentTypeValid() both return false. |
---|
1743 | */ |
---|
1744 | inh String InstFunctionArgument.expectedArgumentType(); |
---|
1745 | eq FAbstractFunctionCall.getChild().expectedArgumentType() = |
---|
1746 | "Real, Integer, Boolean, String or enumeration"; |
---|
1747 | eq FTranspose.getChild().expectedArgumentType() = |
---|
1748 | "matrix of Real, Integer, Boolean, String or enumeration"; |
---|
1749 | eq FSymmetric.getChild().expectedArgumentType() = "square matrix"; |
---|
1750 | eq FReductionExp.getChild().expectedArgumentType() = "Real array"; |
---|
1751 | eq FEnumIntegerExp.getChild().expectedArgumentType() = "enumeration"; |
---|
1752 | eq FSemiLinearExp.getChild().expectedArgumentType() = "Real"; |
---|
1753 | eq FAbsExp.getChild().expectedArgumentType() = "Real"; |
---|
1754 | eq FSignExp.getChild().expectedArgumentType() = "Real"; |
---|
1755 | eq FEventGenExp.getChild().expectedArgumentType() = "Real"; |
---|
1756 | eq FMathematicalFunctionCall.getChild().expectedArgumentType() = "Real"; |
---|
1757 | eq FSmoothExp.getChild().expectedArgumentType() = "Real"; |
---|
1758 | eq FHomotopyExp.getChild().expectedArgumentType() = "Real"; |
---|
1759 | eq FMinMaxExp.getOriginalArg(int i).expectedArgumentType() = |
---|
1760 | (hasY() ? "scalar" : "array of") + " Real, Integer, Boolean, String or enumeration"; |
---|
1761 | eq FScalarExp.getChild().expectedArgumentType() = "array with exactly 1 element"; |
---|
1762 | eq FVectorExp.getChild().expectedArgumentType() = "scalar or vector-shaped array"; |
---|
1763 | eq FMatrixExp.getChild().expectedArgumentType() = "scalar, vector or matrix-shaped array"; |
---|
1764 | eq FCardinality.getChild().expectedArgumentType() = "scalar connector"; |
---|
1765 | eq FConnectionsOp.getChild().expectedArgumentType() = "connector"; |
---|
1766 | eq FStringExp.getChild().expectedArgumentType() = "scalar Real, Integer, Boolean or enumeration"; |
---|
1767 | |
---|
1768 | protected static final Criteria<InstComponentDecl> FCardinality.ALLOWED_COMPONENTS = new Criteria<InstComponentDecl>() { |
---|
1769 | public boolean test(InstComponentDecl elem) { return elem.isConnector() || elem.isPrimitive(); } |
---|
1770 | }; |
---|
1771 | |
---|
1772 | protected static final Criteria<InstComponentDecl> FConnectionsOp.ALLOWED_COMPONENTS = new Criteria<InstComponentDecl>() { |
---|
1773 | public boolean test(InstComponentDecl elem) { return elem.isOverconstrainedType(); } |
---|
1774 | }; |
---|
1775 | |
---|
1776 | /** |
---|
1777 | * Check if this expression is a reference to a component matching specified criteria. |
---|
1778 | * |
---|
1779 | * Only valid in instance tree. |
---|
1780 | */ |
---|
1781 | syn boolean FExp.isComponentReference(Criteria<InstComponentDecl> criteria) = false; |
---|
1782 | eq CommonAccessExp.isComponentReference(Criteria<InstComponentDecl> criteria) = getAccess().isComponentReference(criteria); |
---|
1783 | |
---|
1784 | syn boolean CommonAccess.isComponentReference(Criteria<InstComponentDecl> criteria) = false; |
---|
1785 | eq InstAccess.isComponentReference(Criteria<InstComponentDecl> criteria) = |
---|
1786 | criteria.test(myInstComponentDecl()); |
---|
1787 | |
---|
1788 | /** |
---|
1789 | * Check if the given Size is valid for the argument of the operator. |
---|
1790 | */ |
---|
1791 | syn boolean FDimensionConvert.argumentSizeValid(Size s) { |
---|
1792 | if (s.isUnknown()) |
---|
1793 | return true; |
---|
1794 | |
---|
1795 | boolean[] useDim = new boolean[s.ndims()]; |
---|
1796 | for (int d : dimensionsToKeep()) |
---|
1797 | if (d < useDim.length) |
---|
1798 | useDim[d] = true; |
---|
1799 | for (int i = 0; i < s.ndims(); i++) |
---|
1800 | if (!useDim[i] && s.get(i) != 1) |
---|
1801 | return false; |
---|
1802 | return true; |
---|
1803 | } |
---|
1804 | |
---|
1805 | protected static void ASTNode.typeCheckEnabled(ErrorCheckType checkType, FExp enabledExp, FType parentType, boolean eachSet) { |
---|
1806 | enabledExp.collectErrors(checkType); |
---|
1807 | if (checkType.checkTypes()) { |
---|
1808 | if (!enabledExp.type().isBoolean() && !enabledExp.type().isUnknown()) { |
---|
1809 | enabledExp.error("The type of the enabled expression is not boolean"); |
---|
1810 | } else if (!eachSet && !parentType.dimensionCompatible(enabledExp.type())) { |
---|
1811 | if (enabledExp.ndims() == 0) { |
---|
1812 | enabledExp.warning("Assuming 'each' for enabled expression"); |
---|
1813 | } else { |
---|
1814 | enabledExp.errorUnlessDisabledAnd(parentType.ndims() == enabledExp.ndims(), |
---|
1815 | "Array size mismatch for the enabled attribute, " + |
---|
1816 | "size of component declaration is %s and size of expression is %s", |
---|
1817 | parentType.size(), enabledExp.size()); |
---|
1818 | } |
---|
1819 | } else if (eachSet) { |
---|
1820 | if (parentType.ndims() == 0) { |
---|
1821 | enabledExp.warning("The 'each' keyword should not be applied to attributes of scalar components"); |
---|
1822 | } else if (enabledExp.ndims() > 0) { |
---|
1823 | enabledExp.error("The enabled attribute is declared 'each' and the expression is not scalar"); |
---|
1824 | } |
---|
1825 | } |
---|
1826 | } |
---|
1827 | } |
---|
1828 | |
---|
1829 | } |
---|
1830 | |
---|
1831 | aspect VariabilityCheck { |
---|
1832 | |
---|
1833 | private FExp FPreExp.instanceTreeSource = null; |
---|
1834 | private FExp FReinit.instanceTreeSource = null; |
---|
1835 | |
---|
1836 | public void FExp.setInstanceTreeSource(FExp source) {} |
---|
1837 | |
---|
1838 | public void FPreExp.setInstanceTreeSource(FExp source) { |
---|
1839 | instanceTreeSource = source; |
---|
1840 | } |
---|
1841 | |
---|
1842 | public void FReinit.setInstanceTreeSource(FExp source) { |
---|
1843 | instanceTreeSource = source; |
---|
1844 | } |
---|
1845 | |
---|
1846 | /** |
---|
1847 | * Surrounds the FExp <code>exp</code> with pre if it is an non literal exp, else return exp. |
---|
1848 | * |
---|
1849 | * Also sets the <code>instanceTreeSource</code> field of the FPreExp (if any) |
---|
1850 | * to <code>source</code>. |
---|
1851 | */ |
---|
1852 | public static FExp FPreExp.create(FExp exp, FExp source) { |
---|
1853 | exp = exp.createFPreExp(); |
---|
1854 | exp.setInstanceTreeSource(source); |
---|
1855 | return exp; |
---|
1856 | } |
---|
1857 | |
---|
1858 | /** |
---|
1859 | * Check operations that are allowed on discrete expressions or variables, |
---|
1860 | * but not on continuous ones or vice-versa. |
---|
1861 | * |
---|
1862 | * Also breaks connections back to instance tree that was added during flattening |
---|
1863 | * to be able to report these errors in the correct place. |
---|
1864 | */ |
---|
1865 | public void ASTNode.checkDiscreteOperations() { |
---|
1866 | for (ASTNode n : this) |
---|
1867 | n.checkDiscreteOperations(); |
---|
1868 | } |
---|
1869 | |
---|
1870 | public void FPreExp.checkDiscreteOperations() { |
---|
1871 | if (instanceTreeSource != null && getFAccess().myFV().isContinuous() && !inWhen() && !inInitialEquationSection()) |
---|
1872 | instanceTreeSource.discreteArgError(); |
---|
1873 | instanceTreeSource = null; |
---|
1874 | } |
---|
1875 | |
---|
1876 | public void FReinit.checkDiscreteOperations() { |
---|
1877 | if (instanceTreeSource != null && !myFV().isContinuous()) |
---|
1878 | instanceTreeSource.discreteArgError(); |
---|
1879 | instanceTreeSource = null; |
---|
1880 | } |
---|
1881 | |
---|
1882 | /** |
---|
1883 | * Generate error for operator that got wrong variability of argument |
---|
1884 | */ |
---|
1885 | public void FExp.discreteArgError() { |
---|
1886 | throw new UnsupportedOperationException(); |
---|
1887 | } |
---|
1888 | |
---|
1889 | public void InstPreExp.discreteArgError() { |
---|
1890 | error("Calling built-in operator pre() with a continuous variable access as argument can only be done in when clauses and initial equations"); |
---|
1891 | } |
---|
1892 | |
---|
1893 | public void FChangeExp.discreteArgError() { |
---|
1894 | error("Calling built-in operator change() with a continuous variable access as argument can only be done in when clauses and initial equations"); |
---|
1895 | } |
---|
1896 | |
---|
1897 | public void FReinit.discreteArgError() { |
---|
1898 | error("Built-in operator reinit() must have a continuous variable access as its first argument"); |
---|
1899 | } |
---|
1900 | |
---|
1901 | } |
---|