/
NFSCodeCheck.mo
599 lines (522 loc) · 17.2 KB
/
NFSCodeCheck.mo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
/*
* This file is part of OpenModelica.
*
* Copyright (c) 1998-2014, Open Source Modelica Consortium (OSMC),
* c/o Linköpings universitet, Department of Computer and Information Science,
* SE-58183 Linköping, Sweden.
*
* All rights reserved.
*
* THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3 LICENSE OR
* THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2.
* ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
* RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3,
* ACCORDING TO RECIPIENTS CHOICE.
*
* The OpenModelica software and the Open Source Modelica
* Consortium (OSMC) Public License (OSMC-PL) are obtained
* from OSMC, either from the above address,
* from the URLs: http://www.ida.liu.se/projects/OpenModelica or
* http://www.openmodelica.org, and in the OpenModelica distribution.
* GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html.
*
* This program is distributed WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
* IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
*
* See the full OSMC Public License conditions for more details.
*
*/
encapsulated package NFSCodeCheck
" file: NFSCodeCheck.mo
package: NFSCodeCheck
description: SCode checking
This module checks the SCode representation for conformance "
public import Absyn;
public import NFInstTypes;
public import SCode;
public import NFSCodeEnv;
protected import Debug;
protected import Dump;
protected import Error;
protected import Flags;
protected import NFInstDump;
protected import SCodeDump;
import NFSCodeEnv.EnvTree;
public function checkRecursiveShortDefinition
input Absyn.TypeSpec inTypeSpec;
input String inTypeName;
input NFSCodeEnv.Env inTypeEnv;
input SourceInfo inInfo;
algorithm
_ := matchcontinue(inTypeSpec, inTypeName, inTypeEnv, inInfo)
local
Absyn.Path ts_path, ty_path;
String ty;
case (_, _, {}, _) then ();
case (_, _, _ :: _, _)
equation
ts_path = Absyn.typeSpecPath(inTypeSpec);
ty_path = NFSCodeEnv.getEnvPath(inTypeEnv);
false = isSelfReference(inTypeName, ty_path, ts_path);
then
();
else
equation
ty = Dump.unparseTypeSpec(inTypeSpec);
Error.addSourceMessage(Error.RECURSIVE_SHORT_CLASS_DEFINITION,
{inTypeName, ty}, inInfo);
then
fail();
end matchcontinue;
end checkRecursiveShortDefinition;
protected function isSelfReference
input String inTypeName;
input Absyn.Path inTypePath;
input Absyn.Path inReferencedName;
output Boolean selfRef;
algorithm
selfRef := match(inTypeName, inTypePath, inReferencedName)
local
Absyn.Path p1, p2;
case (_, p1, Absyn.FULLYQUALIFIED(p2))
then Absyn.pathEqual(Absyn.joinPaths(p1, Absyn.IDENT(inTypeName)), p2);
case (_, _, p2)
then stringEqual(Absyn.pathLastIdent(inTypePath), Absyn.pathFirstIdent(p2));
end match;
end isSelfReference;
public function checkClassExtendsReplaceability
input NFSCodeEnv.Item inBaseClass;
input SourceInfo inOriginInfo;
algorithm
_ := match(inBaseClass, inOriginInfo)
local
SourceInfo info;
String name;
case (NFSCodeEnv.CLASS(cls = SCode.CLASS(prefixes = SCode.PREFIXES(
replaceablePrefix = SCode.REPLACEABLE()))), _)
then ();
//case (NFSCodeEnv.CLASS(cls = SCode.CLASS(name = name, prefixes = SCode.PREFIXES(
// replaceablePrefix = SCode.NOT_REPLACEABLE()), info = info)), _)
// equation
// Error.addSourceMessage(Error.ERROR_FROM_HERE, {}, inOriginInfo);
// Error.addSourceMessage(Error.NON_REPLACEABLE_CLASS_EXTENDS,
// {name}, info);
// then
// fail();
end match;
end checkClassExtendsReplaceability;
public function checkRedeclareModifier
input NFSCodeEnv.Redeclaration inModifier;
input Absyn.Path inBaseClass;
input NFSCodeEnv.Env inEnv;
algorithm
_ := match(inModifier, inBaseClass, inEnv)
local
SCode.Element e;
case (NFSCodeEnv.RAW_MODIFIER(e as SCode.CLASS(classDef =
SCode.DERIVED())), _, _)
equation
checkRedeclareModifier2(e, inBaseClass, inEnv);
then
();
else ();
end match;
end checkRedeclareModifier;
public function checkRedeclareModifier2
input SCode.Element inModifier;
input Absyn.Path inBaseClass;
input NFSCodeEnv.Env inEnv;
algorithm
_ := matchcontinue(inModifier, inBaseClass, inEnv)
local
Absyn.TypeSpec ty;
SourceInfo info;
String name, ty_str;
Absyn.Path ty_path;
case (SCode.CLASS(name = name,
classDef = SCode.DERIVED(typeSpec = ty)), _, _)
equation
ty_path = Absyn.typeSpecPath(ty);
false = isSelfReference(name, inBaseClass, ty_path);
then
();
case (SCode.CLASS(name = name,
classDef = SCode.DERIVED(typeSpec = ty), info = info), _, _)
equation
ty_str = Dump.unparseTypeSpec(ty);
Error.addSourceMessage(Error.RECURSIVE_SHORT_CLASS_DEFINITION,
{name, ty_str}, info);
then
fail();
end matchcontinue;
end checkRedeclareModifier2;
public function checkModifierIfRedeclare
input NFSCodeEnv.Item inItem;
input SCode.Mod inModifier;
input SourceInfo inInfo;
algorithm
_ := match(inItem, inModifier, inInfo)
local
SCode.Element el;
case (_, SCode.REDECL(element = el), _)
equation
checkRedeclaredElementPrefix(inItem, el, inInfo);
then
();
else ();
end match;
end checkModifierIfRedeclare;
public function checkRedeclaredElementPrefix
"Checks that an element that is being redeclared is declared as replaceable
and non-final, otherwise an error is printed."
input NFSCodeEnv.Item inItem;
input SCode.Element inReplacement;
input SourceInfo inInfo;
algorithm
_ := match(inItem, inReplacement)
local
SCode.Replaceable repl;
SCode.Final fin;
SCode.Ident name;
SourceInfo info;
SCode.Variability var;
SCode.Restriction res;
SCode.Visibility vis1, vis2;
String ty;
Absyn.TypeSpec ty1, ty2;
Boolean ok;
case (NFSCodeEnv.VAR(var =
SCode.COMPONENT(name = name, prefixes = SCode.PREFIXES(
finalPrefix = fin, replaceablePrefix = repl),
attributes = SCode.ATTR(variability = var), typeSpec = ty1, info = info)),
SCode.COMPONENT(prefixes = SCode.PREFIXES(), typeSpec = ty2))
algorithm
ty := "component";
ok := checkCompRedeclarationReplaceable(name, repl, ty1, ty2, inInfo, info);
ok := checkRedeclarationFinal(name, ty, fin, inInfo, info) and ok;
ok := checkRedeclarationVariability(name, ty, var, inInfo, info) and ok;
//checkRedeclarationVisibility(name, ty, vis1, vis2, inInfo, info);
true := ok;
then
();
case (NFSCodeEnv.CLASS(cls =
SCode.CLASS(name = name, prefixes = SCode.PREFIXES(
finalPrefix = fin, replaceablePrefix = repl),
restriction = res, info = info)),
SCode.CLASS(prefixes = SCode.PREFIXES()))
algorithm
ty := SCodeDump.restrictionStringPP(res);
ok := checkClassRedeclarationReplaceable(name, ty, repl, inInfo, info);
ok := checkRedeclarationFinal(name, ty, fin, inInfo, info) and ok;
//checkRedeclarationVisibility(name, ty, vis1, vis2, inInfo, info);
true := ok;
then
();
case (NFSCodeEnv.VAR(var = SCode.COMPONENT(name = name, info = info)),
SCode.CLASS(restriction = res))
algorithm
ty := SCodeDump.restrictionStringPP(res);
ty := "a " + ty;
Error.addMultiSourceMessage(Error.INVALID_REDECLARE_AS,
{"component", name, ty}, {inInfo, info});
then
fail();
case (NFSCodeEnv.CLASS(cls = SCode.CLASS(restriction = res, info = info)),
SCode.COMPONENT(name = name))
algorithm
ty := SCodeDump.restrictionStringPP(res);
Error.addMultiSourceMessage(Error.INVALID_REDECLARE_AS,
{ty, name, "a component"}, {inInfo, info});
then
fail();
else ();
end match;
end checkRedeclaredElementPrefix;
protected function checkClassRedeclarationReplaceable
input SCode.Ident inName;
input String inType;
input SCode.Replaceable inReplaceable;
input SourceInfo inOriginInfo;
input SourceInfo inInfo;
output Boolean isValid;
algorithm
isValid := match inReplaceable
case SCode.NOT_REPLACEABLE() guard not Flags.getConfigBool(Flags.IGNORE_REPLACEABLE)
algorithm
Error.addMultiSourceMessage(Error.REDECLARE_NON_REPLACEABLE,
{inType, inName}, {inOriginInfo, inInfo});
then
false;
else true;
end match;
end checkClassRedeclarationReplaceable;
protected function checkCompRedeclarationReplaceable
input SCode.Ident inName;
input SCode.Replaceable inReplaceable;
input Absyn.TypeSpec inType1;
input Absyn.TypeSpec inType2;
input SourceInfo inOriginInfo;
input SourceInfo inInfo;
output Boolean isValid;
algorithm
isValid := match inReplaceable
case SCode.NOT_REPLACEABLE()
guard Absyn.pathEqual(Absyn.typeSpecPath(inType1),
Absyn.typeSpecPath(inType2))
then
true;
case SCode.NOT_REPLACEABLE() guard not Flags.getConfigBool(Flags.IGNORE_REPLACEABLE)
algorithm
Error.addMultiSourceMessage(Error.REDECLARE_NON_REPLACEABLE,
{"component", inName}, {inOriginInfo, inInfo});
then
fail();
else true;
end match;
end checkCompRedeclarationReplaceable;
protected function checkRedeclarationFinal
input SCode.Ident inName;
input String inType;
input SCode.Final inFinal;
input SourceInfo inOriginInfo;
input SourceInfo inInfo;
output Boolean isValid;
algorithm
isValid := match inFinal
case SCode.NOT_FINAL() then true;
case SCode.FINAL()
algorithm
Error.addMultiSourceMessage(Error.INVALID_REDECLARE,
{"final", inType, inName}, {inOriginInfo, inInfo});
then
false;
end match;
end checkRedeclarationFinal;
protected function checkRedeclarationVariability
input SCode.Ident inName;
input String inType;
input SCode.Variability inVariability;
input SourceInfo inOriginInfo;
input SourceInfo inInfo;
output Boolean isValid;
algorithm
isValid := match inVariability
case SCode.CONST()
algorithm
Error.addMultiSourceMessage(Error.INVALID_REDECLARE,
{"constant", inType, inName}, {inOriginInfo, inInfo});
then
false;
else true;
end match;
end checkRedeclarationVariability;
protected function checkRedeclarationVisibility
input SCode.Ident inName;
input String inType;
input SCode.Visibility inOriginalVisibility;
input SCode.Visibility inNewVisibility;
input SourceInfo inOriginInfo;
input SourceInfo inNewInfo;
output Boolean isValid;
algorithm
isValid := match (inOriginalVisibility, inNewVisibility)
case (SCode.PUBLIC(), SCode.PROTECTED())
algorithm
Error.addMultiSourceMessage(Error.INVALID_REDECLARE_AS,
{"public element", inName, "protected"}, {inNewInfo, inOriginInfo});
then
false;
case (SCode.PROTECTED(), SCode.PUBLIC())
algorithm
Error.addMultiSourceMessage(Error.INVALID_REDECLARE_AS,
{"protected element", inName, "public"}, {inNewInfo, inOriginInfo});
then
false;
else true;
end match;
end checkRedeclarationVisibility;
public function checkValidEnumLiteral
input String inLiteral;
input SourceInfo inInfo;
algorithm
_ := match(inLiteral, inInfo)
case (_, _) guard not listMember(inLiteral, {"quantity", "min", "max", "start", "fixed"})
then ();
else
equation
Error.addSourceMessage(Error.INVALID_ENUM_LITERAL, {inLiteral}, inInfo);
then
fail();
end match;
end checkValidEnumLiteral;
public function checkDuplicateRedeclarations
"Checks if a redeclaration already exists in a list of redeclarations."
input NFSCodeEnv.Redeclaration inRedeclare;
input list<NFSCodeEnv.Redeclaration> inRedeclarations;
protected
SCode.Element el;
String el_name;
SourceInfo el_info;
algorithm
(el_name, el_info) := NFSCodeEnv.getRedeclarationNameInfo(inRedeclare);
false := checkDuplicateRedeclarations2(el_name, el_info, inRedeclarations);
end checkDuplicateRedeclarations;
protected function checkDuplicateRedeclarations2
"Helper function to checkDuplicateRedeclarations."
input String inRedeclareName;
input SourceInfo inRedeclareInfo;
input list<NFSCodeEnv.Redeclaration> inRedeclarations;
output Boolean outIsDuplicate;
algorithm
outIsDuplicate := matchcontinue(inRedeclareName, inRedeclareInfo,
inRedeclarations)
local
NFSCodeEnv.Redeclaration redecl;
list<NFSCodeEnv.Redeclaration> rest_redecls;
String el_name;
SourceInfo el_info;
case (_, _, {}) then false;
case (_, _, redecl :: _)
equation
(el_name, el_info) = NFSCodeEnv.getRedeclarationNameInfo(redecl);
true = stringEqual(inRedeclareName, el_name);
Error.addSourceMessage(Error.ERROR_FROM_HERE, {}, el_info);
Error.addSourceMessage(Error.DUPLICATE_REDECLARATION,
{inRedeclareName}, inRedeclareInfo);
then
true;
case (_, _, _ :: rest_redecls)
then checkDuplicateRedeclarations2(inRedeclareName,
inRedeclareInfo, rest_redecls);
end matchcontinue;
end checkDuplicateRedeclarations2;
public function checkRecursiveComponentDeclaration
"Checks if a component is declared with a type that is one of the enclosing
classes, e.g:
class A
class B
A a;
end B;
end A;
"
input String inComponentName;
input SourceInfo inComponentInfo;
input NFSCodeEnv.Env inTypeEnv;
input NFSCodeEnv.Item inTypeItem;
input NFSCodeEnv.Env inComponentEnv;
algorithm
_ := matchcontinue(inComponentName, inComponentInfo, inTypeEnv, inTypeItem,
inComponentEnv)
local
String cls_name, ty_name;
EnvTree.Tree tree;
SCode.Element el;
// No environment means one of the basic types.
case (_, _, {}, _, _) then ();
// Check that the environment of the components type is not an enclosing
// scope of the component itself.
case (_, _, _, _, _)
equation
false = NFSCodeEnv.envPrefixOf(inTypeEnv, inComponentEnv);
then
();
// Make an exception for components in functions.
case (_, _, _, _, NFSCodeEnv.FRAME(name = SOME(cls_name)) ::
NFSCodeEnv.FRAME(clsAndVars = tree) :: _)
equation
NFSCodeEnv.CLASS(cls = el) = EnvTree.get(tree, cls_name);
true = SCode.isFunction(el);
then
();
else
equation
ty_name = NFSCodeEnv.getItemName(inTypeItem);
Error.addSourceMessage(Error.RECURSIVE_DEFINITION,
{inComponentName, ty_name}, inComponentInfo);
then
fail();
end matchcontinue;
end checkRecursiveComponentDeclaration;
public function checkIdentNotEqTypeName
"Checks that a simple identifier is not the same as a type name."
input String inIdent;
input Absyn.TypeSpec inTypeName;
input SourceInfo inInfo;
output Boolean outIsNotEq;
algorithm
outIsNotEq := matchcontinue(inIdent, inTypeName, inInfo)
local
String id, ty;
case (id, Absyn.TPATH(path = Absyn.IDENT(ty)), _)
equation
true = stringEq(id, ty);
Error.addSourceMessage(Error.LOOKUP_TYPE_FOUND_COMP, {id}, inInfo);
then
false;
else true;
end matchcontinue;
end checkIdentNotEqTypeName;
public function checkComponentsEqual
input NFInstTypes.Component inComponent1;
input NFInstTypes.Component inComponent2;
algorithm
_ := match(inComponent1, inComponent2)
case (_, _)
equation
print("Found duplicate component\n");
then
();
end match;
end checkComponentsEqual;
public function checkInstanceRestriction
input NFSCodeEnv.Item inItem;
input NFInstTypes.Prefix inPrefix;
input SourceInfo inInfo;
algorithm
_ := matchcontinue(inItem, inPrefix, inInfo)
local
SCode.Restriction res;
String pre_str, res_str;
case (NFSCodeEnv.CLASS(cls = SCode.CLASS(restriction = res)), _, _)
equation
true = SCode.isInstantiableClassRestriction(res);
then
();
case (NFSCodeEnv.CLASS(cls = SCode.CLASS(restriction = res)), _, _)
equation
res_str = SCodeDump.restrictionStringPP(res);
pre_str = NFInstDump.prefixStr(inPrefix);
Error.addSourceMessage(Error.INVALID_CLASS_RESTRICTION,
{res_str, pre_str}, inInfo);
then
fail();
else
equation
true = Flags.isSet(Flags.FAILTRACE);
Debug.traceln("- NFSCodeCheck.checkInstanceRestriction failed on unknown item.");
then
fail();
end matchcontinue;
end checkInstanceRestriction;
public function checkPartialInstance
"Checks if the given item is partial, and prints out an error message in that
case."
input NFSCodeEnv.Item inItem;
input SourceInfo inInfo;
algorithm
_ := match(inItem, inInfo)
local
String name;
case (NFSCodeEnv.CLASS(cls = SCode.CLASS(name = name, partialPrefix =
SCode.PARTIAL())), _)
equation
Error.addSourceMessage(Error.INST_PARTIAL_CLASS, {name}, inInfo);
then
fail();
else ();
end match;
end checkPartialInstance;
annotation(__OpenModelica_Interface="frontend");
end NFSCodeCheck;