1 |
/* |
2 |
* Type definition lint module |
3 |
* by Ben Allan |
4 |
* Created: 9/16/96 |
5 |
* Version: $Revision: 1.48 $ |
6 |
* Version control file: $RCSfile: typelint.c,v $ |
7 |
* Date last modified: $Date: 1998/07/23 13:57:59 $ |
8 |
* Last modified by: $Author: ballan $ |
9 |
* |
10 |
* This file is part of the Ascend Language Interpreter. |
11 |
* |
12 |
* Copyright (C) 1996 Benjamin Andrew Allan |
13 |
* |
14 |
This program is free software; you can redistribute it and/or modify |
15 |
it under the terms of the GNU General Public License as published by |
16 |
the Free Software Foundation; either version 2, or (at your option) |
17 |
any later version. |
18 |
|
19 |
This program is distributed in the hope that it will be useful, |
20 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 |
GNU General Public License for more details. |
23 |
|
24 |
You should have received a copy of the GNU General Public License |
25 |
along with this program; if not, write to the Free Software |
26 |
Foundation, Inc., 59 Temple Place - Suite 330, |
27 |
Boston, MA 02111-1307, USA. |
28 |
*/ |
29 |
|
30 |
#include <math.h> |
31 |
#include <ctype.h> |
32 |
#include <ascend/general/platform.h> |
33 |
#include <ascend/general/list.h> |
34 |
#include <ascend/general/dstring.h> |
35 |
|
36 |
#include "functype.h" |
37 |
#include "expr_types.h" |
38 |
#include "stattypes.h" |
39 |
#include "statement.h" |
40 |
#include "slist.h" |
41 |
#include "statio.h" |
42 |
#include "symtab.h" |
43 |
#include "module.h" |
44 |
#include "library.h" |
45 |
#include "child.h" |
46 |
#include "vlist.h" |
47 |
#include "vlistio.h" |
48 |
#include "name.h" |
49 |
#include "nameio.h" |
50 |
#include "when.h" |
51 |
#include "select.h" |
52 |
#include "switch.h" |
53 |
#include "sets.h" |
54 |
#include "exprs.h" |
55 |
#include "forvars.h" |
56 |
#include "syntax.h" |
57 |
#include "setinstval.h" |
58 |
#include "childinfo.h" |
59 |
#include "evaluate.h" |
60 |
#include "proc.h" |
61 |
#include "type_desc.h" |
62 |
#include "typedef.h" |
63 |
#include "typelint.h" |
64 |
|
65 |
struct errormessage { |
66 |
const char *str; |
67 |
int level; |
68 |
}; |
69 |
|
70 |
/* |
71 |
* Messages with a level < g_parser_warnings do not get printed. |
72 |
* g_parser_warnings == |
73 |
* 2 => suppress style warnings. |
74 |
* 3 => suppress warnings |
75 |
* 4 => suppress errors |
76 |
* 5 => suppress fatality explanations. |
77 |
* The effect is obviously cumulative. |
78 |
*/ |
79 |
int g_parser_warnings = 0; |
80 |
|
81 |
static struct errormessage g_DefinitionErrorMessages[] = { |
82 |
/*0*/{"No error",0}, |
83 |
{"Name of a part has been reused (failure)",3}, |
84 |
{"Name of a part has incorrect structure (failure)",3}, |
85 |
{"Name of a part/variable that does not exist",3}, |
86 |
{"Name of undefined function (failure)",3}, |
87 |
/*5*/{"Illegal right hand side type in ALIASES",3}, |
88 |
{"Illegal expression encountered (parser, lint or memory error, failure)",3}, |
89 |
{"Illegal parameter type for WILL_BE (failure)",3}, |
90 |
{"Statement not allowed in context (failure)",3}, |
91 |
{"Illegal parameter (more than 1 name per IS_A/WILL_BE - failure)",3}, |
92 |
/*10*/{"Illegal parameter reduction (LHS not defined by ancestral IS_A)",3}, |
93 |
{"Illegal parameter reduction (reassigning part - failure)",3}, |
94 |
{"Illegal parameter type for IS_A (punting). Try WILL_BE?",3}, |
95 |
{"Unverifiable name or illegal type in a relation",2}, |
96 |
{"Unverifiable name or illegal type in RHS of :==",2}, |
97 |
/*15*/{"Incorrect number of arguments passed to parameterized type. (failure)",3}, |
98 |
{"Incorrect argument passed to parameterized type. (failure)",3}, |
99 |
{"Statement possibly modifies type of parameter. (failure)",3}, |
100 |
{"Unverifiable LHS of :==, possibly undefined part or non-constant type",2}, |
101 |
{"Unverifiable LHS of :=, possibly undefined part or non-variable type",2}, |
102 |
/*20*/{"Illegal type or undefined name in RHS of := (failure)",3}, |
103 |
{"Object with incompatible type specified in refinement",3}, |
104 |
{"FOR loop index shadows previous declaration (failure)",3}, |
105 |
{"Unverifiable name or illegal type in ARE_ALIKE",2}, |
106 |
{"Illegal parameterized type in ARE_ALIKE",3}, |
107 |
/*25*/{"Illegal set of array elements in ARE_ALIKE",3}, |
108 |
{"WILL(_NOT)_BE_THE_SAME contains incorrect names.",3}, |
109 |
{"WILL_BE in WHERE clause not yet implemented.",3}, |
110 |
{"Mismatched alias array subscript and set name in ALIASES-ISA.",3}, |
111 |
{"Unverifiable FOR loop set, possibly undefined part or non-constant type", 2}, |
112 |
/*30*/{"SELECT statements are not allowed inside a FOR loop",3}, |
113 |
{"Illegal relation -- too many relational operators (<,>,=,<=,>=,<>)",3}, |
114 |
{"Illegal logical relation -- too many equality operators (!=,==)",3}, |
115 |
{"Illegal USE found outside WHEN statement",3}, |
116 |
{"Illegal FOR used in a method must be FOR/DO",3}, |
117 |
/*35*/{"Illegal FOR used in body must be FOR/CREATE",3}, |
118 |
{"Illegal ATOM attribute or relation type in ARE_THE_SAME",3}, |
119 |
{":= used outside METHOD makes models hard to debug or reuse",1}, |
120 |
{"Illegal BREAK used outside loop or SWITCH.",3}, |
121 |
{"Illegal CONTINUE used outside loop.",3}, |
122 |
/*40*/{"Illegal FALL_THROUGH used outside SWITCH.",3}, |
123 |
{"Incorrect nested argument definition for MODEL. (failure)",3}, |
124 |
{"Indexed relation has incorrect subscripts. (failure)",3}, |
125 |
{"Illegal FOR used in WHERE statements must be FOR/CHECK",3}, |
126 |
{"Illegal FOR used in parameter definitions must be FOR/EXPECT",3}, |
127 |
/*45*/{"Miscellaneous style",1}, |
128 |
{"Miscellaneous warning",2}, |
129 |
{"Miscellaneous error",3}, |
130 |
{"Unknown error encountered in statement",5} |
131 |
}; |
132 |
|
133 |
void TypeLintErrorAuxillary(FILE *f, char *str, enum typelinterr err, |
134 |
int uselabel) |
135 |
{ |
136 |
assert(f!=NULL); |
137 |
assert(str!=NULL); |
138 |
if (g_DefinitionErrorMessages[err].level < g_parser_warnings) { |
139 |
/* no element of gDEM should have .level == 0 */ |
140 |
return; |
141 |
} |
142 |
if (uselabel) { |
143 |
FPRINTF(f,"%s%s",StatioLabel(g_DefinitionErrorMessages[err].level),str); |
144 |
} else { |
145 |
FPRINTF(f,"%s",str); |
146 |
} |
147 |
} |
148 |
|
149 |
void TypeLintError(FILE *f, CONST struct Statement *stat,enum typelinterr err) |
150 |
{ |
151 |
assert(f!=NULL); |
152 |
assert(stat!=NULL); |
153 |
if (g_DefinitionErrorMessages[err].level < g_parser_warnings) { |
154 |
/* no element of gDEM should have .level == 0 */ |
155 |
return; |
156 |
} |
157 |
WSSM(f,stat,g_DefinitionErrorMessages[err].str, |
158 |
g_DefinitionErrorMessages[err].level); |
159 |
} |
160 |
|
161 |
void TypeLintName(FILE *f, CONST struct Name *n, char *m) |
162 |
{ |
163 |
TypeLintNameMsg(f,n,m,0); |
164 |
} |
165 |
|
166 |
void TypeLintNameMsg(FILE *f, CONST struct Name *n, char *m,int level) |
167 |
{ |
168 |
assert(f!=NULL); |
169 |
assert(n!=NULL); |
170 |
assert(m!=NULL); |
171 |
if (level > 0 && level < g_parser_warnings) { |
172 |
return; |
173 |
} |
174 |
switch(level){ |
175 |
case 2: |
176 |
ERROR_REPORTER_START_NOLINE(ASC_PROG_WARNING); |
177 |
break; |
178 |
case 3: |
179 |
ERROR_REPORTER_START_NOLINE(ASC_PROG_ERROR); |
180 |
break; |
181 |
case 4: |
182 |
ERROR_REPORTER_START_NOLINE(ASC_PROG_FATAL); |
183 |
break; |
184 |
default: |
185 |
ERROR_REPORTER_START_NOLINE(ASC_PROG_NOTE); |
186 |
} |
187 |
FPRINTF(f,"%s",m); |
188 |
WriteName(f,n); |
189 |
error_reporter_end_flush(); |
190 |
} |
191 |
|
192 |
void TypeLintNameNode(FILE *f, CONST struct Name *n, char *m) |
193 |
{ |
194 |
assert(f!=NULL); |
195 |
assert(n!=NULL); |
196 |
assert(m!=NULL); |
197 |
FPRINTF(f,"%s",m); |
198 |
WriteNameNode(f,n); |
199 |
FPRINTF(f,"\n"); |
200 |
} |
201 |
|
202 |
void TypeLintNameNodeMsg(FILE*f, CONST struct Name *n, char *m) |
203 |
{ |
204 |
assert(f!=NULL); |
205 |
assert(n!=NULL); |
206 |
assert(m!=NULL); |
207 |
if (3 < g_parser_warnings) { |
208 |
return; |
209 |
} |
210 |
ERROR_REPORTER_START_NOLINE(ASC_USER_ERROR); |
211 |
FPRINTF(f,"%s '",m); |
212 |
WriteNameNode(f,n); |
213 |
FPRINTF(f,"'"); |
214 |
error_reporter_end_flush(); |
215 |
} |
216 |
|
217 |
/* |
218 |
* Returns position of first compound name in list |
219 |
* if a CompoundName (e.g. a.b) is found in the |
220 |
* list. Array names are simple e.g. a[i][j], |
221 |
* but compound names include names like a[i][j].b. |
222 |
* Returns -1 OTHERWISE. |
223 |
*/ |
224 |
static |
225 |
int CompoundNameInList(CONST struct VariableList *vl) |
226 |
{ |
227 |
int rval = 0; |
228 |
while (vl != NULL) { |
229 |
if (NameCompound(NamePointer(vl))) { |
230 |
return rval; |
231 |
} |
232 |
vl = NextVariableNode(vl); |
233 |
rval++; |
234 |
} |
235 |
return -1; |
236 |
} |
237 |
|
238 |
/* |
239 |
* pulls the single name element out of the last set name (subscript) |
240 |
* in the alias array name of the ALIASES-IS_A statement. |
241 |
*/ |
242 |
static |
243 |
CONST struct Name *ExtractARRName(CONST struct Statement *s) |
244 |
{ |
245 |
CONST struct Name *n; |
246 |
CONST struct Set *sn; |
247 |
CONST struct Expr *ex; |
248 |
int len; |
249 |
|
250 |
assert(s!=NULL); |
251 |
assert(StatementType(s)==ARR); |
252 |
|
253 |
/* get name from var. */ |
254 |
n = NamePointer(ArrayStatAvlNames(s)); |
255 |
len = NameLength(n); |
256 |
if (len < 2) { |
257 |
return NULL; |
258 |
} |
259 |
/* get last subscript in name */ |
260 |
while (len > 1) { |
261 |
len--; |
262 |
n = NextName(n); |
263 |
} |
264 |
/* must be subscript */ |
265 |
if (NameId(n)!=0) { |
266 |
return NULL; |
267 |
} |
268 |
sn = NameSetPtr(n); |
269 |
/* must be single set, not range */ |
270 |
if (SetType(sn)!=0) { |
271 |
return NULL; |
272 |
} |
273 |
ex = GetSingleExpr(sn); |
274 |
/* must be name of var we're to IS_A elsewhere */ |
275 |
if (ExprListLength(ex) != 1 || ExprType(ex) !=e_var) { |
276 |
return NULL; |
277 |
} |
278 |
return ExprName(ex); |
279 |
} |
280 |
|
281 |
static int g_tlibs_depth=0; |
282 |
/* counter to avoid redundant spew */ |
283 |
enum typelinterr TypeLintIllegalBodyStats(FILE *fp, |
284 |
symchar *name, |
285 |
CONST struct StatementList *sl, |
286 |
unsigned int context) |
287 |
{ |
288 |
unsigned long c,len; |
289 |
struct gl_list_t *gl; |
290 |
struct Statement *s; |
291 |
struct TypeDescription *d; |
292 |
enum typelinterr rval = DEF_OKAY, tmperr; |
293 |
struct SelectList *selcase; |
294 |
struct WhenList *wcase; |
295 |
struct StatementList *slint; |
296 |
|
297 |
g_tlibs_depth++; |
298 |
assert(name !=NULL); |
299 |
len = StatementListLength(sl); |
300 |
if (len == 0L) { |
301 |
g_tlibs_depth--; |
302 |
return rval; |
303 |
} |
304 |
gl = GetList(sl); |
305 |
for(c=1; c<=len; c++) { |
306 |
s = (struct Statement *)gl_fetch(gl,c); |
307 |
switch(StatementType(s)) { |
308 |
case ISA: |
309 |
d = FindType(GetStatType(s)); |
310 |
if (GetBaseType(d)== model_type || GetBaseType(d) == patch_type) { |
311 |
/* check arg list length. can't do types until after. */ |
312 |
if (GetModelParameterCount(d) != SetLength(GetStatTypeArgs(s))) { |
313 |
if (TLINT_ERROR) { |
314 |
FPRINTF(fp,"%sType %s needs %u arguments. Got %lu.\n", |
315 |
StatioLabel(3), |
316 |
SCP(GetStatType(s)), |
317 |
GetModelParameterCount(d), |
318 |
SetLength(GetStatTypeArgs(s))); |
319 |
} |
320 |
rval = DEF_ARGNUM_INCORRECT; |
321 |
TypeLintError(fp,s,rval); |
322 |
break; |
323 |
} |
324 |
} |
325 |
/* fall through */ |
326 |
case ALIASES: |
327 |
/* check simple name */ |
328 |
if (CompoundNameInList(GetStatVarList(s)) != -1) { |
329 |
if (TLINT_ERROR) { |
330 |
FPRINTF(fp, |
331 |
"%sCannot create parts in another object with IS_A/ALIASES.\n", |
332 |
StatioLabel(3)); |
333 |
FPRINTF(fp,"%sName %d is incorrect.\n", |
334 |
StatioLabel(3), |
335 |
CompoundNameInList(GetStatVarList(s))); |
336 |
} |
337 |
rval = DEF_NAME_INCORRECT; |
338 |
TypeLintError(fp,s,rval); |
339 |
} |
340 |
break; |
341 |
case ARR: |
342 |
/* like ALIASES, only different. */ |
343 |
/* assumptions about the parser: the avlname and setname varlists |
344 |
* will only have 1 name pointer in them, as the parser stops |
345 |
* longer lists. |
346 |
*/ |
347 |
/* check simple names */ |
348 |
if (CompoundNameInList(ArrayStatAvlNames(s)) != -1) { |
349 |
if (TLINT_ERROR) { |
350 |
FPRINTF(fp,"%sCannot create parts in another object with ALIASES.\n", |
351 |
StatioLabel(3)); |
352 |
} |
353 |
rval = DEF_NAME_INCORRECT; |
354 |
TypeLintError(fp,s,rval); |
355 |
} |
356 |
if (CompoundNameInList(ArrayStatSetName(s)) != -1) { |
357 |
if (TLINT_ERROR) { |
358 |
FPRINTF(fp,"%sCannot create parts in another object with IS_A.\n", |
359 |
StatioLabel(3)); |
360 |
} |
361 |
rval = DEF_NAME_INCORRECT; |
362 |
TypeLintError(fp,s,rval); |
363 |
} |
364 |
if (CompareNames(NamePointer(ArrayStatSetName(s)),ExtractARRName(s))) { |
365 |
if (TLINT_ERROR) { |
366 |
FPRINTF(fp,"%sName of set defined with IS_A ",StatioLabel(3)); |
367 |
WriteVariableList(fp,ArrayStatSetName(s)); |
368 |
FPRINTF(fp,"\n must match last subscript of ALIASES-ISA LHS.\n"); |
369 |
} |
370 |
rval = DEF_ARR_INCORRECT; |
371 |
TypeLintError(fp,s,rval); |
372 |
} |
373 |
break; |
374 |
case REL: |
375 |
/* check simple name */ |
376 |
if (NameCompound(RelationStatName(s)) != 0) { |
377 |
if (TLINT_ERROR) { |
378 |
FPRINTF(fp,"%sCannot create relations in another object.\n", |
379 |
StatioLabel(3)); |
380 |
} |
381 |
rval = DEF_NAME_INCORRECT; |
382 |
TypeLintError(fp,s,rval); |
383 |
} |
384 |
if (NumberOfRelOps(RelationStatExpr(s)) > 1) { |
385 |
rval = DEF_TOOMANY_RELOP; |
386 |
TypeLintError(fp,s,rval); |
387 |
} |
388 |
break; |
389 |
case LOGREL: |
390 |
/* check simple name */ |
391 |
if (NameCompound(LogicalRelStatName(s)) != 0) { |
392 |
if (TLINT_ERROR) { |
393 |
FPRINTF(fp,"%sCannot create logical relations in another object.\n", |
394 |
StatioLabel(3)); |
395 |
} |
396 |
rval = DEF_NAME_INCORRECT; |
397 |
TypeLintError(fp,s,rval); |
398 |
} |
399 |
if (NumberOfRelOps(LogicalRelStatExpr(s)) > 1) { |
400 |
rval = DEF_TOOMANY_LOGOP; |
401 |
TypeLintError(fp,s,rval); |
402 |
} |
403 |
break; |
404 |
case IRT: |
405 |
d = FindType(GetStatType(s)); |
406 |
if (GetBaseType(d)== model_type || GetBaseType(d) == patch_type) { |
407 |
/* check arg list length. can't do types until after. */ |
408 |
if (GetModelParameterCount(d) != SetLength(GetStatTypeArgs(s))) { |
409 |
if (TLINT_ERROR) { |
410 |
FPRINTF(fp,"%sType %s needs %u arguments. Got %lu.\n", |
411 |
StatioLabel(3), |
412 |
SCP(GetStatType(s)), |
413 |
GetModelParameterCount(d), |
414 |
SetLength(GetStatTypeArgs(s))); |
415 |
} |
416 |
rval = DEF_ARGNUM_INCORRECT; |
417 |
TypeLintError(fp,s,rval); |
418 |
break; |
419 |
} |
420 |
} |
421 |
break; |
422 |
case ATS: |
423 |
break; |
424 |
case AA: |
425 |
if(TLINT_STYLE){ |
426 |
FPRINTF(fp,"%sType \"%s\" contains AA:\n", |
427 |
StatioLabel(1),SCP(name)); |
428 |
WriteStatement(fp,s,2); |
429 |
} |
430 |
break; |
431 |
case LNK: |
432 |
if(TLINT_STYLE){ |
433 |
FPRINTF(fp,"%sType \"%s\" contains LNK:\n", |
434 |
StatioLabel(1),SCP(name)); |
435 |
WriteStatement(fp,s,2); |
436 |
} |
437 |
break; |
438 |
case UNLNK: |
439 |
if(TLINT_STYLE){ |
440 |
FPRINTF(fp,"%sType \"%s\" contains UNLNK:\n", |
441 |
StatioLabel(1),SCP(name)); |
442 |
WriteStatement(fp,s,2); |
443 |
} |
444 |
break; |
445 |
case FOR: |
446 |
if (ForContainsSelect(s)) { |
447 |
rval = DEF_ILLEGAL_SELECT; |
448 |
TypeLintError(fp,s,rval); |
449 |
} |
450 |
if (ForLoopKind(s) != fk_create) { |
451 |
rval = DEF_FOR_NOTBODY; /* err fatal to type */ |
452 |
TypeLintError(fp,s,rval); |
453 |
} else { |
454 |
tmperr = TypeLintIllegalBodyStats(fp,name,ForStatStmts(s), |
455 |
(context | context_FOR)); |
456 |
if (tmperr != DEF_OKAY) { |
457 |
/* don't want DEF_OKAY to wipe out rval if badness already found. |
458 |
*/ |
459 |
rval = tmperr; |
460 |
} |
461 |
} |
462 |
break; |
463 |
case ASGN: |
464 |
TypeLintError(fp,s,DEF_STAT_BODYASGN); |
465 |
TypeLintErrorAuxillary(fp, |
466 |
" Move default assignments to METHOD default_self.\n", |
467 |
DEF_STAT_BODYASGN,FALSE); |
468 |
break; |
469 |
case CASGN: |
470 |
break; |
471 |
case FNAME: |
472 |
if ((context & context_WHEN) == 0) { |
473 |
rval = DEF_USE_NOTWHEN; |
474 |
TypeLintError(fp,s,rval); |
475 |
if ((context & context_SELECT) != 0) { |
476 |
FPRINTF(fp," Perhaps the surrounding SELECT should be WHEN?\n"); |
477 |
} |
478 |
} |
479 |
break; |
480 |
case WHEN: |
481 |
/* check simple name */ |
482 |
/* vicente, what's up with this? we can name whens? */ |
483 |
if (NameCompound(WhenStatName(s)) != 0) { |
484 |
FPRINTF(fp," Cannot create whens in another object.\n"); |
485 |
rval = DEF_NAME_INCORRECT; |
486 |
TypeLintError(fp,s,rval); |
487 |
} |
488 |
wcase = WhenStatCases(s); |
489 |
while ( wcase!=NULL ) { |
490 |
slint = WhenStatementList(wcase); |
491 |
tmperr = TypeLintIllegalBodyStats(fp,name,slint, |
492 |
(context | context_WHEN)); |
493 |
if (tmperr != DEF_OKAY) { |
494 |
rval = tmperr; |
495 |
} |
496 |
wcase = NextWhenCase(wcase); |
497 |
} |
498 |
break; |
499 |
case SELECT: |
500 |
selcase = SelectStatCases(s); |
501 |
while ( selcase!=NULL ) { |
502 |
slint = SelectStatementList(selcase); |
503 |
tmperr = TypeLintIllegalBodyStats(fp,name,slint, |
504 |
(context | context_SELECT)); |
505 |
if (tmperr != DEF_OKAY) { |
506 |
rval = tmperr; |
507 |
} |
508 |
selcase = NextSelectCase(selcase); |
509 |
} |
510 |
break; |
511 |
case EXT: |
512 |
if (ExternalStatMode(s) == ek_method) { |
513 |
Asc_StatErrMsg_NotAllowedDeclarative(fp,s,""); |
514 |
rval = DEF_STAT_MISLOCATED; |
515 |
} |
516 |
break; |
517 |
case REF: |
518 |
break; |
519 |
case COND: |
520 |
tmperr = TypeLintIllegalBodyStats(fp,name,CondStatList(s), |
521 |
(context | context_COND)); |
522 |
if (tmperr != DEF_OKAY) { |
523 |
rval = tmperr; |
524 |
} |
525 |
break; |
526 |
/* Stuff illegal in body */ |
527 |
case SWITCH: |
528 |
TypeLintError(fp,s,DEF_STAT_MISLOCATED); |
529 |
rval = DEF_STAT_MISLOCATED; |
530 |
FPRINTF(fp," Perhaps SWITCH should be WHEN or SELECT?\n"); |
531 |
break; |
532 |
case FLOW: /* fallthrough */ |
533 |
case WHILE: |
534 |
TypeLintError(fp,s,DEF_STAT_MISLOCATED); |
535 |
rval = DEF_STAT_MISLOCATED; |
536 |
FPRINTF(fp," Flow controls are allowed only in methods.\n"); |
537 |
break; |
538 |
case IF: |
539 |
TypeLintError(fp,s,DEF_STAT_MISLOCATED); |
540 |
rval = DEF_STAT_MISLOCATED; |
541 |
FPRINTF(fp," Perhaps IF should be WHEN or SELECT?\n"); |
542 |
break; |
543 |
case RUN: |
544 |
case CALL: |
545 |
case WILLBE: |
546 |
case WBTS: |
547 |
case WNBTS: |
548 |
default: |
549 |
TypeLintError(fp,s,DEF_STAT_MISLOCATED); |
550 |
rval = DEF_STAT_MISLOCATED; |
551 |
} |
552 |
} |
553 |
if (rval != DEF_OKAY && g_tlibs_depth < 2 /* at top */) { |
554 |
FPRINTF(fp," Errors detected in declarative section of '%s'\n", |
555 |
SCP(name)); |
556 |
} |
557 |
g_tlibs_depth--; |
558 |
return rval; |
559 |
} |
560 |
|
561 |
enum typelinterr TypeLintIllegalParamStats(FILE * fp, |
562 |
symchar *name, |
563 |
CONST struct StatementList *sl) |
564 |
{ |
565 |
unsigned long c,len; |
566 |
struct gl_list_t *gl; |
567 |
struct Statement *s; |
568 |
enum typelinterr rval = DEF_OKAY; |
569 |
symchar *tid; |
570 |
CONST struct TypeDescription *t; |
571 |
|
572 |
assert(name !=NULL); |
573 |
len = StatementListLength(sl); |
574 |
if (len == 0L) { |
575 |
return rval; |
576 |
} |
577 |
gl = GetList(sl); |
578 |
for(c=1; c<=len;c++) { |
579 |
s = (struct Statement *)gl_fetch(gl,c); |
580 |
switch(StatementType(s)) { |
581 |
case WILLBE: |
582 |
/* check rhs for bad type here */ |
583 |
tid = GetStatType(s); |
584 |
t = FindType(tid); |
585 |
switch (GetBaseType(t)) { |
586 |
case relation_type: |
587 |
case logrel_type: |
588 |
case when_type: |
589 |
rval = DEF_ILLEGAL_PARAM; |
590 |
TypeLintError(fp,s,rval); |
591 |
break; |
592 |
case model_type: |
593 |
case patch_type: |
594 |
/* check arg list length. can't do types until after. */ |
595 |
if ( SetLength(GetStatTypeArgs(s)) != 0L) { |
596 |
if (TLINT_ERROR) { |
597 |
FPRINTF(fp, |
598 |
"%sArguments defined with WILL_BE cannot " /* no comma */ |
599 |
"have arguments. Got %lu.\n", |
600 |
StatioLabel(3), |
601 |
SetLength(GetStatTypeArgs(s))); |
602 |
FPRINTF(fp, "%sYou may want to use WILL_BE_THE_SAME instead.\n", |
603 |
StatioLabel(2)); |
604 |
} |
605 |
rval = DEF_ARGDEF_INCORRECT; |
606 |
TypeLintError(fp,s,rval); |
607 |
} |
608 |
break; |
609 |
default: |
610 |
break; |
611 |
} |
612 |
if (VariableListLength(GetStatVarList(s)) > 1L) { |
613 |
rval = DEF_MULTI_PARAM; |
614 |
TypeLintError(fp,s,rval); |
615 |
break; /* no point complaining twice */ |
616 |
} |
617 |
/* check simple names */ |
618 |
if (CompoundNameInList(GetStatVarList(s)) != -1) { |
619 |
if (TLINT_ERROR) { |
620 |
FPRINTF(fp,"%sCannot use . in defining MODEL arguments.\n", |
621 |
StatioLabel(3)); |
622 |
} |
623 |
rval = DEF_NAME_INCORRECT; |
624 |
TypeLintError(fp,s,rval); |
625 |
} |
626 |
break; |
627 |
case ISA: |
628 |
/* check rhs for bad type here */ |
629 |
tid = GetStatType(s); |
630 |
t = FindType(tid); |
631 |
if (BaseTypeIsSet(t)==0 && BaseTypeIsConstant(t)==0) { |
632 |
rval = DEF_ILLEGAL_VALPAR; |
633 |
TypeLintError(fp,s,rval); |
634 |
break; /* no point complaining twice */ |
635 |
} |
636 |
if (VariableListLength(GetStatVarList(s)) > 1L) { |
637 |
rval = DEF_MULTI_PARAM; |
638 |
TypeLintError(fp,s,rval); |
639 |
break; /* no point complaining twice */ |
640 |
} |
641 |
if (CompoundNameInList(GetStatVarList(s)) != -1) { |
642 |
if (TLINT_ERROR) { |
643 |
FPRINTF(fp,"%sCannot create parts in another object with IS_A.\n", |
644 |
StatioLabel(3)); |
645 |
FPRINTF(fp," Name %d is incorrect.\n", |
646 |
CompoundNameInList(GetStatVarList(s))); |
647 |
} |
648 |
rval = DEF_NAME_INCORRECT; |
649 |
TypeLintError(fp,s,rval); |
650 |
} |
651 |
break; |
652 |
case ALIASES: /* huge fallthrough */ |
653 |
case ARR: |
654 |
case IRT: |
655 |
case ATS: |
656 |
case WBTS: |
657 |
case WNBTS: |
658 |
case AA: |
659 |
case LNK: |
660 |
case UNLNK: |
661 |
case FOR: /* eventually for legal and fk_expect required */ |
662 |
case REL: |
663 |
case LOGREL: |
664 |
case ASGN: |
665 |
case CASGN: |
666 |
case WHEN: |
667 |
case FNAME: |
668 |
case SELECT: |
669 |
case SWITCH: |
670 |
case EXT: |
671 |
case REF: |
672 |
case COND: |
673 |
case RUN: |
674 |
case CALL: |
675 |
case FLOW: |
676 |
case WHILE: |
677 |
case IF: |
678 |
default: |
679 |
TypeLintError(fp,s,DEF_STAT_MISLOCATED); |
680 |
rval = DEF_STAT_MISLOCATED; |
681 |
} |
682 |
} |
683 |
if (rval != DEF_OKAY) { |
684 |
FPRINTF(fp," Errors detected in argument definitions of '%s'\n",SCP(name)); |
685 |
} |
686 |
return rval; |
687 |
} |
688 |
|
689 |
/* could stand to be a lot more rigorous */ |
690 |
enum typelinterr |
691 |
TypeLintIllegalWhereStats(FILE * fp, |
692 |
symchar *name, |
693 |
CONST struct StatementList *sl) |
694 |
{ |
695 |
unsigned long c,len; |
696 |
struct gl_list_t *gl; |
697 |
struct Statement *s; |
698 |
enum typelinterr rval = DEF_OKAY, tmperr; |
699 |
|
700 |
assert(name !=NULL); |
701 |
len = StatementListLength(sl); |
702 |
if (len == 0L) { |
703 |
return rval; |
704 |
} |
705 |
gl = GetList(sl); |
706 |
for(c=1; c<=len;c++) { |
707 |
s = (struct Statement *)gl_fetch(gl,c); |
708 |
switch(StatementType(s)) { |
709 |
case FOR: |
710 |
if (ForLoopKind(s) != fk_check) { |
711 |
rval = DEF_FOR_NOTCHECK; |
712 |
TypeLintError(fp,s,rval); |
713 |
} else { |
714 |
tmperr = TypeLintIllegalWhereStats(fp,name,ForStatStmts(s)); |
715 |
if (tmperr != DEF_OKAY) { |
716 |
rval = tmperr; |
717 |
} |
718 |
} |
719 |
break; |
720 |
case WBTS: |
721 |
case WNBTS: |
722 |
case LOGREL: |
723 |
case REL: |
724 |
break; |
725 |
case CASGN: |
726 |
case ALIASES: |
727 |
case ARR: |
728 |
case ISA: |
729 |
case IRT: |
730 |
case ATS: |
731 |
case AA: |
732 |
case LNK: |
733 |
case UNLNK: |
734 |
case ASGN: |
735 |
case WHEN: |
736 |
case FNAME: |
737 |
case SELECT: |
738 |
case SWITCH: |
739 |
case EXT: |
740 |
case REF: |
741 |
case COND: |
742 |
case RUN: |
743 |
case CALL: |
744 |
case IF: |
745 |
case FLOW: |
746 |
case WHILE: |
747 |
case WILLBE: |
748 |
default: |
749 |
TypeLintError(fp,s,DEF_STAT_MISLOCATED); |
750 |
rval = DEF_STAT_MISLOCATED; |
751 |
} |
752 |
} |
753 |
if (rval != DEF_OKAY) { |
754 |
FPRINTF(fp," Errors detected in WHERE statements of '%s'\n",SCP(name)); |
755 |
} |
756 |
return rval; |
757 |
} |
758 |
|
759 |
enum typelinterr |
760 |
TypeLintIllegalReductionStats(FILE * fp, |
761 |
symchar *name, |
762 |
CONST struct StatementList *sl) |
763 |
{ |
764 |
unsigned long c,len; |
765 |
struct gl_list_t *gl; |
766 |
struct Statement *s; |
767 |
enum typelinterr rval = DEF_OKAY; |
768 |
|
769 |
assert(name !=NULL); |
770 |
len = StatementListLength(sl); |
771 |
if (len == 0L) { |
772 |
return rval; |
773 |
} |
774 |
gl = GetList(sl); |
775 |
for(c=1; c<=len;c++) { |
776 |
s = (struct Statement *)gl_fetch(gl,c); |
777 |
switch(StatementType(s)) { |
778 |
case CASGN: |
779 |
if (NameCompound(AssignStatVar(s)) != 0) { |
780 |
if (TLINT_ERROR) { |
781 |
FPRINTF(fp,"%sCannot assign parts in an object being passed in.\n", |
782 |
StatioLabel(3)); |
783 |
} |
784 |
rval = DEF_NAME_INCORRECT; |
785 |
TypeLintError(fp,s,rval); |
786 |
} |
787 |
break; |
788 |
case ALIASES: |
789 |
case ARR: |
790 |
case ISA: |
791 |
case IRT: |
792 |
case ATS: |
793 |
case WBTS: |
794 |
case WNBTS: |
795 |
case AA: |
796 |
case LNK: |
797 |
case UNLNK: |
798 |
case FOR: /* probably should be legal now and require fk_create */ |
799 |
case REL: |
800 |
case LOGREL: |
801 |
case ASGN: |
802 |
case WHEN: |
803 |
case FNAME: |
804 |
case SELECT: |
805 |
case SWITCH: |
806 |
case EXT: |
807 |
case REF: |
808 |
case COND: |
809 |
case RUN: |
810 |
case CALL: |
811 |
case IF: |
812 |
case FLOW: |
813 |
case WHILE: |
814 |
case WILLBE: |
815 |
default: |
816 |
TypeLintError(fp,s,DEF_STAT_MISLOCATED); |
817 |
rval = DEF_STAT_MISLOCATED; |
818 |
} |
819 |
} |
820 |
if (rval != DEF_OKAY) { |
821 |
FPRINTF(fp," Errors detected in parameter assignments of '%s'\n",SCP(name)); |
822 |
} |
823 |
return rval; |
824 |
} |
825 |
|
826 |
static |
827 |
enum typelinterr |
828 |
TypeLintIllegalMethodStatList(FILE *fp, |
829 |
symchar *name, symchar *pname, |
830 |
struct StatementList *sl, |
831 |
unsigned int context) |
832 |
{ |
833 |
unsigned long c,len; |
834 |
struct gl_list_t *gl; |
835 |
struct Statement *s; |
836 |
struct SwitchList *sw; |
837 |
struct StatementList *sublist; |
838 |
enum typelinterr rval = DEF_OKAY, tmperr; |
839 |
|
840 |
if (sl == NULL) { |
841 |
return rval; |
842 |
} |
843 |
len = StatementListLength(sl); |
844 |
gl = GetList(sl); |
845 |
for(c=1; c<=len;c++) { |
846 |
s = (struct Statement *)gl_fetch(gl,c); |
847 |
switch(StatementType(s)) { |
848 |
case CASGN: |
849 |
case ALIASES: |
850 |
case ARR: |
851 |
case ISA: |
852 |
case IRT: |
853 |
case ATS: |
854 |
case WBTS: |
855 |
case WNBTS: |
856 |
case AA: |
857 |
case REF: |
858 |
case COND: |
859 |
case WILLBE: |
860 |
case FNAME: |
861 |
Asc_StatErrMsg_NotAllowedMethod(fp,s,""); |
862 |
rval = DEF_STAT_MISLOCATED; |
863 |
break; |
864 |
case REL: |
865 |
case LOGREL: |
866 |
Asc_StatErrMsg_NotAllowedMethod(fp,s,"Perhaps '=' or '==' should be ':='?"); |
867 |
rval = DEF_STAT_MISLOCATED; |
868 |
break; |
869 |
case WHEN: |
870 |
Asc_StatErrMsg_NotAllowedMethod(fp,s,"Perhaps WHEN should be SWITCH?"); |
871 |
rval = DEF_STAT_MISLOCATED; |
872 |
break; |
873 |
case SELECT: |
874 |
Asc_StatErrMsg_NotAllowedMethod(fp,s,"Perhaps SELECT should be SWITCH?"); |
875 |
rval = DEF_STAT_MISLOCATED; |
876 |
break; |
877 |
case FOR: |
878 |
if (ForLoopKind(s) != fk_do) { |
879 |
rval = DEF_FOR_NOTMETH; |
880 |
TypeLintError(fp,s,rval); |
881 |
} else { |
882 |
tmperr = TypeLintIllegalMethodStatList(fp,name,pname,ForStatStmts(s), |
883 |
(context | context_FOR)); |
884 |
if (tmperr != DEF_OKAY) { |
885 |
rval = tmperr; |
886 |
} |
887 |
} |
888 |
break; |
889 |
case EXT: |
890 |
if (ExternalStatMode(s) != ek_method) { |
891 |
Asc_StatErrMsg_NotAllowedMethod(fp,s,""); |
892 |
rval = DEF_STAT_MISLOCATED; |
893 |
} |
894 |
break; |
895 |
case LNK: |
896 |
case UNLNK: |
897 |
/* DS: in case we provide functionality for other statements inside LINK, check their legal status */ |
898 |
/* DS: in case we provide functionality for other statements inside UNLINK, check their legal status */ |
899 |
break; |
900 |
case ASGN: |
901 |
case RUN: |
902 |
case FIX: |
903 |
case FREE: |
904 |
case CALL: |
905 |
case SOLVER: |
906 |
case OPTION: |
907 |
case SOLVE: |
908 |
break; |
909 |
case WHILE: |
910 |
if (WhileStatBlock(s) != NULL) { |
911 |
tmperr = TypeLintIllegalMethodStatList(fp,name,pname,WhileStatBlock(s), |
912 |
(context | context_WHILE)); |
913 |
if (tmperr != DEF_OKAY) { |
914 |
rval = tmperr; |
915 |
break; |
916 |
} |
917 |
} |
918 |
break; |
919 |
case ASSERT: |
920 |
/* no sublists for TEST */ |
921 |
break; |
922 |
|
923 |
case IF: |
924 |
if (IfStatThen(s) != NULL) { |
925 |
tmperr = TypeLintIllegalMethodStatList(fp,name,pname,IfStatThen(s), |
926 |
(context | context_IF)); |
927 |
if (tmperr != DEF_OKAY) { |
928 |
rval = tmperr; |
929 |
break; |
930 |
} |
931 |
} |
932 |
if (IfStatElse(s) != NULL){ |
933 |
tmperr = TypeLintIllegalMethodStatList(fp,name,pname,IfStatElse(s), |
934 |
(context | context_IF)); |
935 |
if (tmperr != DEF_OKAY) { |
936 |
rval = tmperr; |
937 |
} |
938 |
} |
939 |
break; |
940 |
case SWITCH: |
941 |
sw = SwitchStatCases(s); |
942 |
while (sw!=NULL) { |
943 |
sublist = SwitchStatementList(sw); |
944 |
if (sublist!=NULL) { |
945 |
tmperr = TypeLintIllegalMethodStatList(fp,name,pname,sublist, |
946 |
(context | context_SWITCH)); |
947 |
if (tmperr != DEF_OKAY) { |
948 |
rval = tmperr; |
949 |
break; |
950 |
} |
951 |
} |
952 |
sw = NextSwitchCase(sw); |
953 |
} |
954 |
break; |
955 |
case FLOW: |
956 |
switch (FlowStatControl(s)) { |
957 |
case fc_break: |
958 |
if ((context & (context_FOR | context_SWITCH | context_WHILE))==0) { |
959 |
rval = DEF_ILLEGAL_BREAK; |
960 |
TypeLintError(fp,s,rval); |
961 |
} |
962 |
break; |
963 |
case fc_continue: |
964 |
if ((context & (context_FOR | context_WHILE))==0) { |
965 |
rval = DEF_ILLEGAL_CONTINUE; |
966 |
TypeLintError(fp,s,rval); |
967 |
} |
968 |
break; |
969 |
case fc_fallthru: |
970 |
if ((context & context_SWITCH)==0) { |
971 |
rval = DEF_ILLEGAL_FALLTHRU; |
972 |
TypeLintError(fp,s,rval); |
973 |
} |
974 |
break; |
975 |
case fc_return: |
976 |
case fc_stop: |
977 |
break; |
978 |
} |
979 |
break; |
980 |
default: |
981 |
rval = DEF_UNKNOWN_ERR; |
982 |
TypeLintError(fp,s,rval); |
983 |
break; |
984 |
} |
985 |
} |
986 |
if (rval != DEF_OKAY) { |
987 |
FPRINTF(fp," Errors detected in METHOD '%s' of '%s'\n",SCP(pname),SCP(name)); |
988 |
} |
989 |
return rval; |
990 |
} |
991 |
|
992 |
enum typelinterr TypeLintIllegalMethodStats(FILE * fp, |
993 |
symchar *name, |
994 |
struct gl_list_t *pl, |
995 |
unsigned int context) |
996 |
{ |
997 |
unsigned long pc,plen; |
998 |
struct StatementList *sl; |
999 |
symchar *pname; |
1000 |
enum typelinterr rval = DEF_OKAY, tmperr; |
1001 |
|
1002 |
assert(name != NULL); |
1003 |
if (pl == NULL) { |
1004 |
return rval; |
1005 |
} |
1006 |
plen = gl_length(pl); |
1007 |
for (pc=1; pc <= plen; pc++) { |
1008 |
sl = ProcStatementList((struct InitProcedure *)gl_fetch(pl,pc)); |
1009 |
pname= ProcName((struct InitProcedure *)gl_fetch(pl,pc)); |
1010 |
tmperr = TypeLintIllegalMethodStatList(fp,name,pname,sl,context); |
1011 |
if (tmperr != DEF_OKAY) { |
1012 |
rval = tmperr; |
1013 |
printf("asdsaf \n"); |
1014 |
} |
1015 |
} |
1016 |
return rval; |
1017 |
} |