libutap  0.93
Uppaal Timed Automata Parser
typechecker.cpp
Go to the documentation of this file.
1 // -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2 
3 /* libutap - Uppaal Timed Automata Parser.
4  Copyright (C) 2002-2006 Uppsala University and Aalborg University.
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Lesser General Public License
8  as published by the Free Software Foundation; either version 2.1 of
9  the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Lesser General Public License for more details.
15 
16  You should have received a copy of the GNU Lesser General Public
17  License along with this library; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  USA
20 */
21 
22 #include "utap/utap.h"
23 #include "utap/typechecker.h"
24 #include "utap/systembuilder.h"
25 
26 #include <sstream>
27 #include <list>
28 #include <stdexcept>
29 #include <cmath>
30 #include <cstdio>
31 #include <cassert>
32 #include <boost/tuple/tuple.hpp>
33 
34 using std::exception;
35 using std::set;
36 using std::pair;
37 using std::make_pair;
38 using std::max;
39 using std::min;
40 using std::map;
41 using std::vector;
42 using std::list;
43 
44 using boost::tie;
45 
46 using namespace UTAP;
47 using namespace Constants;
48 
49 /* The following are simple helper functions for testing the type of
50  * expressions.
51  */
52 static bool isCost(expression_t expr)
53 {
54  return expr.getType().is(COST);
55 }
56 
57 static bool isVoid(expression_t expr)
58 {
59  return expr.getType().isVoid();
60 }
61 
62 static bool isDouble(expression_t expr)
63 {
64  return expr.getType().isDouble();
65 }
66 
67 // static bool isScalar(expression_t expr)
68 // {
69 // return expr.getType().isScalar();
70 // }
71 
72 static bool isInteger(expression_t expr)
73 {
74  return expr.getType().isInteger();
75 }
76 
77 static bool isBound(expression_t expr)
78 {
79  return expr.getType().isInteger() || expr.getType().isDouble();
80 }
81 
82 static bool isIntegral(expression_t expr)
83 {
84  return expr.getType().isIntegral();
85 }
86 
87 static bool isClock(expression_t expr)
88 {
89  return expr.getType().isClock();
90 }
91 
92 static bool isDiff(expression_t expr)
93 {
94  return expr.getType().isDiff();
95 }
96 
97 static bool isDoubleValue(expression_t expr)
98 {
99  return isDouble(expr) || isClock(expr) || isDiff(expr);
100 }
101 
102 static bool isNumber(expression_t expr)
103 {
104  return isDoubleValue(expr) || isIntegral(expr);
105 }
106 
108 {
109  return expr.getKind() == CONSTANT && isInteger(expr);
110 }
111 
113 {
114  return expr.getKind() == CONSTANT && isDouble(expr);
115 }
116 
117 static bool isInvariant(expression_t expr)
118 {
119  return expr.getType().isInvariant();
120 }
121 
122 static bool isGuard(expression_t expr)
123 {
124  return expr.getType().isGuard();
125 }
126 
127 #ifdef ENABLE_PROB
128 static bool isProbability(expression_t expr)
129 {
130  return expr.getType().isProbability();
131 }
132 #endif
133 
134 static bool isConstraint(expression_t expr)
135 {
136  return expr.getType().isConstraint();
137 }
138 
139 static bool isFormula(expression_t expr)
140 {
141  return expr.getType().isFormula();
142 }
143 
145 {
146  if (expr.getKind() != LIST)
147  {
148  return false;
149  }
150 
151  for(uint32_t i = 0; i < expr.getSize(); ++i)
152  {
153  if (!expr[i].getType().isFormula())
154  {
155  return false;
156  }
157  }
158 
159  return true;
160 }
161 
163 {
164  for(size_t i = 0; i < expr.getSize(); ++i)
165  {
166  if (hasStrictLowerBound(expr[i]))
167  {
168  return true;
169  }
170  }
171 
172  switch(expr.getKind())
173  {
174  case LT: // int < clock
175  if (isIntegral(expr[0]) && isClock(expr[1]))
176  {
177  return true;
178  }
179  break;
180  case GT: // clock > int
181  if (isClock(expr[0]) && isIntegral(expr[1]))
182  {
183  return true;
184  }
185  break;
186 
187  default: ;
188  }
189 
190  return false;
191 }
192 
194 {
195  for(size_t i = 0; i < expr.getSize(); ++i)
196  {
197  if (hasStrictUpperBound(expr[i]))
198  {
199  return true;
200  }
201  }
202 
203  switch(expr.getKind())
204  {
205  case GT: // int > clock
206  if (isIntegral(expr[0]) && isClock(expr[1]))
207  {
208  return true;
209  }
210  break;
211  case LT: // clock < int
212  if (isClock(expr[0]) && isIntegral(expr[1]))
213  {
214  return true;
215  }
216  break;
217 
218  default: ;
219  }
220 
221  return false;
222 }
223 
228 static bool isInvariantWR(expression_t expr)
229 {
230  return isInvariant(expr) || (expr.getType().is(INVARIANT_WR));
231 }
232 
238 static bool isAssignable(type_t type)
239 {
240  switch (type.getKind())
241  {
242  case Constants::INT:
243  case Constants::BOOL:
244  case Constants::DOUBLE:
245  case Constants::CLOCK:
246  case Constants::COST:
247  case Constants::SCALAR:
248  return true;
249 
250  case ARRAY:
251  return isAssignable(type[0]);
252 
253  case RECORD:
254  for (size_t i = 0; i < type.size(); i++)
255  {
256  if (!isAssignable(type[i]))
257  {
258  return false;
259  }
260  }
261  return true;
262 
263  default:
264  return type.size() > 0 && isAssignable(type[0]);
265  }
266 }
267 
269 
271 {
272  if (variable.uid.getType().isConstant())
273  {
274  variables.insert(variable.uid);
275  }
276 }
277 
279 {
280  frame_t parameters = temp.parameters;
281  for (uint32_t i = 0; i < parameters.getSize(); i++)
282  {
283  type_t type = parameters[i].getType();
284  if (!type.is(REF) && type.isConstant() && !type.isDouble())
285  {
286  variables.insert(parameters[i]);
287  }
288  }
289 }
290 
292 {
293  return (variables.find(symbol) != variables.end());
294 }
295 
297 
298 class RateDecomposer
299 {
300 public:
301  RateDecomposer()
302  : invariant(expression_t::createConstant(1)),
303  hasStrictInvariant(false), hasClockRates(false),
304  countCostRates(0) {}
305 
306  expression_t costRate;
307  expression_t invariant;
308  bool hasStrictInvariant, hasClockRates;
309  size_t countCostRates;
310 
311  void decompose(expression_t,bool inforall = false);
312 };
313 
314 void RateDecomposer::decompose(expression_t expr, bool inforall)
315 {
316  assert(isInvariantWR(expr));
317 
318  if (isInvariant(expr))
319  {
320  if (expr.getKind() == Constants::LT)
321  {
322  hasStrictInvariant = true; // Strict upper bounds only.
323  }
324  if (!inforall)
325  {
326  invariant = invariant.empty()
327  ? expr
328  : invariant = expression_t::createBinary(
329  AND, invariant, expr,
330  expr.getPosition(),
332  }
333  }
334  else if (expr.getKind() == AND)
335  {
336  decompose(expr[0], inforall);
337  decompose(expr[1], inforall);
338  }
339  else if (expr.getKind() == EQ)
340  {
341  expression_t left, right;
342  assert((expr[0].getType().getKind() == RATE)
343  ^ (expr[1].getType().getKind() == RATE));
344 
345  if (expr[0].getType().getKind() == RATE)
346  {
347  left = expr[0][0];
348  right = expr[1];
349  }
350  else
351  {
352  left = expr[1][0];
353  right = expr[0];
354  }
355 
356  if (isCost(left))
357  {
358  costRate = right;
359  countCostRates++;
360  }
361  else
362  {
363  hasClockRates = true;
364  if (!inforall)
365  {
366  invariant = invariant.empty()
367  ? expr
369  AND, invariant, expr,
370  expr.getPosition(),
372  }
373  }
374  }
375  else
376  {
377  assert(expr.getType().is(INVARIANT_WR));
378  assert(expr.getKind() == FORALL);
379  // Enter the forall to look for clock rates but don't
380  // record them, rather the forall expression.
381  decompose(expr[1], true);
382  invariant = invariant.empty()
383  ? expr
384  : invariant = expression_t::createBinary(
385  AND, invariant, expr,
386  expr.getPosition(),
388  }
389 }
390 
392 
394  TimedAutomataSystem *_system, bool refinement)
395  : system{_system}, refinementWarnings{refinement}
396 {
397  system->accept(compileTimeComputableValues);
398  checkExpression(system->getBeforeUpdate());
399  checkExpression(system->getAfterUpdate());
400 }
401 
402 template<class T>
403 void TypeChecker::handleWarning(const T& expr, const std::string& msg)
404 {
405  system->addWarning(expr.getPosition(), msg, "(typechecking)");
406 }
407 
408 template<class T>
409 void TypeChecker::handleError(const T& expr, const std::string& msg)
410 {
411  system->addError(expr.getPosition(), msg, "(typechecking)");
412 }
413 
424 void TypeChecker::checkIgnoredValue(expression_t expr)
425 {
426  if (expr.getKind()!=EXIT && !expr.changesAnyVariable())
427  {
428  handleWarning(expr, "$Expression_does_not_have_any_effect");
429  }
430  else if (expr.getKind() == COMMA)
431  {
432  checkIgnoredValue(expr[1]);
433  }
434 }
435 
436 bool TypeChecker::isCompileTimeComputable(expression_t expr) const
437 {
438  /* An expression is compile time computable if all identifers it
439  * could possibly access during an evaluation are compile time
440  * computable (i.e. their value is known at compile time).
441  *
442  * FIXME: We could maybe refine this to actually include function
443  * local variables with compile time computable initialisers. This
444  * would increase the class of models we accept while also getting
445  * rid of the compileTimeComputableValues object.
446  */
447  set<symbol_t> reads;
448  expr.collectPossibleReads(reads, true);
449  for (set<symbol_t>::iterator i = reads.begin(); i != reads.end(); i++)
450  {
451  if (*i == symbol_t() ||
452  (!i->getType().isFunction()
453  && !compileTimeComputableValues.contains(*i)))
454  {
455  return false;
456  }
457  }
458  return true;
459 }
460 
461 // static bool contains(frame_t frame, symbol_t symbol)
462 // {
463 // for (size_t i = 0; i < frame.getSize(); i++)
464 // {
465 // if (frame[i] == symbol)
466 // {
467 // return true;
468 // }
469 // }
470 // return false;
471 // }
472 
486 void TypeChecker::checkType(type_t type, bool initialisable, bool inStruct)
487 {
488  expression_t l, u;
489  type_t size;
490  frame_t frame;
491 
492  switch (type.getKind())
493  {
494  case LABEL:
495  checkType(type[0], initialisable, inStruct);
496  break;
497 
498  case URGENT:
499  if (!type.isLocation() && !type.isChannel())
500  {
501  handleError(type, "$Prefix_urgent_only_allowed_for_locations_and_channels");
502  }
503  checkType(type[0], initialisable, inStruct);
504  break;
505 
506  case BROADCAST:
507  if (!type.isChannel())
508  {
509  handleError(type, "$Prefix_broadcast_only_allowed_for_channels");
510  }
511  checkType(type[0], initialisable, inStruct);
512  break;
513 
514  case COMMITTED:
515  if (!type.isLocation())
516  {
517  handleError(type, "$Prefix_committed_only_allowed_for_locations");
518  }
519  checkType(type[0], initialisable, inStruct);
520  break;
521 
522  case HYBRID:
523  if (!type.isClock() && !(type.isArray() && type.stripArray().isClock()))
524  {
525  handleError(type, "$Prefix_hybrid_only_allowed_for_clocks");
526  }
527  checkType(type[0], initialisable, inStruct);
528  break;
529 
530  case CONSTANT:
531  if (type.isClock())
532  {
533  handleError(type, "$Prefix_const_not_allowed_for_clocks");
534  }
535  checkType(type[0], true, inStruct);
536  break;
537 
538  case SYSTEM_META:
539  if (type.isClock())
540  {
541  handleError(type, "$Prefix_meta_not_allowed_for_clocks");
542  }
543  checkType(type[0], true, inStruct);
544  break;
545 
546  case REF:
547  if (!type.isIntegral() && !type.isArray() && !type.isRecord()
548  && !type.isChannel() && !type.isClock() && !type.isScalar()
549  && !type.isDouble())
550  {
551  handleError(type, "$Reference_to_this_type_not_allowed");
552  }
553  checkType(type[0], initialisable, inStruct);
554  break;
555 
556  case RANGE:
557  if (!type.isInteger() && !type.isScalar())
558  {
559  handleError(type, "$Range_over_this_type_not_allowed");
560  }
561  tie(l, u) = type.getRange();
562  if (checkExpression(l))
563  {
564  if (!isInteger(l))
565  {
566  handleError(l, "$Integer_expected");
567  }
568  if (!isCompileTimeComputable(l))
569  {
570  handleError(l, "$Must_be_computable_at_compile_time");
571  }
572  }
573  if (checkExpression(u))
574  {
575  if (!isInteger(u))
576  {
577  handleError(u, "$Integer_expected");
578  }
579  if (!isCompileTimeComputable(u))
580  {
581  handleError(u, "$Must_be_computable_at_compile_time");
582  }
583  }
584  break;
585 
586  case ARRAY:
587  size = type.getArraySize();
588  if (!size.is(RANGE))
589  {
590  handleError(type, "$Invalid_array_size");
591  }
592  else
593  {
594  checkType(size);
595  }
596  checkType(type[0], initialisable, inStruct);
597  break;
598 
599  case RECORD:
600  for (size_t i = 0; i < type.size(); i++)
601  {
602  checkType(type.getSub(i), true, true);
603  }
604  break;
605 
606  case Constants::DOUBLE:
607  if (inStruct)
608  {
609  handleError(type, "$This_type_cannot_be_declared_inside_a_struct");
610  }
611  case Constants::INT:
612  case Constants::BOOL:
613  break;
614 
615  default:
616  if (initialisable)
617  {
618  handleError(type, "$This_type_cannot_be_declared_const_or_meta");
619  }
620  }
621 }
622 
624 {
625  const std::list<chan_priority_t>& list = sys->getChanPriorities();
626  std::list<chan_priority_t>::const_iterator i;
627  for (i = list.begin(); i != list.end(); i++)
628  {
629  bool isDefault = (i->head == expression_t());
630  if (!isDefault && checkExpression(i->head))
631  {
632  expression_t expr = i->head;
633  type_t channel = expr.getType();
634 
635  // Check that chanElement is a channel, or an array of channels.
636  while (channel.isArray())
637  {
638  channel = channel.getSub();
639  }
640  if (!channel.isChannel())
641  {
642  handleError(expr, "$Channel_expected");
643  }
644 
645  // Check index expressions
646  while (expr.getKind() == ARRAY)
647  {
648  if (!isCompileTimeComputable(expr[1]))
649  {
650  handleError(expr[1], "$Must_be_computable_at_compile_time");
651  }
652  else if (i->head.changesAnyVariable())
653  {
654  handleError(expr[1], "$Index_must_be_side-effect_free");
655  }
656  expr = expr[0];
657  }
658  }
659 
660  chan_priority_t::tail_t::const_iterator j;
661  for (j = i->tail.begin(); j != i->tail.end(); ++j)
662  {
663  bool isDefault = (j->second == expression_t());
664  if (!isDefault && checkExpression(j->second))
665  {
666  expression_t expr = j->second;
667  type_t channel = expr.getType();
668 
669  // Check that chanElement is a channel, or an array of channels.
670  while (channel.isArray())
671  {
672  channel = channel.getSub();
673  }
674  if (!channel.isChannel())
675  {
676  handleError(expr, "$Channel_expected");
677  }
678 
679  // Check index expressions
680  while (expr.getKind() == ARRAY)
681  {
682  if (!isCompileTimeComputable(expr[1]))
683  {
684  handleError(expr[1], "$Must_be_computable_at_compile_time");
685  }
686  else if (j->second.changesAnyVariable())
687  {
688  handleError(expr[1], "$Index_must_be_side-effect_free");
689  }
690  expr = expr[0];
691  }
692  }
693  }
694  }
695 }
696 
698 {
699  if (checkExpression(e))
700  {
701  if (!isClock(e))
702  {
703  handleError(e, "$Clock_expected");
704  }
705  else if (e.changesAnyVariable())
706  {
707  handleError(e, "$Index_must_be_side-effect_free");
708  }
709  // Should be a check to identify the clock at compile time.
710  // Problematic now. Same issue for inf & sup.
711  }
712 }
713 
715 {
716  for(vector<expression_t>::iterator i = iodecl.param.begin();
717  i != iodecl.param.end(); ++i)
718  {
719  expression_t e = *i;
720  if (checkExpression(e))
721  {
722  if (!isInteger(e))
723  {
724  handleError(e, "$Integer_expected");
725  }
726  else if (!isCompileTimeComputable(e))
727  {
728  handleError(e, "$Must_be_computable_at_compile_time");
729  }
730  else if (e.changesAnyVariable())
731  {
732  handleError(e, "$Index_must_be_side-effect_free");
733  }
734  }
735  }
736 
737  if (syncUsed == sync_use_t::unused)
738  {
739  if (!iodecl.inputs.empty() || !iodecl.outputs.empty())
740  {
741  syncUsed = sync_use_t::io;
742  }
743  else if (!iodecl.csp.empty())
744  {
745  syncUsed = sync_use_t::csp;
746  }
747  }
748  if (syncUsed == sync_use_t::io)
749  {
750  if (!iodecl.csp.empty())
751  {
752  syncError = true;
753  }
754  }
755  else if (syncUsed == sync_use_t::csp)
756  {
757  if (!iodecl.inputs.empty() || !iodecl.outputs.empty())
758  {
759  syncError = true;
760  }
761  }
762  if (syncError)
763  {
764  handleError(iodecl.csp.front(), "$CSP_and_IO_synchronisations_cannot_be_mixed");
765  }
766 
767  system->setSyncUsed(syncUsed);
768 
769  for(list<expression_t>::iterator i = iodecl.inputs.begin();
770  i != iodecl.inputs.end(); ++i)
771  {
772  if (checkExpression(*i))
773  {
774  type_t channel = i->getType();
775  expression_t expr = *i;
776 
777  // Check that chanElement is a channel, or an array of channels.
778  while (channel.isArray())
779  {
780  channel = channel.getSub();
781  }
782  if (!channel.isChannel())
783  {
784  handleError(expr, "$Channel_expected");
785  }
786 
787  // Check index expressions
788  while (expr.getKind() == ARRAY)
789  {
790  if (!isCompileTimeComputable(expr[1]))
791  {
792  handleError(expr[1], "$Must_be_computable_at_compile_time");
793  }
794  else if (i->changesAnyVariable())
795  {
796  handleError(expr[1], "$Index_must_be_side-effect_free");
797  }
798  expr = expr[0];
799  }
800  }
801  }
802 
803  for(list<expression_t>::iterator i = iodecl.outputs.begin();
804  i != iodecl.outputs.end(); ++i)
805  {
806  if (checkExpression(*i))
807  {
808  type_t channel = i->getType();
809  expression_t expr = *i;
810 
811  // Check that chanElement is a channel, or an array of channels.
812  while (channel.isArray())
813  {
814  channel = channel.getSub();
815  }
816  if (!channel.isChannel())
817  {
818  handleError(expr, "$Channel_expected");
819  }
820 
821  // Check index expressions
822  while (expr.getKind() == ARRAY)
823  {
824  if (!isCompileTimeComputable(expr[1]))
825  {
826  handleError(expr[1], "$Must_be_computable_at_compile_time");
827  }
828  else if (i->changesAnyVariable())
829  {
830  handleError(expr[1], "$Index_must_be_side-effect_free");
831  }
832  expr = expr[0];
833  }
834  }
835  }
836 }
837 
839 {
840  for (size_t i = 0; i < process.unbound; i++)
841  {
842  /* Unbound parameters of processes must be either scalars or
843  * bounded integers.
844  */
845  symbol_t parameter = process.parameters[i];
846  type_t type = parameter.getType();
847  if (!(type.isScalar() || type.isRange()) || type.is(REF))
848  {
849  handleError(type, "$Free_process_parameters_must_be_a_bounded_integer_or_a_scalar");
850  }
851 
852  /* Unbound parameters must not be used either directly or
853  * indirectly in any array size declarations. I.e. they must
854  * not be restricted.
855  */
856  if (process.restricted.find(parameter) != process.restricted.end())
857  {
858  handleError(type, "$Free_process_parameters_must_not_be_used_directly_or_indirectly_in_an_array_declaration_or_select_expression");
859  }
860  }
861 }
862 
864 {
866 
867  checkType(variable.uid.getType());
868  if (variable.expr.isDynamic() || variable.expr.hasDynamicSub ())
869  {
870  handleError (variable.expr,"Dynamic constructions cannot be used as initialisers");
871  }
872  else if (!variable.expr.empty() && checkExpression(variable.expr))
873  {
874  if (!isCompileTimeComputable(variable.expr))
875  {
876  handleError(variable.expr, "$Must_be_computable_at_compile_time");
877  }
878  else if (variable.expr.changesAnyVariable())
879  {
880  handleError(variable.expr, "$Initialiser_must_be_side-effect_free");
881  }
882  else
883  {
884  variable.expr = checkInitialiser(variable.uid.getType(), variable.expr);
885  }
886  }
887 }
888 
890 {
892 
893  if (!state.invariant.empty())
894  {
895  if (checkExpression(state.invariant))
896  {
897  if (!isInvariantWR(state.invariant))
898  {
899  std::string s = "$Expression_of_type ";
900  s += state.invariant.getType().toString();
901  s += " $cannot_be_used_as_an_invariant";
902  handleError(state.invariant, s);
903  }
904  else if (state.invariant.changesAnyVariable())
905  {
906  handleError(state.invariant, "$Invariant_must_be_side-effect_free");
907  }
908  else
909  {
910  RateDecomposer decomposer;
911  decomposer.decompose(state.invariant);
912  state.invariant = decomposer.invariant;
913  state.costRate = decomposer.costRate;
914  if (decomposer.countCostRates > 1)
915  {
916  handleError(state.invariant, "$Only_one_cost_rate_is_allowed");
917  }
918  if (decomposer.hasClockRates)
919  {
920  system->recordStopWatch();
921  }
922  if (decomposer.hasStrictInvariant)
923  {
924  system->recordStrictInvariant();
925 #if ENABLE_TIGA
926  handleWarning(state.invariant, "$Strict_invariant");
927 #endif
928  }
929  }
930  }
931  }
932  if (!state.exponentialRate.empty())
933  {
934  if (checkExpression(state.exponentialRate))
935  {
936  if (!isIntegral(state.exponentialRate) &&
937  state.exponentialRate.getKind() != FRACTION &&
938  !state.exponentialRate.getType().isDouble())
939  {
940  handleError(state.exponentialRate, "$Number_expected");
941  }
942  }
943  }
944 }
945 
947 {
949 
950  // select
951  frame_t select = edge.select;
952  for (size_t i = 0; i < select.getSize(); i++)
953  {
954  checkType(select[i].getType());
955  }
956 
957  // guard
958  bool strictBound = false;
959  if (!edge.guard.empty())
960  {
961  if (checkExpression(edge.guard))
962  {
963  if (!isGuard(edge.guard))
964  {
965  std::string s = "$Expression_of_type ";
966  s += edge.guard.getType().toString();
967  s += " $cannot_be_used_as_a_guard";
968  handleError(edge.guard, s);
969  }
970  else if (edge.guard.changesAnyVariable())
971  {
972  handleError(edge.guard, "$Guard_must_be_side-effect_free");
973  }
974  if (hasStrictLowerBound(edge.guard))
975  {
976  if (edge.control)
977  {
979  }
980  strictBound = true;
981  }
982  if (hasStrictUpperBound(edge.guard))
983  {
984  strictBound = true;
985  }
986  }
987  }
988 
989  // sync
990  if (!edge.sync.empty())
991  {
992  if (checkExpression(edge.sync))
993  {
994  type_t channel = edge.sync.get(0).getType();
995  if (!channel.isChannel())
996  {
997  handleError(edge.sync.get(0), "$Channel_expected");
998  }
999  else if (edge.sync.changesAnyVariable())
1000  {
1001  handleError(edge.sync,
1002  "$Synchronisation_must_be_side-effect_free");
1003  }
1004  else
1005  {
1006  bool hasClockGuard =
1007  !edge.guard.empty() && !isIntegral(edge.guard);
1008  bool isUrgent = channel.is(URGENT);
1009  bool receivesBroadcast = channel.is(BROADCAST)
1010  && edge.sync.getSync() == SYNC_QUE;
1011 
1012  if (isUrgent && hasClockGuard)
1013  {
1014  system->setUrgentTransition();
1015  handleWarning(edge.sync,
1016  "$Clock_guards_are_not_allowed_on_urgent_edges");
1017  }
1018  else if (receivesBroadcast && hasClockGuard)
1019  {
1020  system->clockGuardRecvBroadcast();
1021  /*
1022  This is now allowed, though it is expensive.
1023 
1024  handleError(edge.sync,
1025  "$Clock_guards_are_not_allowed_on_broadcast_receivers");
1026  */
1027  }
1028  if (receivesBroadcast && edge.guard.isTrue())
1029  {
1030  if (edge.dst == NULL)
1031  { // dst is null at least in a case of branchpoint
1032  handleWarning(edge.sync,
1033  "SMC requires input edges to be deterministic");
1034  }
1035 #ifndef NDEBUG
1036  else if (!edge.dst->invariant.isTrue())
1037  {
1038  // This case is not handled correctly by the engine and it is expensive to fix.
1039  handleWarning(edge.sync,
1040  "$It_may_be_needed_to_add_a_guard_involving_the_target_invariant");
1041  }
1042  /*
1043  The warning above gives too many false alarms and is therefore disabled.
1044  In particular it does not consider the common idiom of clock reset (i.e. guard is irrelevant).
1045  Details: the above case may lead to violation of target invariant if unchecked,
1046  however the invariant *is* being checked in the engine and halts with
1047  "violates model sanity with transition" + proper diagnostics about the transition and location.
1048  */
1049 #endif /* NDEBUG */
1050  }
1051  if (isUrgent && strictBound)
1052  {
1053  handleWarning(edge.guard,
1054  "$Strict_bounds_on_urgent_edges_may_not_make_sense");
1055  }
1056  }
1057 
1058  switch(syncUsed)
1059  {
1060  case sync_use_t::unused:
1061  switch(edge.sync.getSync())
1062  {
1063  case SYNC_BANG:
1064  case SYNC_QUE:
1065  syncUsed = sync_use_t::io;
1066  break;
1067  case SYNC_CSP:
1068  syncUsed = sync_use_t::csp;
1069  break;
1070  }
1071  break;
1072  case sync_use_t::io:
1073  switch(edge.sync.getSync())
1074  {
1075  case SYNC_BANG:
1076  case SYNC_QUE:
1077  // ok
1078  break;
1079  case SYNC_CSP:
1080  syncError = true;
1081  handleError(edge.sync, "$Assumed_IO_but_found_CSP_synchronization");
1082  break;
1083  }
1084  break;
1085  case sync_use_t::csp:
1086  switch(edge.sync.getSync())
1087  {
1088  case SYNC_BANG:
1089  case SYNC_QUE:
1090  syncError = true;
1091  handleError(edge.sync, "$Assumed_CSP_but_found_IO_synchronization");
1092  break;
1093  case SYNC_CSP:
1094  // ok
1095  break;
1096  }
1097  break;
1098  default:
1099  // nothing
1100  ;
1101  }
1102 
1103  if (refinementWarnings)
1104  {
1105  if (edge.sync.getSync() == SYNC_BANG)
1106  {
1107  if (edge.control)
1108  {
1109  handleWarning(edge.sync,
1110  "$Outputs_should_be_uncontrollable_for_refinement_checking");
1111  }
1112  }
1113  else if (edge.sync.getSync() == SYNC_QUE)
1114  {
1115  if (!edge.control)
1116  {
1117  handleWarning(edge.sync,
1118  "$Inputs_should_be_controllable_for_refinement_checking");
1119  }
1120  }
1121  else
1122  {
1123  handleWarning(edge.sync,
1124  "$CSP_synchronisations_are_incompatible_with_refinement_checking");
1125  }
1126  }
1127  }
1128  }
1129 
1130  // assignment
1131  checkAssignmentExpression(edge.assign);
1132 
1133 #ifdef ENABLE_PROB
1134  // probability
1135  if (!edge.prob.empty())
1136  {
1137  if (checkExpression(edge.prob))
1138  {
1139  if (!isProbability(edge.prob))
1140  {
1141  std::string s = "$Expression_of_type ";
1142  s += edge.prob.getType().toString();
1143  s += " $cannot_be_used_as_a_probability";
1144  handleError(edge.prob, s);
1145  }
1146  else if (edge.prob.changesAnyVariable())
1147  {
1148  handleError(edge.prob, "$Probability_must_be_side-effect_free");
1149  }
1150  }
1151  }
1152 #endif
1153 }
1154 
1157 }
1158 
1160  SystemVisitor::visitMessage(message);
1161 
1162  if (!message.label.empty())
1163  {
1164  if (checkExpression(message.label))
1165  {
1166  type_t channel = message.label.get(0).getType();
1167  if (!channel.isChannel())
1168  {
1169  handleError(message.label.get(0), "$Channel_expected");
1170  }
1171  else if (message.label.changesAnyVariable())
1172  {
1173  handleError(message.label,
1174  "$Message_must_be_side-effect_free");
1175  }
1176  }
1177  }
1178 }
1180  SystemVisitor::visitCondition(condition);
1181  if (!condition.label.empty())
1182  {
1183  if (checkExpression(condition.label))
1184  {
1185  if (!isGuard(condition.label))
1186  {
1187  std::string s = "$Expression_of_type ";
1188  s += condition.label.getType().toString();
1189  s += " $cannot_be_used_as_a_condition";
1190  handleError(condition.label, s);
1191  }
1192  else if (condition.label.changesAnyVariable())
1193  {
1194  handleError(condition.label, "$Condition_must_be_side-effect_free");
1195  }
1196  }
1197  }
1198 }
1201  if (!update.label.empty())
1202  {
1203  checkAssignmentExpression(update.label);
1204  }
1205 }
1206 
1208 {
1209  checkExpression(progress.guard);
1210  checkExpression(progress.measure);
1211 
1212  if (!progress.guard.empty() && !isIntegral(progress.guard))
1213  {
1214  handleError(progress.guard,
1215  "$Progress_guard_must_evaluate_to_a_boolean");
1216  }
1217 
1218  if (!isIntegral(progress.measure))
1219  {
1220  handleError(progress.measure,
1221  "$Progress_measure_must_evaluate_to_a_value");
1222  }
1223 }
1224 
1226 {
1227  size_t n = gc.parameters.getSize();
1228  for(size_t i = 0; i < n; ++i)
1229  {
1230  checkType(gc.parameters[i].getType());
1231  }
1232 
1233  std::list<ganttmap_t>::const_iterator first, end = gc.mapping.end();
1234  for(first = gc.mapping.begin(); first != end; ++first)
1235  {
1236  n = (*first).parameters.getSize();
1237  for(size_t i = 0; i < n; ++i)
1238  {
1239  checkType((*first).parameters[i].getType());
1240  }
1241 
1242  const expression_t &p = (*first).predicate;
1243  checkExpression(p);
1244  if (!isIntegral(p) && !isConstraint(p))
1245  {
1246  handleError(p, "$Boolean_expected");
1247  }
1248 
1249  const expression_t &m = (*first).mapping;
1250  checkExpression(m);
1251  if (!isIntegral(m))
1252  {
1253  handleError(m, "$Integer_expected");
1254  }
1255  }
1256 }
1257 
1259 {
1260  SystemVisitor::visitInstance(instance);
1261 
1262  /* Check the parameters of the instance.
1263  */
1264  type_t type = instance.uid.getType();
1265  for (size_t i = 0; i < type.size(); i++)
1266  {
1267  checkType(type[i]);
1268  }
1269 
1270  /* Check arguments.
1271  */
1272  for (size_t i = type.size(); i < type.size() + instance.arguments; i++)
1273  {
1274  symbol_t parameter = instance.parameters[i];
1275  expression_t argument = instance.mapping[parameter];
1276 
1277  if (!checkExpression(argument))
1278  {
1279  continue;
1280  }
1281 
1282  // For template instantiation, the argument must be side-effect free
1283  if (argument.changesAnyVariable())
1284  {
1285  handleError(argument, "$Argument_must_be_side-effect_free");
1286  continue;
1287  }
1288 
1289  // We have three ok cases:
1290  // - Value parameter with computable argument
1291  // - Constant reference with computable argument
1292  // - Reference parameter with unique lhs argument
1293  // If non of the cases are true, then we generate an error
1294  bool ref = parameter.getType().is(REF);
1295  bool constant = parameter.getType().isConstant();
1296  bool computable = isCompileTimeComputable(argument);
1297 
1298  if ((!ref && !computable)
1299  || (ref && !constant && !isUniqueReference(argument))
1300  || (ref && constant && !computable))
1301  {
1302  handleError(argument, "$Incompatible_argument");
1303  continue;
1304  }
1305 
1306  checkParameterCompatible(parameter.getType(), argument);
1307  }
1308 }
1309 
1310 static bool isGameProperty(expression_t expr)
1311 {
1312  switch(expr.getKind())
1313  {
1314  case CONTROL:
1315  case SMC_CONTROL:
1316  case EF_CONTROL:
1317  case CONTROL_TOPT:
1318  case PO_CONTROL:
1319  case CONTROL_TOPT_DEF1:
1320  case CONTROL_TOPT_DEF2:
1321  case SIMULATION_LE:
1322  case SIMULATION_GE:
1323  case REFINEMENT_LE:
1324  case REFINEMENT_GE:
1325  case CONSISTENCY:
1326  case IMPLEMENTATION:
1327  case SPECIFICATION:
1328  return true;
1329  default:
1330  return false;
1331  }
1332 }
1333 
1334 
1336 {
1337  bool hasIt = (expr.getKind () == MITLFORALL || expr.getKind () == MITLEXISTS);
1338  if (!hasIt)
1339  {
1340  for (uint32_t i = 0; i < expr.getSize(); i++)
1341  {
1342  hasIt |= hasMITLInQuantifiedSub (expr.get(i));
1343  }
1344  }
1345  return hasIt;
1346 }
1347 
1348 static bool hasSpawnOrExit(expression_t expr) {
1349  bool hasIt = (expr.getKind () == SPAWN || expr.getKind () == EXIT);
1350  if (!hasIt)
1351  {
1352  for (uint32_t i = 0; i < expr.getSize(); i++)
1353  {
1354  hasIt |= hasSpawnOrExit (expr.get(i));
1355  }
1356  }
1357  return hasIt;
1358 }
1359 
1361 {
1362  if (checkExpression(expr))
1363  {
1364  if (expr.changesAnyVariable())
1365  {
1366  handleError(expr, "$Property_must_be_side-effect_free");
1367  }
1368  if (!((expr.getType().is(TIOGRAPH) && expr.getKind() == CONSISTENCY) ||
1369  isFormula(expr)))
1370  {
1371  handleError(expr, "$Property_must_be_a_valid_formula");
1372  }
1373  if (isGameProperty(expr))
1374  {
1375  /*
1376  for (uint32_t i = 0; i < expr.getSize(); i++)
1377  {
1378  if (isFormula(expr[i]))
1379  {
1380  for (uint32_t j = 0; j < expr[i].getSize(); j++)
1381  {
1382  if (!isConstraint(expr[i][j]))
1383  {
1384  handleError(expr[i][j], "$Nesting_of_path_quantifiers_is_not_allowed");
1385  }
1386  }
1387  }
1388  }
1389  */
1390  }
1391  else if (expr.getKind() != SUP_VAR &&
1392  expr.getKind() != INF_VAR &&
1393  expr.getKind() != SCENARIO &&
1394  expr.getKind() != PROBAMINBOX &&
1395  expr.getKind() != PROBAMINDIAMOND &&
1396  expr.getKind() != PROBABOX &&
1397  expr.getKind() != PROBADIAMOND &&
1398  expr.getKind() != PROBAEXP &&
1399  expr.getKind() != PROBACMP &&
1400  expr.getKind() != SIMULATE &&
1401  expr.getKind() != SIMULATEREACH &&
1402  expr.getKind() != MITLFORMULA)
1403  {
1404  for (uint32_t i = 0; i < expr.getSize(); i++)
1405  {
1406  /* No nesting except for constraints */
1407  if (!isConstraint(expr[i]))
1408  {
1409  handleError(expr[i], "$Nesting_of_path_quantifiers_is_not_allowed");
1410  }
1411  }
1412  }
1413  if (expr.getKind() == PO_CONTROL)
1414  {
1415  /* Observations on clock constraints are limited to be
1416  * weak for lower bounds and strict for upper bounds.
1417  */
1418  checkObservationConstraints(expr);
1419  }
1420  if (hasMITLInQuantifiedSub (expr) && expr.getKind () != MITLFORMULA)
1421  {
1422  handleError(expr, "MITL inside forall or exists in non-MITL property");
1423 
1424  }
1425  }
1426 }
1427 
1444 bool TypeChecker::checkAssignmentExpression(expression_t expr)
1445 {
1446  if (!checkExpression(expr))
1447  {
1448  return false;
1449  }
1450 
1451  if (!isAssignable(expr.getType()) && !isVoid(expr))
1452  {
1453  handleError(expr, "$Invalid_assignment_expression");
1454  return false;
1455  }
1456 
1457  if (expr.getKind() != CONSTANT || expr.getValue() != 1)
1458  {
1459  checkIgnoredValue(expr);
1460  }
1461 
1462  return true;
1463 }
1464 
1466 bool TypeChecker::checkConditionalExpressionInFunction(expression_t expr)
1467 {
1468  if (!isIntegral(expr))
1469  {
1470  handleError(expr, "$Boolean_expected");
1471  return false;
1472  }
1473  return true;
1474 }
1475 
1476 
1477 void TypeChecker::checkObservationConstraints(expression_t expr)
1478 {
1479  for(size_t i = 0; i < expr.getSize(); ++i)
1480  {
1481  checkObservationConstraints(expr[i]);
1482  }
1483 
1484  bool invalid = false;
1485 
1486  switch(expr.getKind())
1487  {
1488  case LT: // int < clock
1489  case GE: // int >= clock
1490  invalid = isIntegral(expr[0]) && isClock(expr[1]);
1491  break;
1492 
1493  case LE: // clock <= int
1494  case GT: // clock > int
1495  invalid = isClock(expr[0]) && isIntegral(expr[1]);
1496  break;
1497 
1498  case EQ: // clock == int || int == clock
1499  case NEQ: // clock != int || int != clock
1500  invalid = (isClock(expr[0]) && isIntegral(expr[1]))
1501  || (isIntegral(expr[0]) && isClock(expr[1]));
1502  break;
1503 
1504  default: ;
1505  }
1506 
1507  if (invalid)
1508  {
1509  handleError(expr, "$Clock_lower_bound_must_be_weak_and_upper_bound_strict");
1510  }
1511  else
1512  {
1513  switch(expr.getKind()) // No clock differences.
1514  {
1515  case LT:
1516  case LE:
1517  case GT:
1518  case GE:
1519  case EQ:
1520  case NEQ:
1521  if ((isClock(expr[0]) && isClock(expr[1])) ||
1522  (isDiff(expr[0]) && isInteger(expr[1])) ||
1523  (isInteger(expr[0]) && isDiff(expr[1])))
1524  {
1525  handleError(expr, "$Clock_differences_are_not_supported");
1526  }
1527  break;
1528 
1529  default: ;
1530  }
1531  }
1532 }
1533 
1534 
1535 static bool validReturnType(type_t type)
1536 {
1537  frame_t frame;
1538 
1539  switch (type.getKind())
1540  {
1541  case Constants::RECORD:
1542  for (size_t i = 0; i < type.size(); i++)
1543  {
1544  if (!validReturnType(type[i]))
1545  {
1546  return false;
1547  }
1548  }
1549  return true;
1550 
1551  case Constants::RANGE:
1552  case Constants::LABEL:
1553  return validReturnType(type[0]);
1554 
1555  case Constants::INT:
1556  case Constants::BOOL:
1557  case Constants::SCALAR:
1558  case Constants::DOUBLE:
1559  return true;
1560 
1561  default:
1562  return false;
1563  }
1564 }
1565 
1567 {
1569  /* Check that the return type is consistent and is a valid return
1570  * type.
1571  */
1572  type_t return_type = fun.uid.getType()[0];
1573  checkType(return_type);
1574  if (!return_type.isVoid() && !validReturnType(return_type))
1575  {
1576  handleError(return_type, "$Invalid_return_type");
1577  }
1578 
1579  /* Type check the function body: Type checking return statements
1580  * requires access to the return type, hence we store a pointer to
1581  * the current function being type checked in the \a function
1582  * member.
1583  */
1584  function = &fun;
1585  fun.body->accept(this);
1586  function = NULL;
1587 
1588  /* Check if there are dynamic expressions in the function body*/
1590 
1591  /* Collect identifiers of things external to the function accessed
1592  * or changed by the function. Notice that neither local variables
1593  * nor parameters are considered to be changed or accessed by a
1594  * function.
1595  */
1596  CollectChangesVisitor visitor(fun.changes);
1597  fun.body->accept(&visitor);
1598 
1599  CollectDependenciesVisitor visitor2(fun.depends);
1600  fun.body->accept(&visitor2);
1601 
1602  list<variable_t> &vars = fun.variables;
1603  for (list<variable_t>::iterator i = vars.begin(); i != vars.end(); i++)
1604  {
1605  fun.changes.erase(i->uid);
1606  fun.depends.erase(i->uid);
1607  }
1608  size_t parameters = fun.uid.getType().size() - 1;
1609  for (size_t i = 0; i < parameters; i++)
1610  {
1611  fun.changes.erase(fun.body->getFrame()[i]);
1612  fun.depends.erase(fun.body->getFrame()[i]);
1613  }
1614 }
1615 
1617 {
1618  return 0;
1619 }
1620 
1622 {
1623  checkAssignmentExpression(stat->expr);
1624  return 0;
1625 }
1626 
1628 {
1629  if (checkExpression(stat->expr) && stat->expr.changesAnyVariable())
1630  {
1631  handleError(stat->expr, "$Assertion_must_be_side-effect_free");
1632  }
1633  return 0;
1634 }
1635 
1637 {
1638  checkAssignmentExpression(stat->init);
1639 
1640  if (checkExpression(stat->cond))
1641  {
1642  checkConditionalExpressionInFunction(stat->cond);
1643  }
1644 
1645  checkAssignmentExpression(stat->step);
1646 
1647  return stat->stat->accept(this);
1648 }
1649 
1651 {
1652  type_t type = stat->symbol.getType();
1653  checkType(type);
1654 
1655  /* We only support iteration over scalars and integers.
1656  */
1657  if (!type.isScalar() && !type.isInteger())
1658  {
1659  handleError(type, "$Scalar_set_or_integer_expected");
1660  }
1661  else if (!type.is(RANGE))
1662  {
1663  handleError(type, "$Range_expected");
1664  }
1665 
1666  return stat->stat->accept(this);
1667 }
1668 
1670 {
1671  if (checkExpression(stat->cond))
1672  {
1673  checkConditionalExpressionInFunction(stat->cond);
1674  }
1675  return stat->stat->accept(this);
1676 }
1677 
1679 {
1680  if (checkExpression(stat->cond))
1681  {
1682  checkConditionalExpressionInFunction(stat->cond);
1683  }
1684  return stat->stat->accept(this);
1685 }
1686 
1688 {
1689  /* Check type and initialiser of local variables (parameters are
1690  * also considered local variables).
1691  */
1692  frame_t frame = stat->getFrame();
1693  for (uint32_t i = 0; i < frame.getSize(); ++i)
1694  {
1695  symbol_t symbol = frame[i];
1696  checkType(symbol.getType());
1697  if (symbol.getData())
1698  {
1699  variable_t *var = static_cast<variable_t*>(symbol.getData());
1700  if (!var->expr.empty() && checkExpression(var->expr))
1701  {
1702  if (var->expr.changesAnyVariable())
1703  {
1704  /* This is stronger than C. However side-effects in
1705  * initialisers are nasty: For records, the evaluation
1706  * order may be different from the order in the input
1707  * file.
1708  */
1709  handleError(var->expr, "$Initialiser_must_be_side-effect_free");
1710  }
1711  else
1712  {
1713  var->expr = checkInitialiser(symbol.getType(), var->expr);
1714  }
1715  }
1716  }
1717  }
1718 
1719  /* Check statements.
1720  */
1721  for (auto* blockstatement : *stat)
1722  blockstatement->accept(this);
1723  return 0;
1724 }
1725 
1727 {
1728  if (checkExpression(stat->cond))
1729  {
1730  checkConditionalExpressionInFunction(stat->cond);
1731  }
1732  stat->trueCase->accept(this);
1733  if (stat->falseCase)
1734  {
1735  stat->falseCase->accept(this);
1736  }
1737  return 0;
1738 }
1739 
1741 {
1742  if (!stat->value.empty())
1743  {
1744  checkExpression(stat->value);
1745 
1746  /* The only valid return types are integers and records. For these
1747  * two types, the type rules are the same as for parameters.
1748  */
1749  type_t return_type = function->uid.getType()[0];
1750  checkParameterCompatible(return_type, stat->value);
1751  }
1752  return 0;
1753 }
1754 
1761 static int channelCapability(type_t type)
1762 {
1763  assert(type.isChannel());
1764  if (type.is(URGENT))
1765  {
1766  return 0;
1767  }
1768  if (type.is(BROADCAST))
1769  {
1770  return 1;
1771  }
1772  return 2;
1773 }
1774 
1778 static bool isSameScalarType(type_t t1, type_t t2)
1779 {
1780  if (t1.getKind() == REF || t1.getKind() == CONSTANT || t1.getKind() == SYSTEM_META)
1781  {
1782  return isSameScalarType(t1[0], t2);
1783  }
1784  else if (t2.getKind() == EF || t2.getKind() == CONSTANT || t2.getKind() == SYSTEM_META)
1785  {
1786  return isSameScalarType(t1, t2[0]);
1787  }
1788  else if (t1.getKind() == LABEL && t2.getKind() == LABEL)
1789  {
1790  return t1.getLabel(0) == t2.getLabel(0)
1791  && isSameScalarType(t1[0], t2[0]);
1792  }
1793  else if (t1.getKind() == SCALAR && t2.getKind() == SCALAR)
1794  {
1795  return true;
1796  }
1797  else if (t1.getKind() == RANGE && t2.getKind() == RANGE)
1798  {
1799  return isSameScalarType(t1[0], t2[0])
1800  && t1.getRange().first.equal(t2.getRange().first)
1801  && t1.getRange().second.equal(t2.getRange().second);
1802  }
1803  else
1804  {
1805  return false;
1806  }
1807 }
1808 
1812 bool TypeChecker::isParameterCompatible(type_t paramType, expression_t arg)
1813 {
1814  bool ref = paramType.is(REF);
1815  bool constant = paramType.isConstant();
1816  bool lvalue = isModifiableLValue(arg);
1817  type_t argType = arg.getType();
1818  // For non-const reference parameters, we require a modifiable
1819  // lvalue argument
1820  if (ref && !constant && !lvalue)
1821  {
1822  return false;
1823  }
1824 
1825  if (paramType.isChannel() && argType.isChannel())
1826  {
1827  return channelCapability(argType) >= channelCapability(paramType);
1828  }
1829  else if (ref && lvalue)
1830  {
1831  return areEquivalent(argType, paramType);
1832  }
1833  else
1834  {
1835  return areAssignmentCompatible(paramType, argType);
1836  }
1837 }
1838 
1842 bool TypeChecker::checkParameterCompatible(type_t paramType, expression_t arg)
1843 {
1844  if (!isParameterCompatible(paramType, arg))
1845  {
1846  handleError(arg, "$Incompatible_argument");
1847  return false;
1848  }
1849  return true;
1850 }
1851 
1859 expression_t TypeChecker::checkInitialiser(type_t type, expression_t init)
1860 {
1861  if (areAssignmentCompatible(type, init.getType(), true))
1862  {
1863  return init;
1864  }
1865  else if (type.isArray() && init.getKind() == LIST)
1866  {
1867  type_t subtype = type.getSub();
1868  vector<expression_t> result(init.getSize(), expression_t());
1869  for (uint32_t i = 0; i < init.getType().size(); i++)
1870  {
1871  if (!init.getType().getLabel(i).empty())
1872  {
1873  handleError(
1874  init[i], "$Field_name_not_allowed_in_array_initialiser");
1875  }
1876  result[i] = checkInitialiser(subtype, init[i]);
1877  }
1878  return expression_t::createNary(
1879  LIST, result, init.getPosition(), type);
1880  }
1881  else if (type.isRecord() || init.getKind() == LIST)
1882  {
1883  /* In order to access the record labels we have to strip any
1884  * prefixes and labels from the record type.
1885  */
1886  vector<expression_t> result(type.getRecordSize(), expression_t());
1887  int32_t current = 0;
1888  for (uint32_t i = 0; i < init.getType().size(); i++, current++)
1889  {
1890  std::string label = init.getType().getLabel(i);
1891  if (!label.empty())
1892  {
1893  current = type.findIndexOf(label);
1894  if (current == -1)
1895  {
1896  handleError(init[i], "$Unknown_field");
1897  break;
1898  }
1899  }
1900 
1901  if (current >= (int32_t)type.getRecordSize())
1902  {
1903  handleError(init[i], "$Too_many_elements_in_initialiser");
1904  break;
1905  }
1906 
1907  if (!result[current].empty())
1908  {
1909  handleError(init[i], "$Multiple_initialisers_for_field");
1910  continue;
1911  }
1912 
1913  result[current] = checkInitialiser(type.getSub(current), init[i]);
1914  }
1915 
1916  // Check that all fields do have an initialiser.
1917  for (size_t i = 0; i < result.size(); i++)
1918  {
1919  if (result[i].empty())
1920  {
1921  handleError(init, "$Incomplete_initialiser");
1922  break;
1923  }
1924  }
1925 
1926  return expression_t::createNary(
1927  LIST, result, init.getPosition(), type);
1928  }
1929  handleError(init, "$Invalid_initialiser");
1930  return init;
1931 }
1932 
1939 bool TypeChecker::areInlineIfCompatible(type_t t1, type_t t2) const
1940 {
1941  if (t1.isIntegral() && t2.isIntegral())
1942  {
1943  return true;
1944  }
1945  else
1946  {
1947  return areEquivalent(t1, t2);
1948  }
1949 }
1950 
1956 bool TypeChecker::areEquivalent(type_t a, type_t b) const
1957 {
1958  if (a.isInteger() && b.isInteger())
1959  {
1960  return !a.is(RANGE)
1961  || !b.is(RANGE)
1962  || (a.getRange().first.equal(b.getRange().first)
1963  && a.getRange().second.equal(b.getRange().second));
1964  }
1965  else if (a.isBoolean() && b.isBoolean())
1966  {
1967  return true;
1968  }
1969  else if (a.isClock() && b.isClock())
1970  {
1971  return true;
1972  }
1973  else if (a.isChannel() && b.isChannel())
1974  {
1975  return channelCapability(a) == channelCapability(b);
1976  }
1977  else if (a.isRecord() && b.isRecord())
1978  {
1979  size_t aSize = a.getRecordSize();
1980  size_t bSize = b.getRecordSize();
1981  if (aSize == bSize)
1982  {
1983  for (size_t i = 0; i < aSize; i++)
1984  {
1985  if (a.getRecordLabel(i) != b.getRecordLabel(i)
1986  || !areEquivalent(a.getSub(i), b.getSub(i)))
1987  {
1988  return false;
1989  }
1990  }
1991  return true;
1992  }
1993  }
1994  else if (a.isArray() && b.isArray())
1995  {
1996  type_t asize = a.getArraySize();
1997  type_t bsize = b.getArraySize();
1998 
1999  if (asize.isInteger() && bsize.isInteger())
2000  {
2001  return asize.getRange().first.equal(bsize.getRange().first)
2002  && asize.getRange().second.equal(bsize.getRange().second)
2003  && areEquivalent(a.getSub(), b.getSub());
2004  }
2005  else if (asize.isScalar() && bsize.isScalar())
2006  {
2007  return isSameScalarType(asize, bsize)
2008  && areEquivalent(a.getSub(), b.getSub());
2009  }
2010  return false;
2011  }
2012  else if (a.isScalar() && b.isScalar())
2013  {
2014  return isSameScalarType(a, b);
2015  }
2016  else if (a.isDouble() && b.isDouble())
2017  {
2018  return true;
2019  }
2020 
2021  return false;
2022 }
2023 
2030 bool TypeChecker::areAssignmentCompatible(type_t lvalue, type_t rvalue, bool init) const
2031 {
2032  if (init
2033  ? (lvalue.isClock() && rvalue.isDouble())
2034  : ((lvalue.isClock() || lvalue.isDouble()) &&
2035  (rvalue.isIntegral() || rvalue.isDouble() || rvalue.isClock())))
2036  {
2037  return true;
2038  }
2039  else if (lvalue.isIntegral() && rvalue.isIntegral())
2040  {
2041  return true;
2042  }
2043  return areEquivalent(lvalue, rvalue);
2044 }
2045 
2059 bool TypeChecker::areEqCompatible(type_t t1, type_t t2) const
2060 {
2061  if (t1.isIntegral() && t2.isIntegral())
2062  {
2063  return true;
2064  }
2065  else if (t1.is(PROCESSVAR) && t2.is(PROCESSVAR))
2066  {
2067  return true;
2068  }
2069  else
2070  {
2071  return areEquivalent(t1, t2);
2072  }
2073 }
2074 
2075 static bool isProcessID(expression_t expr)
2076 {
2077  return expr.getKind() == IDENTIFIER && expr.getType().is(PROCESS);
2078 }
2079 
2080 static bool checkIDList(expression_t expr, kind_t kind)
2081 {
2082  if (expr.getKind() != LIST)
2083  {
2084  return false;
2085  }
2086  for(uint32_t j = 0; j < expr.getSize(); ++j)
2087  {
2088  if (!isProcessID(expr[j]))
2089  {
2090  return false;
2091  }
2092  }
2093  return true;
2094 }
2095 
2109 {
2110  /* Do not checkExpression empty expressions.
2111  */
2112  if (expr.empty())
2113  {
2114  return true;
2115  }
2116 
2117  /* CheckExpression sub-expressions.
2118  */
2119  bool ok = true;
2120  for (uint32_t i = 0; i < expr.getSize(); i++)
2121  {
2122  ok &= checkExpression(expr[i]);
2123  }
2124 
2125  /* Do not checkExpression the expression if any of the sub-expressions
2126  * contained errors.
2127  */
2128  if (!ok)
2129  {
2130  return false;
2131  }
2132 
2133  /* CheckExpression the expression. This depends on the kind of expression
2134  * we are dealing with.
2135  */
2136  type_t type, arg1, arg2, arg3;
2137  switch (expr.getKind())
2138  {
2139  // It is possible to have DOT expressions as data.x
2140  // with data being an array of struct. The type checker
2141  // is broken and trying
2142  // expr[0].getType().isRecord() or
2143  // expr[0].isProcess() cannot detect this.
2144  // This should be fixed one day.
2145  /*
2146  case DOT:
2147  if (expr[0].getType().isProcess(Constants::PROCESS) ||
2148  expr[0].getType().is(Constants::RECORD))
2149  {
2150  return true;
2151  }
2152  else
2153  {
2154  handleError(expr, "$Invalid_type");
2155  return false;
2156  }
2157  */
2158  case SUMDYNAMIC:
2159  if (isIntegral(expr[2]) || isDoubleValue (expr[2]))
2160  {
2161  type = expr[2].getType ();
2162  }
2163  else if (isInvariant (expr[2]) || isGuard (expr[2]))
2164  {
2166  }
2167  else {
2168  handleError (expr,"A sum can only be made over integer, double, invariant or guard expressions.");
2169  return false;
2170  }
2171  break;
2172  case FRACTION:
2173  if (isIntegral(expr[0]) && isIntegral(expr[1]))
2174  {
2176  }
2177  break;
2178 
2179  case PLUS:
2180  if (isIntegral(expr[0]) && isIntegral(expr[1]))
2181  {
2183  }
2184  else if ((isInteger(expr[0]) && isClock(expr[1]))
2185  || (isClock(expr[0]) && isInteger(expr[1])))
2186  {
2188  }
2189  else if ((isDiff(expr[0]) && isInteger(expr[1]))
2190  || (isInteger(expr[0]) && isDiff(expr[1])))
2191  {
2192  type = type_t::createPrimitive(DIFF);
2193  }
2194  else if (isNumber(expr[0]) && isNumber(expr[1]))
2195  {
2196  // SMC extension.
2198  }
2199  break;
2200 
2201  case MINUS:
2202  if (isIntegral(expr[0]) && isIntegral(expr[1]))
2203  {
2205  }
2206  else if (isClock(expr[0]) && isInteger(expr[1]))
2207  // removed "|| isInteger(expr[0].type) && isClock(expr[1].type)"
2208  // in order to be able to convert into ClockGuards
2209  {
2211  }
2212  else if ((isDiff(expr[0]) && isInteger(expr[1]))
2213  || (isInteger(expr[0]) && isDiff(expr[1]))
2214  || (isClock(expr[0]) && isClock(expr[1])))
2215  {
2216  type = type_t::createPrimitive(DIFF);
2217  }
2218  else if (isNumber(expr[0]) && isNumber(expr[1]))
2219  {
2220  // SMC extension.
2221  // x-y with that semantic should be written x+(-y)
2223  }
2224  break;
2225 
2226  case AND:
2227  if (isIntegral(expr[0]) && isIntegral(expr[1]))
2228  {
2230  }
2231  else if (isInvariant(expr[0]) && isInvariant(expr[1]))
2232  {
2234  }
2235  else if (isInvariantWR(expr[0]) && isInvariantWR(expr[1]))
2236  {
2238  }
2239  else if (isGuard(expr[0]) && isGuard(expr[1]))
2240  {
2242  }
2243  else if (isConstraint(expr[0]) && isConstraint(expr[1]))
2244  {
2246  }
2247  else if (isFormula(expr[0]) && isFormula(expr[1]))
2248  {
2250  }
2251  break;
2252 
2253  case OR:
2254  if (isIntegral(expr[0]) && isIntegral(expr[1]))
2255  {
2257  }
2258  else if (isIntegral(expr[0]) && isInvariant(expr[1]))
2259  {
2261  }
2262  else if (isInvariant(expr[0]) && isIntegral(expr[1]))
2263  {
2265  }
2266  else if (isIntegral(expr[0]) && isInvariantWR(expr[1]))
2267  {
2269  }
2270  else if (isInvariantWR(expr[0]) && isIntegral(expr[1]))
2271  {
2273  }
2274  else if (isIntegral(expr[0]) && isGuard(expr[1]))
2275  {
2277  }
2278  else if (isGuard(expr[0]) && isIntegral(expr[1]))
2279  {
2281  }
2282  else if (isConstraint(expr[0]) && isConstraint(expr[1]))
2283  {
2285  }
2286  break;
2287 
2288  case XOR:
2289  if (isIntegral(expr[0]) && isIntegral(expr[1]))
2290  {
2292  }
2293  break;
2294 
2295  case SPAWN: {
2296  template_t* temp = system->getDynamicTemplate(expr[0].getSymbol().getName());
2297  if (!temp) {
2298  handleError(expr, "Appears as an attempt to spawn a non-dynamic template");
2299  return false;
2300  }
2301  if (temp->parameters.getSize() != expr.getSize()-1) {
2302  handleError(expr, "Wrong number of arguments");
2303  return false;
2304  }
2305  for (size_t i = 0; i<temp->parameters.getSize(); i++) {
2306  if (!checkSpawnParameterCompatible(temp->parameters[i].getType(),
2307  expr[i+1]))
2308  {
2309  return false;
2310  }
2311  }
2312 
2313  /* check that spawn is only made for templates with definitions*/
2314  if (!temp->isDefined) {
2315  handleError (expr,"Template is only declared - not defined");
2316  return false;
2317  }
2319  break;
2320  }
2321 
2322  case NUMOF: {
2323  template_t* temp = system->getDynamicTemplate (expr[0].getSymbol ().getName ());
2324  if (temp) {
2326  }
2327  else
2328  {
2329  handleError (expr,"Not a dynamic template");
2330  return false;
2331  }
2332  break;
2333  }
2334 
2335  case EXIT:
2336  {
2337  assert(temp);
2338  if (!temp->dynamic) {
2339  handleError (expr,"Exit can only be used in templates declared as dynamic");
2340  return false;
2341  }
2342 
2344 
2345  break;
2346  }
2347 
2348  case EQ:
2349  // FIXME: Apparently the case cost == expr goes through, which is obviously not good.
2350 
2351  if ((isClock(expr[0]) && isClock(expr[1]))
2352  || (isClock(expr[0]) && isInteger(expr[1]))
2353  || (isInteger(expr[0]) && isClock(expr[1]))
2354  || (isDiff(expr[0]) && isInteger(expr[1]))
2355  || (isInteger(expr[0]) && isDiff(expr[1])))
2356  {
2358  }
2359  else if (areEqCompatible(expr[0].getType(), expr[1].getType()))
2360  {
2362  }
2363  else if ((expr[0].getType().is(RATE) &&
2364  (isIntegral(expr[1]) || isDoubleValue(expr[1]))) ||
2365  ((isIntegral(expr[0]) || isDoubleValue(expr[0])) &&
2366  expr[1].getType().is(RATE)))
2367  {
2369  }
2370  else if (isNumber(expr[0]) && isNumber(expr[1]))
2371  {
2373  }
2374  break;
2375 
2376  case NEQ:
2377  if (areEqCompatible(expr[0].getType(), expr[1].getType()))
2378  {
2380  }
2381  else if ((isClock(expr[0]) && isClock(expr[1]))
2382  || (isClock(expr[0]) && isInteger(expr[1]))
2383  || (isInteger(expr[0]) && isClock(expr[1]))
2384  || (isDiff(expr[0]) && isInteger(expr[1]))
2385  || (isInteger(expr[0]) && isDiff(expr[1])))
2386  {
2388  }
2389  else if (isNumber(expr[0]) && isNumber(expr[1]))
2390  {
2392  }
2393  break;
2394 
2395  case GE:
2396  case GT:
2397  case LE:
2398  case LT:
2399  if (isIntegral(expr[0]) && isIntegral(expr[1]))
2400  {
2402  }
2403  else if ((isClock(expr[0]) && isClock(expr[1])) ||
2404  (isClock(expr[0]) && isBound(expr[1])) ||
2405  (isClock(expr[1]) && isBound(expr[0])) ||
2406  (isDiff(expr[0]) && isBound(expr[1])) ||
2407  (isDiff(expr[1]) && isBound(expr[0])))
2408  {
2410  }
2411  else if ((isClock(expr[0]) && isInteger(expr[1])) ||
2412  (isInteger(expr[0]) && isClock(expr[1])))
2413  {
2415  }
2416  else if (isNumber(expr[0]) && isNumber(expr[1]))
2417  {
2419  }
2420  break;
2421 
2422  case MULT:
2423  case DIV:
2424  case MIN:
2425  case MAX:
2426  if (isIntegral(expr[0]) && isIntegral(expr[1]))
2427  {
2429  }
2430  else if (isNumber(expr[0]) && isNumber(expr[1]))
2431  {
2433  }
2434  break;
2435 
2436  case MOD:
2437  case BIT_AND:
2438  case BIT_OR:
2439  case BIT_XOR:
2440  case BIT_LSHIFT:
2441  case BIT_RSHIFT:
2442  if (isIntegral(expr[0]) && isIntegral(expr[1]))
2443  {
2445  }
2446  break;
2447 
2448  case NOT:
2449  if (isIntegral(expr[0]))
2450  {
2452  }
2453  else if (isConstraint(expr[0]))
2454  {
2456  }
2457  break;
2458 
2459  case UNARY_MINUS:
2460  if (isIntegral(expr[0]))
2461  {
2463  }
2464  else if (isNumber(expr[0]))
2465  {
2467  }
2468  break;
2469 
2470  case RATE:
2471  if (isCost(expr[0]) || isClock(expr[0]))
2472  {
2473  type = type_t::createPrimitive(RATE);
2474  }
2475  break;
2476 
2477  case ASSIGN:
2478  if (!areAssignmentCompatible(expr[0].getType(), expr[1].getType()))
2479  {
2480  handleError(expr, "$Incompatible_types");
2481  return false;
2482  }
2483  else if (!isModifiableLValue(expr[0]))
2484  {
2485  handleError(expr[0], "$Left_hand_side_value_expected");
2486  return false;
2487  }
2488  type = expr[0].getType();
2489  break;
2490 
2491  case ASSPLUS:
2492  if ((!isInteger(expr[0]) && !isCost(expr[0])) || !isIntegral(expr[1]))
2493  {
2494  handleError(expr, "$Increment_operator_can_only_be_used_for_integers_and_cost_variables");
2495  }
2496  else if (!isModifiableLValue(expr[0]))
2497  {
2498  handleError(expr[0], "$Left_hand_side_value_expected");
2499  }
2500  type = expr[0].getType();
2501  break;
2502 
2503  case ASSMINUS:
2504  case ASSDIV:
2505  case ASSMOD:
2506  case ASSMULT:
2507  case ASSAND:
2508  case ASSOR:
2509  case ASSXOR:
2510  case ASSLSHIFT:
2511  case ASSRSHIFT:
2512  if (!isIntegral(expr[0]) || !isIntegral(expr[1]))
2513  {
2514  handleError(expr, "$Non-integer_types_must_use_regular_assignment_operator");
2515  return false;
2516  }
2517  else if (!isModifiableLValue(expr[0]))
2518  {
2519  handleError(expr[0], "$Left_hand_side_value_expected");
2520  return false;
2521  }
2522  type = expr[0].getType();
2523  break;
2524 
2525  case POSTINCREMENT:
2526  case PREINCREMENT:
2527  case POSTDECREMENT:
2528  case PREDECREMENT:
2529  if (!isModifiableLValue(expr[0]))
2530  {
2531  handleError(expr[0], "$Left_hand_side_value_expected");
2532  return false;
2533  }
2534  else if (!isInteger(expr[0]))
2535  {
2536  handleError(expr, "$Integer_expected");
2537  return false;
2538  }
2540  break;
2541 
2542  case FMA_F:
2543  case RANDOM_TRI_F:
2544  if (!isNumber(expr[2]))
2545  {
2546  handleError(expr[2], "$Number_expected");
2547  return false;
2548  } // fall-through to check the second argument:
2549  case FMOD_F:
2550  case FMAX_F:
2551  case FMIN_F:
2552  case FDIM_F:
2553  case POW_F:
2554  case HYPOT_F:
2555  case ATAN2_F:
2556  case NEXTAFTER_F:
2557  case COPYSIGN_F:
2558  case RANDOM_ARCSINE_F:
2559  case RANDOM_BETA_F:
2560  case RANDOM_GAMMA_F:
2561  case RANDOM_NORMAL_F:
2562  case RANDOM_WEIBULL_F:
2563  if (!isNumber(expr[1]))
2564  {
2565  handleError(expr[1], "$Number_expected");
2566  return false;
2567  } // fall-through to check the first argument:
2568  case FABS_F:
2569  case EXP_F:
2570  case EXP2_F:
2571  case EXPM1_F:
2572  case LN_F:
2573  case LOG_F:
2574  case LOG10_F:
2575  case LOG2_F:
2576  case LOG1P_F:
2577  case SQRT_F:
2578  case CBRT_F:
2579  case SIN_F:
2580  case COS_F:
2581  case TAN_F:
2582  case ASIN_F:
2583  case ACOS_F:
2584  case ATAN_F:
2585  case SINH_F:
2586  case COSH_F:
2587  case TANH_F:
2588  case ASINH_F:
2589  case ACOSH_F:
2590  case ATANH_F:
2591  case ERF_F:
2592  case ERFC_F:
2593  case TGAMMA_F:
2594  case LGAMMA_F:
2595  case CEIL_F:
2596  case FLOOR_F:
2597  case TRUNC_F:
2598  case ROUND_F:
2599  case LOGB_F:
2600  case RANDOM_F:
2601  case RANDOM_POISSON_F:
2602  if (!isNumber(expr[0]))
2603  {
2604  handleError(expr[0], "$Number_expected");
2605  return false;
2606  }
2608  break;
2609 
2610  case LDEXP_F:
2611  if (!isIntegral(expr[1]))
2612  {
2613  handleError(expr[1], "$Integer_expected");
2614  return false;
2615  }
2616  if (!isNumber(expr[0]))
2617  {
2618  handleError(expr[0], "$Number_expected");
2619  return false;
2620  }
2622  break;
2623 
2624  case ABS_F:
2625  case FPCLASSIFY_F:
2626  if (!isIntegral(expr[0]))
2627  {
2628  handleError(expr[0], "$Integer_expected");
2629  return false;
2630  }
2632  break;
2633 
2634  case ILOGB_F:
2635  case FINT_F:
2636  if (!isNumber(expr[0]))
2637  {
2638  handleError(expr[0], "$Number_expected");
2639  return false;
2640  }
2642  break;
2643 
2644  case ISFINITE_F:
2645  case ISINF_F:
2646  case ISNAN_F:
2647  case ISNORMAL_F:
2648  case SIGNBIT_F:
2649  case ISUNORDERED_F:
2650  if (!isNumber(expr[0]))
2651  {
2652  handleError(expr[0], "$Number_expected");
2653  return false;
2654  }
2656  break;
2657 
2658  case INLINEIF:
2659  if (!isIntegral(expr[0]))
2660  {
2661  handleError(expr, "$First_argument_of_inline_if_must_be_an_integer");
2662  return false;
2663  }
2664  if (!areInlineIfCompatible(expr[1].getType(), expr[2].getType()))
2665  {
2666  handleError(expr, "$Incompatible_arguments_to_inline_if");
2667  return false;
2668  }
2669  type = expr[1].getType();
2670  break;
2671 
2672  case COMMA:
2673  if (!isAssignable(expr[0].getType()) && !isVoid(expr[0]))
2674  {
2675  handleError(expr[0], "$Incompatible_type_for_comma_expression");
2676  return false;
2677  }
2678  if (!isAssignable(expr[1].getType()) && !isVoid(expr[1]))
2679  {
2680  handleError(expr[1], "$Incompatible_type_for_comma_expression");
2681  return false;
2682  }
2683  checkIgnoredValue(expr[0]);
2684  type = expr[1].getType();
2685  break;
2686 
2687  case FUNCALL:
2688  {
2689  checkExpression(expr[0]);
2690 
2691  bool result = true;
2692  type_t type = expr[0].getType();
2693  size_t parameters = type.size() - 1;
2694  for (uint32_t i = 0; i < parameters; i++)
2695  {
2696  type_t parameter = type[i + 1];
2697  expression_t argument = expr[i + 1];
2698  result &= checkParameterCompatible(parameter, argument);
2699  }
2700  return result;
2701  }
2702 
2703  case ARRAY:
2704  arg1 = expr[0].getType();
2705  arg2 = expr[1].getType();
2706 
2707  /* The left side must be an array.
2708  */
2709  if (!arg1.isArray())
2710  {
2711  handleError(expr[0], "$Array_expected");
2712  return false;
2713  }
2714  type = arg1.getSub();
2715 
2716  /* Check the type of the index.
2717  */
2718  if (arg1.getArraySize().isInteger() && arg2.isIntegral())
2719  {
2720 
2721  }
2722  else if (arg1.getArraySize().isScalar() && arg2.isScalar())
2723  {
2724  if (!isSameScalarType(arg1.getArraySize(), arg2))
2725  {
2726  handleError(expr[1], "$Incompatible_type");
2727  return false;
2728  }
2729  }
2730  else
2731  {
2732  handleError(expr[1], "$Incompatible_type");
2733  }
2734  break;
2735 
2736 
2737  case FORALL:
2738  checkType(expr[0].getSymbol().getType());
2739 
2740  if (isIntegral(expr[1]))
2741  {
2743  }
2744  else if (isInvariant(expr[1]))
2745  {
2747  }
2748  else if (isInvariantWR(expr[1]))
2749  {
2751  }
2752  else if (isGuard(expr[1]))
2753  {
2755  }
2756  else if (isConstraint(expr[1]))
2757  {
2759  }
2760  else
2761  {
2762  handleError(expr[1], "$Boolean_expected");
2763  }
2764 
2765  if (expr[1].changesAnyVariable())
2766  {
2767  handleError(expr[1], "$Expression_must_be_side-effect_free");
2768  }
2769  break;
2770 
2771  case EXISTS:
2772  checkType(expr[0].getSymbol().getType());
2773 
2774  if (isIntegral(expr[1]))
2775  {
2777  }
2778  else if (isConstraint(expr[1]))
2779  {
2781  }
2782  else
2783  {
2784  handleError(expr[1], "$Boolean_expected");
2785  }
2786 
2787  if (expr[1].changesAnyVariable())
2788  {
2789  handleError(expr[1], "$Expression_must_be_side-effect_free");
2790  }
2791  break;
2792 
2793  case SUM:
2794  checkType(expr[0].getSymbol().getType());
2795 
2796  if (isIntegral(expr[1]))
2797  {
2799  }
2800  else if (isNumber(expr[1]))
2801  {
2803  }
2804  else
2805  {
2806  handleError(expr[1], "$Number_expected");
2807  }
2808 
2809  if (expr[1].changesAnyVariable())
2810  {
2811  handleError(expr[1], "$Expression_must_be_side-effect_free");
2812  }
2813  break;
2814 
2815  case AF:
2816  case AG:
2817  case EF:
2818  case EG:
2819  case EF_R_Piotr:
2820  case AG_R_Piotr:
2821  case EF_CONTROL:
2822  case CONTROL:
2823  case CONTROL_TOPT:
2824  case CONTROL_TOPT_DEF1:
2825  case CONTROL_TOPT_DEF2:
2826  case PMAX:
2827  if (isFormula(expr[0]))
2828  {
2830  }
2831  break;
2832 
2833  case PO_CONTROL:
2834  if (isListOfFormulas(expr[0]) && isFormula(expr[1]))
2835  {
2837  }
2838  break;
2839 
2840  case RESTRICT:
2841  if (!checkIDList(expr[0], PROCESS))
2842  {
2843  handleError(expr[0], "$Composition_of_processes_expected");
2844  ok = false;
2845  }
2846  if (!checkIDList(expr[1], CHANNEL))
2847  {
2848  handleError(expr[1], "$List_of_channels_expected");
2849  ok = false;
2850  }
2851  if (!ok)
2852  {
2853  return false;
2854  }
2856  break;
2857 
2858  case SIMULATION_LE:
2859  case SIMULATION_GE:
2860  {
2861  bool le = expr.getKind() == SIMULATION_LE;
2862  expression_t &e1 = le ? expr[0] : expr[1];
2863  expression_t &e2 = le ? expr[1] : expr[0];
2864  if (e1.getKind() != RESTRICT)
2865  {
2866  handleError(e1, "$Composition_of_processes_expected");
2867  ok = false;
2868  }
2869  if (!checkIDList(e2, PROCESS))
2870  {
2871  handleError(e2, "$Composition_of_processes_expected");
2872  ok = false;
2873  }
2874  if (!ok)
2875  {
2876  return false;
2877  }
2879  break;
2880  }
2881 
2882  case TIOQUOTIENT: /* (Graph | Id) + (Graph | Id) */
2883  if (!expr[0].getType().is(TIOGRAPH) && !isProcessID(expr[0]))
2884  {
2885  handleError(expr[0], "$Process_expression_expected");
2886  ok = false;
2887  }
2888  if (!expr[1].getType().is(TIOGRAPH) && !isProcessID(expr[1]))
2889  {
2890  handleError(expr[1], "$Process_expression_expected");
2891  ok = false;
2892  }
2893  if (!ok)
2894  {
2895  return false;
2896  }
2898  break;
2899 
2900  case CONSISTENCY: /* (Graph | Id) + Expr */
2901  if (!expr[0].getType().is(TIOGRAPH) && !isProcessID(expr[0]))
2902  {
2903  handleError(expr[0], "$Process_expression_expected");
2904  ok = false;
2905  }
2906  if (!isFormula(expr[1]))
2907  {
2908  handleError(expr[1], "$Property_must_be_a_valid_formula");
2909  ok = false;
2910  }
2911  if (!ok)
2912  {
2913  return false;
2914  }
2916  break;
2917 
2918  case SPECIFICATION:
2919  case IMPLEMENTATION:
2920  if (!expr[0].getType().is(TIOGRAPH) && !isProcessID(expr[0]))
2921  {
2922  handleError(expr[0], "$Process_expression_expected");
2923  return false;
2924  }
2926  break;
2927 
2928  case TIOCOMPOSITION:
2929  case TIOCONJUNCTION:
2930  case SYNTAX_COMPOSITION:
2931  for(uint32_t i = 0; i < expr.getSize(); ++i)
2932  {
2933  if (!expr[i].getType().is(TIOGRAPH) && expr[i].getKind() != IDENTIFIER)
2934  {
2935  handleError(expr[i], "$Process_expression_expected");
2936  ok = false;
2937  }
2938  }
2939  if (!ok)
2940  {
2941  return false;
2942  }
2944  break;
2945 
2946  case REFINEMENT_LE:
2947  case REFINEMENT_GE:
2948  if (!expr[0].getType().is(TIOGRAPH) && expr[0].getKind() != IDENTIFIER)
2949  {
2950  handleError(expr[0], "$Process_expression_expected");
2951  ok = false;
2952  }
2953  if (!expr[1].getType().is(TIOGRAPH) && expr[1].getKind() != IDENTIFIER)
2954  {
2955  handleError(expr[0], "$Process_expression_expected");
2956  ok = false;
2957  }
2958  if (!ok)
2959  {
2960  return false;
2961  }
2963  break;
2964 
2965  case LEADSTO:
2966  case SCENARIO2:
2967  case A_UNTIL:
2968  case A_WEAKUNTIL:
2969  case A_BUCHI:
2970  if (isFormula(expr[0]) && isFormula(expr[1]))
2971  {
2973  }
2974  break;
2975 
2976  case SCENARIO:
2978  break;
2979 
2980  case SIMULATEREACH:
2981  case SIMULATE:
2982  {
2983  bool ok = true;
2984  ok &= checkNrOfRuns(expr[0]);
2985  if (ok && expr[0].getValue() <= 0)
2986  {
2987  handleError(expr[0], "$Invalid_run_count");
2988  ok = false;
2989  }
2990  ok &= checkBoundTypeOrBoundedExpr(expr[1]);
2991  ok &= checkBound(expr[2]);
2992  if (!ok)
2993  return false;
2994  int nb = expr.getSize();
2995  if (expr.getKind() == SIMULATEREACH)
2996  {
2997  bool ok = true;
2998  nb -= 2;
2999  ok &= checkPredicate(expr[nb]);
3000  ok &= checkNrOfRuns(expr[nb+1]);
3001  if (!ok)
3002  return false;
3003  }
3004  for (int i = 3; i < nb; ++i)
3005  if (!checkMonitoredExpr(expr[i]))
3006  return false;
3007 
3009  break;
3010  }
3011 
3012  case SUP_VAR:
3013  case INF_VAR:
3014  if (!isIntegral(expr[0]) && !isConstraint(expr[0]))
3015  {
3016  handleError(expr[0], "$Boolean_expected");
3017  return false;
3018  }
3019  if (expr[1].getKind() == LIST)
3020  {
3021  for(uint32_t i = 0; i < expr[1].getSize(); ++i)
3022  {
3023  if (isIntegral(expr[1][i]))
3024  {
3025  if (expr[1][i].changesAnyVariable())
3026  {
3027  handleError(expr[1][i], "$Expression_must_be_side-effect_free");
3028  return false;
3029  }
3030  }
3031  else if (!isClock(expr[1][i]))
3032  {
3033  handleError(expr[1][i], "$Type_error");
3034  return false;
3035  }
3036  }
3038  }
3039  break;
3040 
3041  case MITLFORMULA:
3042  case MITLCONJ:
3043  case MITLDISJ:
3044  case MITLNEXT:
3045  case MITLUNTIL:
3046  case MITLRELEASE:
3047  case MITLATOM:
3049  //TODO
3050  break;
3051 
3052  case SMC_CONTROL:
3053  assert(expr.getSize() == 3);
3054  ok &= checkBoundTypeOrBoundedExpr(expr[0]);
3055  ok &= checkBound(expr[1]);
3056  if (!ok)
3057  return false;
3058  if (isFormula(expr[2]))
3059  {
3061  }
3062  break;
3063 
3064  case PROBAMINBOX:
3065  case PROBAMINDIAMOND:
3066  if (expr.getSize() == 5)
3067  {
3068  bool ok = true;
3069  ok &= checkNrOfRuns(expr[0]);
3070  if (ok && expr[0].getValue() > 0)
3071  {
3072  handleError(expr[0],"Explicit number of runs is not supported here");
3073  ok = false;
3074  }
3075  ok &= checkBoundTypeOrBoundedExpr(expr[1]);
3076  ok &= checkBound(expr[2]);
3077  ok &= checkPredicate(expr[3]);
3078  ok &= checkProbBound(expr[4]);
3079  if (!ok)
3080  return false;
3082  } else {
3083  handleError(expr, "Bug: wrong number of arguments");
3084  return false;
3085  }
3086  break;
3087 
3088  case PROBABOX:
3089  case PROBADIAMOND:
3090  if (expr.getSize() == 5)
3091  {
3092  bool ok = true;
3093  ok &= checkNrOfRuns(expr[0]);
3094  ok &= checkBoundTypeOrBoundedExpr(expr[1]);
3095  ok &= checkBound(expr[2]);
3096  ok &= checkPredicate(expr[3]);
3097  ok &= checkUntilCond(expr.getKind(), expr[4]);
3098  if (!ok)
3099  return false;
3101  } else {
3102  handleError(expr, "Bug: wrong number of arguments");
3103  return false;
3104  }
3105  break;
3106 
3107  case PROBACMP:
3108  if (expr.getSize() == 8)
3109  {
3110  bool ok = true;
3111  // the first prob property:
3112  ok &= checkBoundTypeOrBoundedExpr(expr[0]);
3113  ok &= checkBound(expr[1]);
3114  ok &= checkPathQuant(expr[2]);
3115  ok &= checkPredicate(expr[3]);
3116  // the second prob property:
3117  ok &= checkBoundTypeOrBoundedExpr(expr[4]);
3118  ok &= checkBound(expr[5]);
3119  ok &= checkPathQuant(expr[6]);
3120  ok &= checkPredicate(expr[7]);
3121  if (!ok)
3122  return false;
3124  } else {
3125  handleError(expr, "Bug: wrong number of arguments");
3126  return false;
3127  }
3128  break;
3129 
3130  case PROBAEXP:
3131  if (expr.getSize() == 5)
3132  { // Encoded by expressionbuilder.
3133  bool ok = true;
3134  ok &= checkNrOfRuns(expr[0]);
3135  ok &= checkBoundTypeOrBoundedExpr(expr[1]);
3136  ok &= checkBound(expr[2]);
3137  ok &= checkAggregationOp(expr[3]);
3138  ok &= checkMonitoredExpr(expr[4]);
3139  if (!ok)
3140  return false;
3142  } else {
3143  handleError(expr, "Bug: wrong number of arguments");
3144  return false;
3145  }
3146  break;
3147 
3148  default:
3149  return true;
3150  }
3151 
3152  if (type.unknown())
3153  {
3154  handleError(expr, "$Type_error");
3155  return false;
3156  }
3157  else
3158  {
3159  expr.setType(type);
3160  return true;
3161  }
3162 }
3163 
3167 bool TypeChecker::isModifiableLValue(expression_t expr) const
3168 {
3169  type_t t, f;
3170  switch (expr.getKind())
3171  {
3172  case IDENTIFIER:
3173  return expr.getType().isNonConstant();
3174 
3175  case DOT:
3176  /* Processes can only be used in properties, which must be
3177  * side-effect anyway. Therefore returning false below is
3178  * acceptable for now (REVISIT).
3179  */
3180  if (expr[0].getType().isProcess())
3181  {
3182  return false;
3183  }
3184  // REVISIT: Not correct if records contain constant fields.
3185  return isModifiableLValue(expr[0]);
3186 
3187  case ARRAY:
3188  return isModifiableLValue(expr[0]);
3189 
3190  case PREINCREMENT:
3191  case PREDECREMENT:
3192  case ASSIGN:
3193  case ASSPLUS:
3194  case ASSMINUS:
3195  case ASSDIV:
3196  case ASSMOD:
3197  case ASSMULT:
3198  case ASSAND:
3199  case ASSOR:
3200  case ASSXOR:
3201  case ASSLSHIFT:
3202  case ASSRSHIFT:
3203  return true;
3204 
3205  case INLINEIF:
3206  return isModifiableLValue(expr[1]) && isModifiableLValue(expr[2])
3207  && areEquivalent(expr[1].getType(), expr[2].getType());
3208 
3209  case COMMA:
3210  return isModifiableLValue(expr[1]);
3211 
3212  case FUNCALL:
3213  // Functions cannot return references (yet!)
3214 
3215  default:
3216  return false;
3217  }
3218 }
3219 
3223 bool TypeChecker::isLValue(expression_t expr) const
3224 {
3225  type_t t, f;
3226  switch (expr.getKind())
3227  {
3228  case IDENTIFIER:
3229  case PREINCREMENT:
3230  case PREDECREMENT:
3231  case ASSIGN:
3232  case ASSPLUS:
3233  case ASSMINUS:
3234  case ASSDIV:
3235  case ASSMOD:
3236  case ASSMULT:
3237  case ASSAND:
3238  case ASSOR:
3239  case ASSXOR:
3240  case ASSLSHIFT:
3241  case ASSRSHIFT:
3242  return true;
3243 
3244  case DOT:
3245  case ARRAY:
3246  return isLValue(expr[0]);
3247 
3248  case INLINEIF:
3249  return isLValue(expr[1]) && isLValue(expr[2])
3250  && areEquivalent(expr[1].getType(), expr[2].getType());
3251 
3252  case COMMA:
3253  return isLValue(expr[1]);
3254 
3255  case FUNCALL:
3256  // Functions cannot return references (yet!)
3257 
3258  default:
3259  return false;
3260  }
3261 }
3262 
3269 bool TypeChecker::isUniqueReference(expression_t expr) const
3270 {
3271  switch (expr.getKind())
3272  {
3273  case IDENTIFIER:
3274  return true;
3275 
3276  case DOT:
3277  return isUniqueReference(expr[0]);
3278 
3279  case ARRAY:
3280  return isUniqueReference(expr[0])
3281  && isCompileTimeComputable(expr[1]);
3282 
3283  case PREINCREMENT:
3284  case PREDECREMENT:
3285  case ASSIGN:
3286  case ASSPLUS:
3287  case ASSMINUS:
3288  case ASSDIV:
3289  case ASSMOD:
3290  case ASSMULT:
3291  case ASSAND:
3292  case ASSOR:
3293  case ASSXOR:
3294  case ASSLSHIFT:
3295  case ASSRSHIFT:
3296  return isUniqueReference(expr[0]);
3297 
3298  case INLINEIF:
3299  return false;
3300 
3301  case COMMA:
3302  return isUniqueReference(expr[1]);
3303 
3304  case FUNCALL:
3305  // Functions cannot return references (yet!)
3306 
3307  default:
3308  return false;
3309  }
3310 }
3311 
3312 bool parseXTA(FILE *file, TimedAutomataSystem *system, bool newxta)
3313 {
3314  SystemBuilder builder(system);
3315  parseXTA(file, &builder, newxta);
3316  if (!system->hasErrors())
3317  {
3318  TypeChecker checker(system);
3319  system->accept(checker);
3320  }
3321  return !system->hasErrors();
3322 }
3323 
3324 bool parseXTA(const char *buffer, TimedAutomataSystem *system, bool newxta)
3325 {
3326  SystemBuilder builder(system);
3327  parseXTA(buffer, &builder, newxta);
3328  if (!system->hasErrors())
3329  {
3330  TypeChecker checker(system);
3331  system->accept(checker);
3332  }
3333  return !system->hasErrors();
3334 }
3335 
3336 int32_t parseXMLBuffer(const char *buffer, TimedAutomataSystem *system, bool newxta)
3337 {
3338  int err;
3339 
3340  SystemBuilder builder(system);
3341  err = parseXMLBuffer(buffer, &builder, newxta);
3342 
3343  if (err)
3344  {
3345  return err;
3346  }
3347 
3348  if (!system->hasErrors())
3349  {
3350  TypeChecker checker(system);
3351  system->accept(checker);
3352  }
3353 
3354  return 0;
3355 }
3356 
3357 int32_t parseXMLFile(const char *file, TimedAutomataSystem *system, bool newxta)
3358 {
3359  int err;
3360 
3361  SystemBuilder builder(system);
3362  err = parseXMLFile(file, &builder, newxta);
3363  if (err)
3364  {
3365  return err;
3366  }
3367 
3368  if (!system->hasErrors())
3369  {
3370  TypeChecker checker(system);
3371  system->accept(checker);
3372  }
3373 
3374  return 0;
3375 }
3376 
3378  TimedAutomataSystem *system, bool newxtr)
3379 {
3380  ExpressionBuilder builder(system);
3381  parseXTA(str, &builder, newxtr, S_EXPRESSION, "");
3382  expression_t expr = builder.getExpressions()[0];
3383  if (!system->hasErrors())
3384  {
3385  TypeChecker checker(system);
3386  checker.checkExpression(expr);
3387  }
3388  return expr;
3389 }
3390 
3392  assert(&t == temp);
3393 
3394  temp = NULL;
3395 }
3396 
3398  assert(!temp);
3399  temp = &t;
3400 
3401  return true;
3402 
3403 }
3404 
3406 {
3407  return checkParameterCompatible(param,arg);
3408 }
3409 
3411 {
3412  std::list<expression_t> l;
3414  stat->accept(&e);
3415  bool ok = true;
3416  for (auto& it: l)
3417  {
3418  ok = false;
3419  handleError(it, "Dynamic constructs are only allowed on edges!");
3420  }
3421  return ok;
3422 }
3423 
3424 bool TypeChecker::checkNrOfRuns(const expression_t& runs)
3425 {
3426  if (!isCompileTimeComputable(runs))
3427  {
3428  handleError(runs, "$Must_be_computable_at_compile_time");
3429  return false;
3430  }
3431  if (!isConstantInteger(runs))
3432  {
3433  handleError(runs, "$Integer_expected");
3434  return false;
3435  }
3436  return true;
3437 }
3438 
3439 bool TypeChecker::checkBoundTypeOrBoundedExpr(const expression_t& boundTypeOrExpr)
3440 {
3441  if (!isConstantInteger(boundTypeOrExpr) && !isClock(boundTypeOrExpr))
3442  {
3443  handleError(boundTypeOrExpr, "$Clock_expected");
3444  return false;
3445  }
3446  return true;
3447 }
3448 
3449 bool TypeChecker::checkBound(const expression_t& bound)
3450 {
3451  if (!isCompileTimeComputable(bound))
3452  {
3453  handleError(bound, "$Must_be_computable_at_compile_time");
3454  return false;
3455  }
3456  if (!isIntegral(bound))
3457  {
3458  handleError(bound, "$Integer_expected");
3459  return false;
3460  }
3461  return true;
3462 }
3463 
3464 bool TypeChecker::checkPredicate(const expression_t& predicate)
3465 {
3466  if (!isIntegral(predicate) && !isConstraint(predicate))
3467  { //check reachability expression is a boolean
3468  handleError(predicate, "$Boolean_expected");
3469  return false;
3470  }
3471  if (predicate.changesAnyVariable())
3472  { //check reachability expression is side effect free
3473  handleError(predicate, "$Property_must_be_side-effect_free");
3474  return false;
3475  }
3476  return true;
3477 }
3478 
3479 bool TypeChecker::checkProbBound(const expression_t& probBound)
3480 {
3481  if (!isConstantDouble(probBound))
3482  {
3483  handleError(probBound, "Floating point number expected as probability bound");
3484  return false;
3485  }
3486  return true;
3487 }
3488 
3489 bool TypeChecker::checkUntilCond(kind_t kind, const expression_t& untilCond)
3490 {
3491  bool ok = true;
3492  if (kind == PROBADIAMOND && !isIntegral(untilCond) && !isConstraint(untilCond))
3493  {
3494  handleError(untilCond, "$Boolean_expected");
3495  ok = false;
3496  }
3497  if (kind == PROBABOX && untilCond.getKind()==Constants::BOOL &&
3498  untilCond.getValue() != 0)
3499  {
3500  handleError(untilCond, "Must be false"); //TODO - error message
3501  ok = false;
3502  }
3503  return ok;
3504 }
3505 
3506 bool TypeChecker::checkMonitoredExpr(const expression_t& expr)
3507 {
3508  if (!isIntegral(expr) && !isClock(expr) && !isDoubleValue(expr) &&
3510  !isConstraint(expr))
3511  {
3512  handleError(expr, "$Integer_or_clock_expected");
3513  return false;
3514  }
3515  if (expr.changesAnyVariable())
3516  {
3517  handleError(expr, "$Property_must_be_side-effect_free");
3518  return false;
3519  }
3520  return true;
3521 }
3522 
3523 bool TypeChecker::checkPathQuant(const expression_t& expr)
3524 {
3525  if (!isConstantInteger(expr))
3526  {
3527  handleError(expr, "Bug: bad path quantifier");
3528  return false;
3529  }
3530  return true;
3531 }
3532 
3533 bool TypeChecker::checkAggregationOp(const expression_t& expr)
3534 {
3535  if (!isConstantInteger(expr))
3536  {
3537  handleError(expr, "Bug: bad aggregation operator expression");
3538  return false;
3539  }
3540  if (expr.getValue()>1) // 0="min", 1="max"
3541  {
3542  handleError(expr, "Bug: bad aggregation operator value");
3543  return false;
3544  }
3545  return true;
3546 }
expression_t value
Definition: statement.h:214
symbol_t uid
The symbol of the variables.
Definition: system.h:45
void recordStrictInvariant()
Record that the system has some strict invariant.
Definition: system.cpp:1362
static bool hasStrictLowerBound(expression_t expr)
bool isRange() const
Shortcut for is(RANGE).
Definition: type.h:199
static bool isClock(expression_t expr)
Definition: typechecker.cpp:87
Constants::kind_t getKind() const
Returns the kind of the expression.
Definition: expression.cpp:182
Partial instance of a template.
Definition: system.h:329
static bool isFormula(expression_t expr)
bool isClock() const
Shortcut for is(CLOCK).
Definition: type.h:235
void recordStopWatch()
Record that the system stops a clock.
Definition: system.cpp:1372
static bool isInvariant(expression_t expr)
std::list< variable_t > variables
Local variables.
Definition: system.h:115
void visitUpdate(update_t &) override
Statement * falseCase
Definition: statement.h:185
bool isDefined
Definition: system.h:390
static bool isCost(expression_t expr)
Definition: typechecker.cpp:52
frame_t getFrame()
Definition: statement.h:141
std::list< ganttmap_t > mapping
Definition: system.h:155
expression_t label
The label.
Definition: system.h:205
static bool isIntegral(expression_t expr)
Definition: typechecker.cpp:82
int32_t parseXMLFile(const char *file, TimedAutomataSystem *system, bool newxta)
bool hasErrors() const
Definition: system.cpp:1431
bool unknown() const
Returns true if this is null-type or of kind UNKNOWN.
Definition: type.cpp:171
bool empty() const
Returns true if this is an empty expression.
Definition: expression.cpp:671
static bool hasMITLInQuantifiedSub(expression_t expr)
static int channelCapability(type_t type)
Returns a value indicating the capabilities of a channel.
std::set< symbol_t > restricted
Restricted variables.
Definition: system.h:337
bool isVoid() const
Shortcut for is(VOID_TYPE).
Definition: type.h:244
bool isIntegral() const
Returns true if this is a boolean or integer.
Definition: type.cpp:343
void visitProgressMeasure(progress_t &) override
virtual void visitInstanceLine(instanceLine_t &)
Definition: system.h:465
uint32_t getSize() const
Returns the number of symbols in this frame.
Definition: symbols.cpp:328
int32_t visitEmptyStatement(EmptyStatement *stat) override
size_t unbound
Definition: system.h:335
std::set< symbol_t > changes
Variables changed by this function.
Definition: system.h:113
expression_t cond
Definition: statement.h:183
virtual void visitProperty(expression_t)
expression_t guard
Definition: system.h:124
bool control
Controllable (true/false)
Definition: system.h:88
void visitInstance(instance_t &) override
void visitGanttChart(gantt_t &) override
bool isInvariant() const
Returns true if this is an invariant, boolean or integer.
Definition: type.cpp:348
bool checkExpression(expression_t)
Type check an expression.
Information about a location.
Definition: system.h:56
bool isInteger() const
Shortcut for is(INT).
Definition: type.h:202
expression_t label
The label.
Definition: system.h:194
expression_t guard
The guard.
Definition: system.h:95
static expression_t createNary(Constants::kind_t, const std::vector< expression_t > &, position_t=position_t(), type_t=type_t())
Create an n-ary expression.
Statement * stat
Definition: statement.h:109
void visitIODecl(iodecl_t &) override
A visitor which type checks the system it visits.
Definition: typechecker.h:57
A reference to a symbol.
Definition: symbols.h:107
static bool isDouble(expression_t expr)
Definition: typechecker.cpp:62
expression_t getAfterUpdate()
Definition: system.cpp:1315
expression_t sync
The synchronisation.
Definition: system.h:97
This class constructs a TimedAutomataSystem.
Definition: systembuilder.h:69
void setSyncUsed(sync_use_t s)
Definition: system.h:572
void addError(position_t, const std::string &msg, const std::string &ctx="")
Definition: system.cpp:1403
std::list< expression_t > outputs
Definition: system.h:132
int32_t visitReturnStatement(ReturnStatement *stat) override
void addWarning(position_t, const std::string &msg, const std::string &ctx="")
Definition: system.cpp:1411
static bool validReturnType(type_t type)
frame_t parameters
The parameters.
Definition: system.h:332
static bool isConstantDouble(expression_t expr)
static type_t createPrimitive(Constants::kind_t, position_t=position_t())
Create a primitive type.
Definition: type.cpp:527
virtual void visitUpdate(update_t &)
Definition: system.h:468
static bool isListOfFormulas(expression_t expr)
static bool isInvariantWR(expression_t expr)
Returns true iff type is a valid invariant.
void visitCondition(condition_t &) override
Information about an edge.
Definition: system.h:85
expression_t exponentialRate
Definition: system.h:60
Statement class for the iterator loop-construction.
Definition: statement.h:91
static vector< string > variables
Definition: tracer.cpp:153
std::vector< expression_t > param
Definition: system.h:131
bool isArray() const
Shortcut for is(ARRAY).
Definition: type.h:229
Information about an update.
Definition: system.h:213
std::string toString() const
Generates string representation of the type.
Definition: type.cpp:547
virtual void visitFunction(function_t &)
Definition: system.h:460
ExpressionFragments & getExpressions()
virtual void visitVariable(variable_t &)
Definition: system.h:453
expression_t assign
The assignment.
Definition: system.h:96
std::pair< expression_t, expression_t > getRange() const
Returns the range of a RANGE type.
Definition: type.cpp:266
static bool hasStrictUpperBound(expression_t expr)
bool visitTemplateBefore(template_t &) override
state_t * dst
Pointer to destination location.
Definition: system.h:92
expression_t expr
Definition: statement.h:58
Gantt chart entry.
Definition: system.h:148
static bool isDiff(expression_t expr)
Definition: typechecker.cpp:92
std::set< symbol_t > depends
Variables the function depends on.
Definition: system.h:114
Partial implementation of the builder interface: The ExpressionBuilder implements all expression rela...
void visitVariable(variable_t &) override
std::list< expression_t > inputs
Definition: system.h:132
Information about an instance line.
Definition: system.h:346
expression_t expr
Definition: statement.h:68
bool checkDynamicExpressions(Statement *stat)
const std::string & getLabel(uint32_t) const
Returns the i&#39;th label.
Definition: type.cpp:99
virtual void visitMessage(message_t &)
Definition: system.h:466
virtual void visitInstance(instance_t &)
Definition: system.h:458
expression_t & get(uint32_t)
Returns the ith subexpression.
Definition: expression.cpp:659
expression_t label
The label.
Definition: system.h:218
bool isFormula() const
Returns true if this is a formula, constraint, guard, invariant, boolean or integer.
Definition: type.cpp:370
expression_t invariant
The invariant.
Definition: system.h:59
const position_t & getPosition() const
Returns the position of this expression.
Definition: expression.cpp:188
bool isConstant() const
Returns true if and only if all elements of the type are constant.
Definition: type.cpp:375
bool isConstraint() const
Returns true if this is a constraint, guard, invariant, boolean or integer.
Definition: type.cpp:365
static bool isBound(expression_t expr)
Definition: typechecker.cpp:77
bool checkSpawnParameterCompatible(type_t param, expression_t arg)
template_t * getDynamicTemplate(const std::string &name)
Definition: system.cpp:1026
void recordStrictLowerBoundOnControllableEdges()
Record that the system has guards on controllable edges with strict lower bounds. ...
Definition: system.cpp:1387
int32_t visitAssertStatement(AssertStatement *stat) override
bool parseXTA(FILE *file, TimedAutomataSystem *system, bool newxta)
Base type for variables, clocks, etc.
Definition: system.h:43
type_t stripArray() const
Removes any leading prefixes, RANGE, REF, LABEL and ARRAY types and returns the result.
Definition: type.cpp:297
size_t arguments
Definition: system.h:334
type_t getSub() const
Returns the element type of an array.
Definition: type.cpp:193
virtual void visitHybridClock(expression_t)
static string symbol(const char *str)
Extracts the alpha-numerical symbol used for variable/type identifiers.
Definition: xmlreader.cpp:107
int32_t visitIfStatement(IfStatement *stat) override
static bool isGameProperty(expression_t expr)
bool isDiff() const
Shortcut for is(DIFF).
Definition: type.h:241
static bool isVoid(expression_t expr)
Definition: typechecker.cpp:57
static bool isGuard(expression_t expr)
static bool isInteger(expression_t expr)
Definition: typechecker.cpp:72
int32_t visitBlockStatement(BlockStatement *stat) override
void visitMessage(message_t &) override
TypeChecker(TimedAutomataSystem *system, bool refinement=false)
int32_t visitExprStatement(ExprStatement *stat) override
void visitEdge(edge_t &) override
bool isNonConstant() const
Returns true if and only if all elements of the type are not constant.
Definition: type.cpp:400
static bool isProcessID(expression_t expr)
void clockGuardRecvBroadcast()
Definition: system.h:570
virtual void visitEdge(edge_t &)
Definition: system.h:457
int32_t visitDoWhileStatement(DoWhileStatement *stat) override
int32_t accept(StatementVisitor *visitor) override
Definition: statement.cpp:243
A reference to a frame.
Definition: symbols.h:183
static bool isConstraint(expression_t expr)
expression_t expr
The initialiser.
Definition: system.h:46
A reference to a type.
Definition: type.h:93
void visitState(state_t &) override
std::map< symbol_t, expression_t > mapping
The arguments.
Definition: system.h:333
type_t getType() const
Returns the type of this symbol.
Definition: symbols.cpp:205
std::list< expression_t > csp
Definition: system.h:132
bool isGuard() const
Returns true if this is a guard, invariant, boolean or integer.
Definition: type.cpp:353
bool isBoolean() const
Shortcut for is(BOOL).
Definition: type.h:205
int32_t visitIterationStatement(IterationStatement *stat) override
size_t size() const
Returns the number of children.
Definition: type.cpp:81
symbol_t uid
The symbol of the function.
Definition: system.h:112
int32_t visitForStatement(ForStatement *stat) override
frame_t select
Frame for non-deterministic select.
Definition: system.h:94
void visitInstance(instance_t &) override
Information about a message.
Definition: system.h:188
int32_t findIndexOf(const std::string &) const
Returns the index of the record or process field with the given label.
Definition: type.cpp:105
std::string getRecordLabel(size_t i) const
Returns the label of the &#39;th field of a record.
Definition: type.cpp:253
void visitFunction(function_t &) override
BlockStatement * body
Pointer to the block.
Definition: system.h:116
void accept(SystemVisitor &)
Definition: system.cpp:1239
A reference to an expression.
Definition: expression.h:70
static bool initialisable(type_t type)
expression_t cond
Definition: statement.h:120
void visitSystemAfter(TimedAutomataSystem *) override
bool hasDynamicSub() const
Definition: expression.cpp:353
Information about a function.
Definition: system.h:110
expression_t init
Definition: statement.h:78
type_t getArraySize() const
Returns the size of an array (this is itself a type).
Definition: type.cpp:227
static bool isDoubleValue(expression_t expr)
Definition: typechecker.cpp:97
void visitProcess(instance_t &) override
bool isDynamic() const
Definition: expression.cpp:329
type_t getType() const
Returns the type of the expression.
Definition: expression.cpp:611
int32_t parseXMLBuffer(const char *buffer, TimedAutomataSystem *system, bool newxta)
void * getData()
Returns the user data of this symbol.
Definition: symbols.cpp:216
virtual int32_t accept(StatementVisitor *visitor)=0
expression_t step
Definition: statement.h:80
static bool isNumber(expression_t expr)
void visitTemplateAfter(template_t &) override
frame_t parameters
The select parameters.
Definition: system.h:154
int32_t getValue() const
Returns the value field of this expression.
Definition: expression.cpp:623
int32_t visitWhileStatement(WhileStatement *stat) override
expression_t cond
Definition: statement.h:108
void visitInstanceLine(instanceLine_t &) override
size_t getSize() const
Returns the number of subexpression.
Definition: expression.cpp:379
expression_t cond
Definition: statement.h:79
expression_t getBeforeUpdate()
Definition: system.cpp:1305
static bool isAssignable(type_t type)
Returns true if values of this type can be assigned.
Statement * trueCase
Definition: statement.h:184
bool is(Constants::kind_t kind) const
Returns true if the type has kind kind or if type is a prefix, RANGE or REF type and the getChild()...
Definition: type.cpp:176
bool isLocation() const
Shortcut for is(LOCATION).
Definition: type.h:217
Definition: lexer.cc:817
static bool isSameScalarType(type_t t1, type_t t2)
Returns true if two scalar types are name-equivalent.
bool isTrue() const
Definition: expression.cpp:676
void visitVariable(variable_t &) override
static expression_t createConstant(int32_t, position_t=position_t())
Create a CONSTANT expression.
void setType(type_t)
Sets the type of the expression.
Definition: expression.cpp:617
bool isScalar() const
Shortcut for is(SCALAR).
Definition: type.h:232
Constants::synchronisation_t getSync() const
Returns the synchronisation type of SYNC operations.
Definition: expression.cpp:641
Statement * stat
Definition: statement.h:81
static expression_t createBinary(Constants::kind_t, expression_t, expression_t, position_t=position_t(), type_t=type_t())
Create a binary expression.
expression_t parseExpression(const char *str, TimedAutomataSystem *system, bool newxtr)
void collectPossibleReads(std::set< symbol_t > &, bool collectRandom=false) const
const std::list< chan_priority_t > & getChanPriorities() const
Definition: system.cpp:1335
static bool checkIDList(expression_t expr, kind_t kind)
virtual void visitState(state_t &)
Definition: system.h:456
bool isDouble() const
Shortcut for is(DOUBLE).
Definition: type.h:250
expression_t costRate
Rate expression.
Definition: system.h:61
Information about a condition.
Definition: system.h:200
static bool hasSpawnOrExit(expression_t expr)
bool isRecord() const
Shortcut for is(RECORD).
Definition: type.h:238
Constants::kind_t getKind() const
Returns the kind of type object.
Definition: type.cpp:120
expression_t measure
Definition: system.h:125
bool isChannel() const
Shortcut for is(CHANNEL).
Definition: type.h:226
static bool isConstantInteger(expression_t expr)
std::string toString() const
Definition: system.cpp:62
virtual void visitCondition(condition_t &)
Definition: system.h:467
size_t getRecordSize() const
Returns the number of fields of a record.
Definition: type.cpp:240
bool changesAnyVariable() const
True if this expression can change any variable at all.
Definition: expression.cpp:852
symbol_t uid
The name.
Definition: system.h:331