source: branches/dev-mo-2530/Compiler/ModelicaFrontEnd/src/jastadd/errorcheck/ErrorCheck.jrag @ 13922

Last change on this file since 13922 was 13922, checked in by molsson, 5 weeks ago

Merged revision(s) 13898-13913 from branches/dev-mo-2617:
#5843 Moved type checking of conditional attributes so that it is always done.
........
#5843 Conditional attribute requires variability fixed parameter or less.
........
#5843 Updated error message NON_BOOLEAN_CONDITIONAL_GUARD to say Boolean instead of boolean.
........
#5843 Merged non-scalar and non-boolean conditional guard error messages.
........

File size: 69.5 KB
Line 
1/*
2    Copyright (C) 2009 Modelon AB
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, version 3 of the License.
7
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12
13    You should have received a copy of the GNU General Public License
14    along with this program.  If not, see <http://www.gnu.org/licenses/>.
15*/
16
17import java.util.Collection;
18import java.util.Collections;
19import java.util.LinkedList;
20import java.util.ArrayList;
21import java.util.Map;
22
23import org.jmodelica.util.collections.ListMap;
24import org.jmodelica.util.collections.LinkedHashListMap;
25import org.jmodelica.api.problemHandling.Problem;
26import org.jmodelica.api.problemHandling.ProblemSeverity;
27import org.jmodelica.api.problemHandling.ProblemKind;
28import org.jmodelica.util.problemHandling.ReporterNode;
29import org.jmodelica.util.problemHandling.ProblemOptionsProvider;
30import org.jmodelica.util.ErrorCheckType;
31
32
33
34/**
35 * Interface for handling semantic errors.
36 * $see Root#setErrorHandler(IErrorHandler)
37 */
38public interface IErrorHandler {
39    /**
40     * Called when a semantic error is found.
41     *
42     * @param s error message.
43     * @param n the node the error originated from.
44     * @see ASTNode#error(String)
45     */
46    public void error(String s, ASTNode n);
47   
48    /**
49     * Called when a compiler compliance error is found.
50     *
51     * These errors are generated when compiling code that is legal Modelica,
52     * but uses features that aren't implemented. Compliance errors are ignored
53     * by test cases (except ComplianceErrorTestCase).
54     * 
55     * @param s error message.
56     * @param n the node the error originated from.
57     * @see ASTNode#compliance(String)
58     */
59    public void compliance(String s, ASTNode n);
60   
61    /**
62     * Called when a warning is issued during semantic error checking.
63     *
64     * @param s warning message.
65     * @param n the node the warning originated from.
66     * @see ASTNode#warning(String)
67     */
68    public void warning(String s, ASTNode n);
69   
70    /**
71     * Called when a problem is generated though other means than the other methods in this interface,
72     * typically during parsing of library files.
73     *
74     * @param p   the problem
75     * @see ASTNode#problem(Problem)
76     */
77    public void problem(Problem p);
78}
79
80/**
81 * Default implementation of {@link IErrorHandler}.
82 * 
83 * Collects a list of {@link Problem} for all found errors.
84 */
85public class DefaultErrorHandler implements IErrorHandler {
86    protected boolean haltOnWarning;
87   
88    public DefaultErrorHandler() {
89        this(false);
90    }
91
92    public DefaultErrorHandler(boolean haltOnWarning) {
93        this.haltOnWarning = haltOnWarning;
94    }
95
96    /**
97     * Creates a new {@link Problem} and adds it to root.errors, ignoring duplicates.
98     *
99     * @param s error message.
100     * @param n the node the error originated from.
101     */
102    public void error(String s, ASTNode n) {
103        problem(s, n, ProblemSeverity.ERROR, ProblemKind.SEMANTIC);
104    }
105
106    /**
107     * Creates a new {@link Problem} with kind COMPLIANCE
108     *        and adds it to root.errors, ignoring duplicates.
109     *
110     * @param s error message.
111     * @param n the node the error originated from.
112     */
113    public void compliance(String s, ASTNode n) {
114        problem(s, n, ProblemSeverity.ERROR, ProblemKind.COMPLIANCE);
115    }
116
117    /**
118     * Creates a new {@link Problem} and adds it to root.warnings, ignoring duplicates.
119     *
120     * @param s warning message.
121     * @param n the node the warning originated from.
122     */
123    public void warning(String s, ASTNode n) {
124        problem(s, n, ProblemSeverity.WARNING, ProblemKind.OTHER);
125    }
126
127    /**
128     * Called when a problem is generated though other means than the other methods in this class,
129     * typically during parsing of library files.
130     *
131     * @param p   the problem
132     * @see ASTNode#problem(Problem)
133     */
134    public void problem(Problem p) {
135        ArrayList<Problem> list = (p.severity() == ProblemSeverity.WARNING) ? warnings : errors;
136        int pos = list.indexOf(p);
137        if (pos == -1)
138            list.add(p);
139        else
140            list.get(pos).merge(p);
141    }
142
143    protected void problem(String message, ASTNode node, ProblemSeverity severity, ProblemKind kind) {
144        problem(Problem.createProblem(null, node, severity, kind, message));
145    }
146}
147
148/**
149 * Error handler that generates warnings for compliance errors,
150 *        delegating to another error handler.
151 */
152public class ComplianceWarnErrorHandler implements IErrorHandler {
153
154    private IErrorHandler delegate;
155
156    public ComplianceWarnErrorHandler(IErrorHandler delegate) {
157        if (delegate instanceof ComplianceWarnErrorHandler)
158            delegate = ((ComplianceWarnErrorHandler) delegate).delegate;
159        this.delegate = delegate;
160    }
161
162    /**
163     * Delegates to wrapped error handler.
164     *
165     * @param s error message.
166     * @param n the node the error originated from.
167     */
168    public void error(String s, ASTNode n) {
169        delegate.error(s, n);
170    }
171
172    /**
173     * Delegates to warning() in wrapped error handler.
174     *
175     * @param s error message.
176     * @param n the node the error originated from.
177     */
178    public void compliance(String s, ASTNode n) {
179        delegate.warning(s, n);
180    }
181
182    /**
183     * Delegates to wrapped error handler.
184     *
185     * @param s warning message.
186     * @param n the node the warning originated from.
187     */
188    public void warning(String s, ASTNode n) {
189        delegate.warning(s, n);
190    }
191
192    /**
193     * Called when a problem is generated though other means than the other methods in this class,
194     * typically during parsing of library files.
195     *
196     * @param p   the problem
197     * @see ASTNode#problem(Problem)
198     */
199    public void problem(Problem p) {
200        delegate.problem(p);
201    }
202}
203
204aspect ErrorCheck {
205   
206    syn ProblemOptionsProvider ASTNode.myProblemOptionsProvider() = root().getUtilInterface();
207   
208    public class UtilInterface implements ProblemOptionsProvider {
209        private Set<String> warningsFilterCache = null;
210        public boolean filterThisWarning(String identifier) {
211            if (warningsFilterCache == null) {
212                warningsFilterCache = new HashSet<String>();
213                for (String s : getOptionRegistry().getStringOption("filter_warnings").split(",")) {
214                    warningsFilterCache.add(s);
215                }
216            }
217            return warningsFilterCache.contains(identifier);
218        }
219    }
220       
221        public void ASTNode.breakOnErrors() throws CompilerException {
222                root().getErrorHandler().breakOnErrors();
223        }
224       
225        public void IErrorHandler.breakOnErrors() throws CompilerException;
226       
227        public void ComplianceWarnErrorHandler.breakOnErrors() throws CompilerException {
228            delegate.breakOnErrors();
229        }
230       
231        public void DefaultErrorHandler.breakOnErrors() throws CompilerException {
232                if (!errors.isEmpty() || (haltOnWarning && !warnings.isEmpty())) {
233                    java.util.Collections.sort(errors);
234                    java.util.Collections.sort(warnings);
235                   
236                    ArrayList<Problem> problems = new ArrayList<Problem>();
237                    problems.addAll(warnings);
238                    problems.addAll(errors);
239                   
240                    errors.clear();
241                    warnings.clear();
242                   
243                    throw new CompilerException(problems);
244                }
245        }
246       
247    public ArrayList<Problem> ASTNode.collectWarnings() {
248        return root().getErrorHandler().collectWarnings();
249    }
250   
251    public ArrayList<Problem> IErrorHandler.collectWarnings();
252   
253    public ArrayList<Problem> ComplianceWarnErrorHandler.collectWarnings() {
254        return delegate.collectWarnings();
255    }
256   
257    public ArrayList<Problem> DefaultErrorHandler.collectWarnings() {
258                breakOnErrors();
259            java.util.Collections.sort(warnings);
260            ArrayList<Problem> problems = new ArrayList<Problem>(warnings);
261            warnings.clear();
262            return problems;
263        }
264
265    public ArrayList<Problem> DefaultErrorHandler.errors = new ArrayList<Problem>();
266    public ArrayList<Problem> DefaultErrorHandler.warnings = new ArrayList<Problem>();
267
268  private IErrorHandler Root.errorHandler = null;
269 
270  /**
271   * Get the handler for semantic errors.
272   * @see IErrorHandler
273   */
274  public IErrorHandler Root.getErrorHandler() {
275          return getUtilInterface().getErrorHandler();
276  }
277
278  ASTNode implements ReporterNode;
279 
280  public void ASTNode.reportProblem(Problem problem) {
281      root().getErrorHandler().problem(problem);
282  }
283
284 
285 
286  /**
287   * Register an error. Delegates to an {@link IErrorHandler}.
288   * @param s   the error message.
289   */
290  @Deprecated
291  public void ASTNode.error(String s) {
292          root().getErrorHandler().error(s, this);
293  }
294 
295  /**
296   * Register an error. Delegates to an {@link IErrorHandler}.
297   *
298   * Builds error message using <code>format</code> as format string.
299   */
300  @Deprecated
301  public void ASTNode.error(String format, Object... args) {
302          error(String.format(format, args));
303  }
304
305  /**
306   * Register a compliance error. Delegates to an {@link IErrorHandler}.
307   * @param s   the error message.
308   */
309  @Deprecated
310  public void ASTNode.compliance(String s) {
311          root().getErrorHandler().compliance(s, this);
312  }
313 
314  /**
315   * Register a compliance error. Delegates to an {@link IErrorHandler}.
316   *
317   * Builds error message using <code>format</code> as format string.
318   */
319  @Deprecated
320  public void ASTNode.compliance(String format, Object... args) {
321          compliance(String.format(format, args));
322  }
323
324  /**
325   * Register a warning. Delegates to an {@link IErrorHandler}.
326   * @param s   the warning message.
327   */
328  @Deprecated
329  public void ASTNode.warning(String s) {
330          root().getErrorHandler().warning(s, this);
331  }
332 
333  /**
334   * Register a warning. Delegates to an {@link IErrorHandler}.
335   *
336   * Builds warning message using <code>format</code> as format string.
337   */
338  @Deprecated
339  public void ASTNode.warning(String format, Object... args) {
340          warning(String.format(format, args));
341  }
342
343  /**
344   * Register a problem. Delegates to an {@link IErrorHandler}.
345   * @param p   the problem.
346   */
347  @Deprecated
348  public void ASTNode.problem(Problem p) {
349      root().getErrorHandler().problem(p);
350  }
351
352    /**
353     * If this node is in a disabled conditional component, generate a warning, otherwise generate an error.
354     */
355    @Deprecated
356    public void ASTNode.errorUnlessDisabled(String s) {
357        if (inDisabledComponent()) {
358            warning("Found error in disabled conditional:\n  " + s);
359        } else {
360            error(s);
361        }
362    }
363
364    /**
365     * If this node is in a disabled conditional component, generate a warning, otherwise generate an error.
366     */
367    @Deprecated
368    public void ASTNode.errorUnlessDisabled(String format, Object... args) {
369        if (inDisabledComponent()) {
370            warning("Found error in disabled conditional:\n  " + format, args);
371        } else {
372            error(format, args);
373        }
374    }
375
376    /**
377     * If this node is in a disabled conditional component and <code>condition</code> is <code>true</code>,
378     * generate a warning, otherwise generate an error.
379     */
380    @Deprecated
381    public void ASTNode.errorUnlessDisabledAnd(boolean condition, String s) {
382        if (condition) {
383            errorUnlessDisabled(s);
384        } else {
385            error(s);
386        }
387    }
388
389    /**
390     * If this node is in a disabled conditional component and <code>condition</code> is <code>true</code>,
391     * generate a warning, otherwise generate an error.
392     */
393    @Deprecated
394    public void ASTNode.errorUnlessDisabledAnd(boolean condition, String format, Object... args) {
395        if (condition) {
396            errorUnlessDisabled(format, args);
397        } else {
398            error(format, args);
399        }
400    }
401
402    public interface LockBranch {
403        /**
404         * Lock the closest surrounding if-equation or if-expression that have only
405         * parameter-expression tests and evaluates to another branch. Returns true
406         * if any such if exists.
407         *
408         * Any parameters used in the test will be marked as structural.
409         *
410         * NB: This has side-effects, despite being an inherited attribute.
411         *
412         * @param checkType  the type of error checks to use when marking structural parameters
413         */
414        public boolean lockBranch(ErrorCheckType checkType);
415    }
416    FExp implements LockBranch;
417    FExpSubscript implements LockBranch;
418    FAbstractEquation implements LockBranch;
419    FStatement implements LockBranch;
420    FIfWhenClause implements LockBranch;
421    InstComponentDecl implements LockBranch;
422    InstFunctionArgument implements LockBranch;
423    FFunctionCallLeft implements LockBranch;
424    InstValueModification implements LockBranch;
425
426    // TODO: find way to move side-effects out from inh attr
427    inh boolean FExp.lockBranch(ErrorCheckType checkType);
428    inh boolean FExpSubscript.lockBranch(ErrorCheckType checkType);
429    inh boolean FIntegerSubscript.lockBranch(ErrorCheckType checkType);
430    inh boolean FAbstractEquation.lockBranch(ErrorCheckType checkType);
431    inh boolean FStatement.lockBranch(ErrorCheckType checkType);
432    inh boolean FIfWhenClause.lockBranch(ErrorCheckType checkType);
433    inh boolean InstComponentDecl.lockBranch(ErrorCheckType checkType);
434    inh boolean InstFunctionArgument.lockBranch(ErrorCheckType checkType); 
435    inh boolean FFunctionCallLeft.lockBranch(ErrorCheckType checkType);
436    inh boolean InstValueModification.lockBranch(ErrorCheckType checkType);
437    eq FIfExp.getThenExp().lockBranch(ErrorCheckType checkType)                = lockMyBranch(this, checkType, getIfExp(), true);
438    eq FIfExp.getElseExp().lockBranch(ErrorCheckType checkType)                = lockMyBranch(this, checkType, getIfExp(), false);
439    eq FIfEquation.getFAbstractEquation().lockBranch(ErrorCheckType checkType) = lockMyBranch(this, checkType, getTest(), true);
440    eq FIfEquation.getElse().lockBranch(ErrorCheckType checkType)              = lockMyBranch(this, checkType, getTest(), false);
441    eq FIfClause.getFStatement().lockBranch(ErrorCheckType checkType)          = lockMyBranch(this, checkType, getTest(), true);
442    eq FIfStmt.getFIfWhenClause(int i).lockBranch(ErrorCheckType checkType)    = lockMyBranch(checkType, i);
443    eq FIfStmt.getElseStmt().lockBranch(ErrorCheckType checkType)              = lockMyBranch(checkType, getNumFIfWhenClause());
444    eq FConnectClause.getConnector1().lockBranch(ErrorCheckType checkType)     = getConnector2().isDisabled() || lockBranch(checkType);
445    eq FConnectClause.getConnector2().lockBranch(ErrorCheckType checkType)     = getConnector1().isDisabled() || lockBranch(checkType);
446    eq InstComponentDecl.getChild().lockBranch(ErrorCheckType checkType)       = isDisabled() || lockBranch(checkType);
447    eq InstValueModification.getFExp().lockBranch(ErrorCheckType checkType)    = isSuperseded() || lockBranch(checkType);
448    eq InstClassDecl.getChild().lockBranch(ErrorCheckType checkType)           = false;
449    eq InstRoot.getChild().lockBranch(ErrorCheckType checkType)                = false;
450    eq FClass.getChild().lockBranch(ErrorCheckType checkType)                  = false;
451
452    /**
453     * Lock branch on src and return true if it only has parameter-expression
454     * tests that evaluates to use the branch not indicated by <code>then</code>.
455     * Otherwise delegates to {@link LockBranch#lockBranch(ErrorCheckType)}.
456     *
457     * Any parameters used in the test will be marked as structural.
458     *
459     * @param checkType  the type of error checks to use when marking structural parameters
460     * @param then       if true, we are trying to remove the then-branch, otherwise the else-branch
461     */
462    public static boolean ASTNode.lockMyBranch(LockBranch src, ErrorCheckType checkType, FExp exp, boolean then) {
463        if (exp.lockable(then)) {
464            exp.markAsStructuralParameter(checkType);
465            return true;
466        } else {
467            return src.lockBranch(checkType);
468        }
469    }
470
471    syn boolean FExp.lockable(boolean then) {
472        if (variability().fixedParameterOrLess()) {
473            try {
474                CValue val = ceval();
475                return val.hasBooleanValue() && val.booleanValue() != then;
476            } catch (ConstantEvaluationException e) {}
477        }
478        return false;
479    }
480
481    public boolean FIfStmt.lockMyBranch(ErrorCheckType checkType, int i) {
482        if (i == 0) {
483            return lockBranch(checkType);
484        } else {
485            FIfWhenClause next = getFIfWhenClause(i - 1);
486            return lockMyBranch(next, checkType, next.getTest(), false);
487        }
488    }
489
490    syn boolean InstValueModification.isSuperseded() {
491        InstComponentDecl cmp = myTargetComponent();
492        InstModification mod = cmp.isAttribute() ? 
493                parentTargetComponent().totalMergedEnvironment().find(cmp.name()) : 
494                cmp.myInstValueMod();
495        return mod != null && mod != this;
496    }
497
498    inh InstComponentDecl InstModification.myTargetComponent();
499    eq InstComponentModification.getChild().myTargetComponent() = getName().myInstComponentDecl();
500    eq InstComponentDecl.getChild().myTargetComponent()         = this;
501    eq InstNode.getChild().myTargetComponent()                  = unknownInstComponentDecl();
502    eq InstRecordConstructor.getChild().myTargetComponent()     = unknownInstComponentDecl();
503
504    inh InstComponentDecl InstModification.parentTargetComponent();
505    eq InstComponentModification.getChild().parentTargetComponent() = myTargetComponent();
506    eq InstNode.getChild().parentTargetComponent()                  = unknownInstComponentDecl();
507    eq InstRecordConstructor.getChild().parentTargetComponent()     = unknownInstComponentDecl();
508
509    syn boolean InstComponentDecl.isAttribute() = false;
510    eq InstBuiltIn.isAttribute()                = true;
511
512
513    /**
514     * Class used by the error check to delegate to different error checks.
515     * This class is subtyped for each error check with different
516     * implementations of check() that delegate to corresponding check.
517     */
518    public abstract class ErrorChecker {
519        private final String name;
520
521        public ErrorChecker(String name) {
522            this.name = name;
523        }
524
525        /**
526         * Do check on ASTNode node with the ErrorCheckType check type.
527         */
528        public abstract void check(ASTNode node, ErrorCheckType checkType);
529
530        @Override
531        public String toString() {
532            return name;
533        }
534    }
535
536    /**
537     * A list that contains all error checkers. New error checkers are added
538     * dynamically during static evaluation by calling addErrorChecker().
539     *
540     * @see ASTNode.addErrorChecker(ErrorChecker)
541     */
542    private static Collection<ErrorChecker> ASTNode.ERROR_CHECKERS;
543
544    /**
545     * Add ErrorChecker checker to the list of error checkers. This method
546     * should only be called from ASTnode in order to ensure that the checker
547     * is added corretly during static evaluation, hence the private
548     * visibility.
549     */
550    private static ErrorChecker ASTNode.addErrorChecker(ErrorChecker checker) {
551        if (ERROR_CHECKERS == null)
552            ERROR_CHECKERS = new ArrayList<ErrorChecker>();
553        ERROR_CHECKERS.add(checker);
554        return checker;
555    }
556
557    /**
558     * A helper method that calls all registered error checkers.
559     *
560     * @see ASTNode#addErrorChecker(ErrorChecker)
561     */
562    protected void ASTNode.allChecks(ErrorCheckType checkType) {
563        for (ErrorChecker checker : ERROR_CHECKERS)
564            checker.check(this, checkType);
565    }
566
567    public void ASTNode.collectErrors(ErrorCheckType checkType) {
568        for (ASTNode n : this) {
569            n.collectErrors(checkType);
570        }
571        allChecks(checkType);
572    }
573
574
575    public void ASTNode.errorCheck(ErrorCheckType checkType) {
576        collectErrors(checkType);
577        breakOnErrors();
578    }
579
580    inh InstComponentDecl ASTNode.errorEnclosingComponent();
581    eq InstNode.getChild().errorEnclosingComponent() = containingInstComponent();
582    eq InstComponentDecl.getChild().errorEnclosingComponent() {
583        if (isRedeclared() || getSrcComponentDecl().hasRedeclare()) {
584            return errorEnclosingComponent();
585        } else {
586            return containingInstComponent();
587        }
588    }
589    eq InstComponentDecl.getFAbstractEquation().errorEnclosingComponent() = this;
590   
591    eq FlatRoot.getChild().errorEnclosingComponent() = null;
592    eq InstRoot.getChild().errorEnclosingComponent() = null;
593    eq SourceRoot.getChild().errorEnclosingComponent() = null;
594
595    syn String ASTNode.errorComponentName() {
596        InstComponentDecl parent = errorEnclosingComponent();
597        return parent == null ? null : parent.getFAccess().scalarName(false);
598    }
599
600}
601
602aspect InstanceErrorCheck {
603
604 // Error checking in instance tree
605
606    // We don't want to error check an entire model, just the classes
607    //   that are used.
608    public void InstProgramRoot.checkErrorsInInstClass(String className, ErrorCheckType checkType) throws ModelicaClassNotFoundException {
609        InstClassDecl icd = instantiateModel(className);
610        if (!icd.isUnknown()) {
611            icd.errorCheck(checkType);
612        } else {
613            throw new ModelicaClassNotFoundException(className);
614        }
615    }
616
617    public void InstClassDecl.checkErrorsInModelInstance(String className, ErrorCheckType checkType) throws ModelicaClassNotFoundException {
618        errorCheck(checkType);
619    }
620
621    public void UnknownInstClassDecl.checkErrorsInModelInstance(String className, ErrorCheckType checkType) throws ModelicaClassNotFoundException {
622        throw new ModelicaClassNotFoundException(className);
623    }
624
625        protected boolean BaseNode.errorChecked = false;
626
627        public void ASTNode.resetCollectErrors() {
628                for (ASTNode n : noTransform())
629                        n.resetCollectErrors();
630        }
631       
632        public static void ASTNode.resetCollectErrorsOn(ASTNode n) {
633                if (n != null)
634                        n.resetCollectErrors();
635        }
636       
637        public void BaseNode.resetCollectErrors() {
638                errorChecked = false;
639                super.resetCollectErrors();
640        }
641       
642        public void InstNode.resetCollectErrors() {
643                super.resetCollectErrors();
644                resetCollectErrorsOn(getInstComponentDeclListNoTransform());
645                resetCollectErrorsOn(getInstClassDeclListNoTransform());
646                resetCollectErrorsOn(getInstExtendsListNoTransform());
647                resetCollectErrorsOn(getInstImportListNoTransform());
648                resetCollectErrorsOn(getRedeclaredInstClassDeclListNoTransform());
649                resetCollectErrorsOn(getFAbstractEquationListNoTransform());
650        }
651
652  public void InstNode.collectErrors(ErrorCheckType checkType) {
653    if (!errorChecked) {
654      errorChecked = true;
655          allChecks(checkType);
656          for (InstNode n : getInstComponentDecls()) 
657                  n.collectErrors(checkType);
658          for (InstNode n : getInstExtendss()) 
659                  n.collectErrors(checkType);
660          for (FAbstractEquation e : getFAbstractEquations()) 
661                  e.collectErrors(checkType);
662        }
663  }
664   
665    /**
666     * Check if this node is in an InstComponentDecl.
667     */
668    inh boolean InstExtends.inInstComponent();
669    inh boolean InstClassRedeclare.inInstComponent();
670    eq InstComponentDecl.getChild().inInstComponent() = true;
671    eq InstClassDecl.getChild().inInstComponent()     = false;
672    eq InstRoot.getChild().inInstComponent()          = false;
673    eq FlatRoot.getChild().inInstComponent()          = false;
674    eq InstRecordConstructor.getChild().inInstComponent() = false;
675   
676   
677    public void FExp.collectErrors(ErrorCheckType checkType) {
678        if (!errorChecked) {
679            errorChecked = true;
680            super.collectErrors(checkType);
681        }
682    }
683
684    public void InstBaseClassDecl.collectErrors(ErrorCheckType checkType) {
685        if (!errorChecked) {
686            super.collectErrors(checkType);
687            errorChecked = true;
688            for (InstImport ii : getInstImports()) {
689                ii.collectErrors(checkType);
690            }
691            if (hasInstConstrainingClass()) {
692                getInstConstrainingClass().collectErrors(checkType);
693            }
694            getInstRestriction().collectErrors(checkType);
695            getInstGeneratedInners().collectErrors(checkType);
696            if (getSrcBaseClassDecl() instanceof SrcFullClassDecl) {
697                SrcFullClassDecl fcd = (SrcFullClassDecl) getSrcBaseClassDecl();
698                if (!(fcd.getName().getID().equals(fcd.getSrcEndDecl().getEndID()))) {
699                    error("The declaration and end names of a class should be the same");
700                }
701            }
702        }
703    }
704
705    public void InstFullClassDecl.collectErrors(ErrorCheckType checkType) {
706        if (!errorChecked) {
707            super.collectErrors(checkType);
708            errorChecked = true;
709            getInstExternalOpt().collectErrors(checkType);
710            if (isFunction())
711                errorCheckDerivativeAnnotations(checkType);
712        }
713    }
714
715    public void InstGeneratedInner.collectErrors(ErrorCheckType checkType) {
716        if (!checkType.allowBadGeneratedInner()) {
717            boolean error = false;
718            if (getMatchingNonInner() != null) {
719                getCopiedOuter().error("Can not generate missing inner declaration for %s, due to presence of component with same name on top level", name());
720                error = true;
721            } else {
722                ListMap<String, String> map = new LinkedHashListMap<String, String>();
723                for (InstComponentDecl outer : outers) {
724                    if (outer.myInstClass().isPartial()) {
725                        outer.error("Can not generate missing inner declaration for outer component %s of partial type %s", 
726                                outer.name(), outer.myInstClass().qualifiedName());
727                        error = true;
728                    } else {
729                        map.add(outer.myInstClass().actualInstClass().qualifiedName(), outer.qualifiedName());
730                    }
731                }
732                if (map.size() > 1) {
733                    StringBuilder sb = new StringBuilder();
734                    java.util.List<String> classes = new ArrayList<String>(map.keySet());
735                    Collections.sort(classes);
736                    for (String cls : classes) {
737                        java.util.List<String> components = map.get(cls);
738                        Collections.sort(components);
739                        for (String outer : components) {
740                            sb.append("\n    ");
741                            sb.append(cls);
742                            sb.append(" ");
743                            sb.append(outer);
744                        }
745                    }
746                    getCopiedOuter().error("Can't generate missing inner declaration for %s, due to the outer declarations being of different types: %s", name(), sb);
747                    error = true;
748                }
749            }
750            if (!error) {
751                getInstComponentDecl().collectErrors(checkType);
752                // TODO: Use missingInnerMessage annotation
753                getCopiedOuter().warning("Generated missing inner declaration for '%s'", getCopiedOuter());
754            }
755        }
756    }
757
758    public void InstBaseClassDecl.errorCheckDerivativeAnnotations(ErrorCheckType checkType) {
759        errorCheckDerivativeAnnotations(checkType, findDerivativeAnnotationRoot());
760    }
761   
762    private void InstBaseClassDecl.errorCheckDerivativeAnnotations(ErrorCheckType checkType, AnnotationNode src) {
763        for (AnnotationNode derivative : src.allFor("derivative")) {
764            errorCheckDerivativeAnnotation(checkType, derivative);
765        }
766    }
767
768    private void InstBaseClassDecl.errorCheckDerivativeAnnotation(ErrorCheckType checkType, AnnotationNode derivative) {
769        // TODO: Check that inputs/outputs of target function matches this function
770        if (!derivative.isValue()) {
771            derivative.ast().error("Function name is missing in derivative annotation declaration");
772            return;
773        }
774        InstLookupResult<InstClassDecl> lr = derivative.lookupInstClass();
775        if (lr == null) {
776            derivative.ast().error("Invalid derivative function reference");
777            return;
778        }
779        if (lr.isProblem()) {
780            lr.problem(derivative.ast(), "function", derivative.valueToString());
781            if (lr.isError()) {
782                return;
783            }
784        }
785        InstClassDecl icd = lr.target().actualInstClass();
786        if (!icd.isFunction()) {
787            derivative.ast().error("The class " + derivative.valueToString() + " is not a function");
788            return;
789        }
790        icd.collectErrors(checkType);
791        boolean orderFound = false;
792        Set<String> noAndZeroDerivatives = new HashSet<String>();
793        for (AnnotationNode attrNode : derivative) {
794            if ("noDerivative".equals(attrNode.name()) || "zeroDerivative".equals(attrNode.name())) {
795                InstLookupResult<InstComponentDecl> res = attrNode.lookupInstComponent();
796                if (res == null) {
797                    attrNode.ast().error("Expecting variable reference for " + attrNode.name() + " annotation");
798                    continue;
799                }
800                String varName = attrNode.valueToString();
801                if (!noAndZeroDerivatives.add(varName))
802                    attrNode.ast().error("Multiple noDerivative or zeroDerivative declarations for " + varName);
803                if (res.isNotFound())
804                    attrNode.ast().error("Unable to find " + varName);
805                else if (!res.target().isInput())
806                    attrNode.ast().error(attrNode.name() + " annotation may only reference input variables");
807            } else if ("order".equals(attrNode.name())) {
808                if (orderFound)
809                    attrNode.ast().error("Multiple declarations of the order attribute");
810                orderFound = true;
811                if (!attrNode.isIntegerValue())
812                    attrNode.ast().error("Expecting integer typed expression for order attribute");
813                else if (attrNode.integer() < 1)
814                    attrNode.ast().error("Order attribute must be greater or equal to one");
815            }
816        }
817    }
818
819    public void InstSimpleShortClassDecl.collectErrors(ErrorCheckType checkType) {
820        if (!errorChecked) {
821            errorChecked = true;
822            getTarget().collectErrors(checkType);
823            actualInstClass().collectErrors(checkType);
824        }
825    }
826
827    public void InstLibNode.collectErrors(ErrorCheckType checkType) {
828        if (!errorChecked) {
829            errorChecked = true;
830            actualInstClass().collectErrors(checkType);
831        }
832    }
833
834    public void InstImport.collectErrors(ErrorCheckType checkType) {
835        if (!errorChecked) {
836            errorChecked = true;
837            getPackageName().collectErrors(checkType);
838        }
839    }
840
841    public void InstComponentDecl.collectErrors(ErrorCheckType checkType) {
842        if (!errorChecked) {
843            errorChecked = true;
844            if (checkType.checkForRecursiveStructure() && isRecursed()) {
845                error("Recursive class structure");
846            } else if (isOuter()) {
847                myInnerInstComponentDecl().collectErrors(checkType);
848            } else {
849                collectErrorsInClassName(checkType);
850                myInstClass().checkRestriction(checkType);
851                if (hasFArraySubscripts()) {
852                    getFArraySubscripts().collectErrors(checkType);
853                }
854                if (hasConditionalAttribute()) {
855                    FExp cond = getConditionalAttribute();
856                    cond.collectErrors(checkType);
857                    if (!cond.type().isUnknown()) {
858                        if (!cond.type().isScalar() || !cond.type().isBoolean()) {
859                            NON_BOOLEAN_CONDITIONAL_GUARD.invoke(this);
860                        }
861                        if (!cond.variability().fixedParameterOrLess()) {
862                            NON_FIXED_CONDITIONAL_GUARD.invoke(this);
863                        } else {
864                            cond.markAsStructuralParameter(checkType);
865                        }
866                    }
867                }
868                if (!isDisabled() && hasInstModification()) {
869                    getInstModification().collectErrors(checkType);
870                }
871                for (InstModification im : getMergedEnvironment()) {
872                    im.checkModificationNames(checkType);
873                }
874               
875                if (shouldCheckInto(checkType)) {
876                    errorChecked = false;
877                    super.collectErrors(checkType);
878                    if (hasInstConstrainingComponent()) {
879                        getInstConstrainingComponent().collectErrors(checkType);
880                    }
881                }
882            }
883        }
884    }
885
886    /**
887     * Check that the restriction of this class is fulfilled.
888     */
889    public void InstClassDecl.checkRestriction(ErrorCheckType checkType) {}
890    public void InstBaseClassDecl.checkRestriction(ErrorCheckType checkType) {
891        if (!errorChecked)
892            getInstRestriction().collectErrors(checkType);
893    }
894
895    public void InstModification.checkModificationNames(ErrorCheckType checkType) {}
896   
897    public void InstElementModification.checkModificationNames(ErrorCheckType checkType) {
898        getName().allChecks(checkType);
899    }
900       
901        syn boolean InstComponentDecl.shouldCheckInto(ErrorCheckType checkType) =
902                !isDisabled() || checkType.checkInactiveComponents() || myOptions().getBooleanOption("check_inactive_contitionals");
903
904        public void InstComponentDecl.collectErrorsInClassName(ErrorCheckType checkType) {
905                getClassName().collectErrors(checkType);
906        }       
907       
908        public void InstArrayComponentDecl.collectErrorsInClassName(ErrorCheckType checkType) {
909                // TODO: use correct class name instead of "ArrayDecl" so that name lookup suceeds instead?
910                //       need that for other things as well, but is there problems with it?
911        }       
912       
913        public void FExp.checkConstantExpression(ErrorCheckType checkType, String varKind, String varName) {
914                boolean failed = false;
915        ConstantEvaluationException eres = null;
916                try {
917                        if (isCircular()) {
918                            if (!checkType.allowConstantNoValue())
919                                error("Could not evaluate binding expression for %s '%s' due to circularity: '%s'", 
920                                                varKind, varName, prettyPrint(""));
921                        } else {
922                                CValue val = ceval();
923                                if (val.isPartlyUnknown()) {
924                                        if (val.isUnsupported()) {
925                                                compliance("Constant evaluation not supported for expression(s) directly or indirectly " + 
926                                                                "used by the binding expression for %s '%s': '%s'", varKind, varName, prettyPrint(""));
927                                        } else {
928                                                failed = true;
929                                        }
930                                }
931                        }
932                } catch (ConstantEvaluationNotReadyException e) {
933                        // Will be evaluatable later, ignore for now
934                } catch (ConstantEvaluationException e) {
935                        failed = true;
936                        eres = e;
937                }
938                if (failed && !checkType.allowConstantNoValue()) {
939                        error("Could not evaluate binding expression for %s '%s': '%s'%s", varKind, varName, prettyPrint(""),
940                                eres == null ? "" : eres.getModelicaStackTrace());
941                }
942        }
943
944    public static final SimpleProblemProducer ASTNode.PARAMETER_MISSING_BINDING_EXPRESSION =
945            new SimpleWarningProducer("PARAMETER_MISSING_BINDING_EXPRESSION", ProblemKind.SEMANTIC, "The parameter %s does not have a binding expression");
946    public static final SimpleProblemProducer ASTNode.CONSTANT_MISSING_BINDING_EXPRESSION =
947            new SimpleWarningProducer("CONSTANT_MISSING_BINDING_EXPRESSION", ProblemKind.SEMANTIC, "The constant %s does not have a binding expression");
948   
949    public void InstAssignable.collectErrors(ErrorCheckType checkType) {
950        //log.debug(toString());
951        if (!errorChecked) {
952            super.collectErrors(checkType);
953            errorChecked = true;
954           
955            // Check modification
956            if (hasInstValueMod()) {
957                myInstValueMod().collectErrors(checkType);
958            }
959           
960            if (hasBindingFExp()) {
961                // Check if the binding expression of constants can be evaluated
962                FExp bexp = getBindingFExp();
963                if (isConstant() && !bexp.type().isUnknown()) {
964                    bexp.checkConstantExpression(checkType, "constant", qualifiedName());
965                } else if (isParameter() && bexp.isCircular()) {
966                    bexp.error("Circularity in binding expression of parameter: %s = %s", qualifiedName(), bexp);
967                }
968            } else {
969                // Warn if constant or parameter does not have a binding expression (start is used)
970                if (variability().fixedParameterOrLess() && !isForIndex() && !isRecord() && 
971                        !hasParentRecordWithBindingExp() && !inFunction()) {
972                    if (isParameter()) {
973                        PARAMETER_MISSING_BINDING_EXPRESSION.invoke(this, qualifiedName());
974                    } else {
975                        CONSTANT_MISSING_BINDING_EXPRESSION.invoke(this, qualifiedName());
976                    }
977                }
978            }
979           
980            TypePrefixVariability v = variability().combine();
981            // Mark parameters with Evaluate=true as structural
982            if (v.parameterVariability() && isEvalAnnotated(true)) {
983                if (v.fixedParameterOrLess()) {
984                    forceVariability(checkType, Variability.STRUCTPARAMETER);
985                } else {
986                    warning("Evaluate annotation is ignored for parameters with fixed=false");
987                }
988            }
989           
990            // Check array indices
991            getClassName().collectErrors(checkType);
992            getLocalFArraySubscriptsOpt().collectErrors(checkType);
993           
994            // Check attributes for primitive variables
995            checkAttributes(checkType);
996        }
997    }
998   
999        public void InstAssignable.checkAttributes(ErrorCheckType checkType) {}
1000
1001    public static final SimpleProblemProducer ASTNode.START_VALUE_NOT_PARAMETER =
1002            new SimpleErrorProducer("START_VALUE_NOT_PARAMETER", ProblemKind.SEMANTIC,
1003                    "Variability of binding expression for attribute '%s' is not less"
1004                    + " than or equal to parameter variability: %s");
1005    public static final SimpleProblemProducer ASTNode.START_VALUE_INITIAL_PARAMETER =
1006            new SimpleWarningProducer("START_VALUE_INITIAL_PARAMETER", ProblemKind.COMPLIANCE,
1007                    "Variability of binding expression for attribute '%s' is "
1008                    + " initial parameter variability: %s");
1009
1010        public void InstPrimitive.checkAttributes(ErrorCheckType checkType) {
1011                // Check if the expressions of the attributes can be evaluated
1012                // Note that this check has to be done locally in the
1013                // context of an InstAssignable node in order to avoid
1014                // evaluation of all value modifications also for non
1015                // parameters.
1016                for (InstModification im : totalMergedEnvironment()) {
1017                        // Only check attributes, value modifications are checked above
1018                        if (im instanceof InstComponentModification) {
1019                                InstComponentModification icm = (InstComponentModification)im;
1020                                if (icm.hasInstModification() && icm.getInstModification().hasInstValueMod()) {
1021                                        FExp val_mod = icm.getInstModification().instValueMod();
1022                    if (val_mod.variability().lessOrEqual(Variability.CONSTANT)) {
1023                        val_mod.checkConstantExpression(checkType, "attribute", icm.getName().name());
1024                    } else if (!val_mod.variability().parameterOrLess()) {
1025                        ASTNode.START_VALUE_NOT_PARAMETER.invoke(val_mod, icm.getName().name(), val_mod);
1026                    }
1027                                }
1028                        }
1029                }
1030        }
1031
1032       
1033    public static final SimpleProblemProducer ASTNode.UNSPECIFIED_ENUM_COMPONENT =
1034            new SimpleErrorProducer("UNSPECIFIED_ENUM_COMPONENT", ProblemKind.SEMANTIC,
1035                    "Components of unspecified enumerations are not allowed in simulation models:\n %s");
1036
1037        syn boolean InstNode.isUnspecifiedEnum() = false;
1038        eq InstPrimitive.isUnspecifiedEnum() = myInstClass().isUnspecifiedEnum();
1039        eq InstClassDecl.isUnspecifiedEnum() = enumLiterals().isEmpty();
1040
1041        public void InstExtends.collectErrors(ErrorCheckType checkType) {
1042            if (!errorChecked) {
1043                if (checkType.checkForRecursiveStructure() && isRecursed()) {
1044                        error("Recursive class structure");
1045                        errorChecked = true;
1046                } else {
1047                                super.collectErrors(checkType);
1048                        errorChecked = true;
1049                                getClassName().collectErrors(checkType);
1050                                if (hasInstClassModification() && shouldCheckModification())
1051                                        getInstClassModification().collectErrors(checkType);
1052                        }
1053            }
1054        }
1055       
1056        // Normally the class modifications in an InstExtendsShortClass
1057        // does not need to be checked, since they are checked in InstShortClassDecl.
1058        // This is not the case if the short class decl references
1059        // an primitive variable, however, and in this case the
1060        // class modification needs to be checked for errors.
1061        syn boolean InstExtends.shouldCheckModification()           = true;
1062        eq InstExtendsShortClass.shouldCheckModification()          = extendsPrimitive();
1063        eq InstReplacingExtendsShortClass.shouldCheckModification() = extendsPrimitive();
1064
1065    public void InstShortClassDecl.collectErrors(ErrorCheckType checkType) {
1066        if (!errorChecked) {
1067          super.collectErrors(checkType);
1068          errorChecked = true;
1069          // The localInstModifications should only be checked if
1070          // the node is not a InstReplacingShortClassDecl. This
1071          // is accomplished by the method collectInstModificationErrors.
1072          collectInstModificationErrors(checkType);
1073          if (hasInstConstrainingClass()) {
1074                getInstConstrainingClass().collectErrors(checkType);
1075          }
1076        }
1077    }
1078
1079        public void InstShortClassDecl.collectInstModificationErrors(ErrorCheckType checkType) {
1080                for (InstModification mod : localInstModifications())
1081                        mod.collectErrors(checkType);
1082    }
1083    public void InstReplacingShortClassDecl.collectInstModificationErrors(ErrorCheckType checkType) { }
1084
1085        public void InstReplacingShortClassDecl.collectErrors(ErrorCheckType checkType) {
1086            if (!errorChecked) {
1087                  super.collectErrors(checkType);
1088          errorChecked = true;
1089                  getOriginalInstClass().collectErrors(checkType);
1090                }
1091               
1092        }
1093
1094        public void InstReplacingFullClassDecl.collectErrors(ErrorCheckType checkType) {
1095            if (!errorChecked) {
1096                  super.collectErrors(checkType);
1097          errorChecked = true;
1098                  getOriginalInstClass().collectErrors(checkType);
1099                }
1100        }
1101
1102        public void InstBuiltIn.collectErrors(ErrorCheckType checkType) {}
1103
1104        public void InstComponentRedeclare.collectErrors(ErrorCheckType checkType) {
1105                if (!errorChecked) {
1106                    super.collectErrors(checkType);
1107                    errorChecked = true;
1108                }
1109        }
1110       
1111        public void InstNode.checkRedeclares(ErrorCheckType checkType) {
1112            if (!errorChecked) {
1113                for (InstNode n : getInstComponentDecls()) 
1114                    n.checkRedeclares(checkType);
1115                for (InstNode n : getInstExtendss()) 
1116                    n.checkRedeclares(checkType);
1117              }
1118        }
1119
1120    public void InstReplacingRecord.checkRedeclares(ErrorCheckType checkType) {
1121        super.checkRedeclares(checkType);
1122        if (shouldCheckInto(checkType))
1123            typeCheckReplacingComponent(getOriginalInstComponent(), checkType);
1124    }
1125
1126    public void InstReplacingComposite.checkRedeclares(ErrorCheckType checkType) {
1127        super.checkRedeclares(checkType);
1128        if (shouldCheckInto(checkType))
1129            typeCheckReplacingComponent(getOriginalInstComponent(), checkType);
1130    }
1131
1132    public void InstReplacingPrimitive.checkRedeclares(ErrorCheckType checkType) {
1133        super.checkRedeclares(checkType);
1134        if (shouldCheckInto(checkType))
1135            typeCheckReplacingComponent(getOriginalInstComponent(), checkType);
1136    }
1137
1138    public void InstReplacingExpandableConnectorDecl.checkRedeclares(ErrorCheckType checkType) {
1139        super.checkRedeclares(checkType);
1140        if (shouldCheckInto(checkType))
1141            typeCheckReplacingComponent(getOriginalInstComponent(), checkType);
1142    }
1143
1144    public void InstComponentDecl.checkRedeclares(ErrorCheckType checkType) {
1145        if (!isDisabled() && hasInstModification()) {
1146            getInstModification().collectErrors(checkType);
1147        }
1148        if (shouldCheckInto(checkType)) {
1149            if (hasInstConstrainingComponent()) {
1150                getInstConstrainingComponent().collectErrors(checkType);
1151            }
1152            super.checkRedeclares(checkType);
1153        }
1154    }
1155
1156        public void InstClassRedeclare.collectErrors(ErrorCheckType checkType) {
1157                super.collectErrors(checkType);
1158//              if (!inInstComponent())
1159//                      getInstClassDecl().collectErrors(checkType);   
1160        }
1161
1162        public void InstValueModification.collectErrors(ErrorCheckType checkType) {
1163                getFExp().collectErrors(checkType);
1164        }
1165
1166    public void InstDot.collectErrors(ErrorCheckType checkType) {
1167        for (InstAccess ia : getInstAccesss()) {
1168            ia.collectErrors(checkType);
1169            if (ia.isUnknown() || !ia.myInstComponentDecl().shouldCheckInto(checkType))
1170                break;
1171        }
1172        allChecks(checkType);
1173    }
1174
1175        public void InstClassAccess.collectErrors(ErrorCheckType checkType) {
1176            nameCheck(checkType);
1177        }
1178
1179        public void InstComponentAccess.collectErrors(ErrorCheckType checkType) {
1180            super.collectErrors(checkType);
1181            if (!myInstComponentDecl().isUnknown() && !isModificationName())
1182                myInstComponentDecl().collectErrors(checkType);
1183        }
1184       
1185        public void InstComponentArrayAccess.collectErrors(ErrorCheckType checkType) {
1186            super.collectErrors(checkType);
1187            if (!myInstComponentDecl().isUnknown() && !isModificationName())
1188                myInstComponentDecl().collectErrors(checkType);
1189        }
1190       
1191        inh boolean InstAccess.isModificationName();
1192        eq InstNamedModification.getName().isModificationName() = true;
1193        eq BaseNode.getChild().isModificationName()             = false;
1194
1195        inh boolean FArraySubscripts.myAccessExists();
1196        eq Root.getChild().myAccessExists()       = false;
1197        eq InstAccess.getChild().myAccessExists() = !myInstComponentDecl().isUnknown();
1198       
1199        public void FArrayExpSubscripts.collectErrors(ErrorCheckType checkType) {
1200                // Should this check be in the access instead?
1201        int ndims = myDims();
1202                if (getNumFSubscript() > ndims && !isInstComponentSize() && myAccessExists()) {
1203                        // TODO: shouldn't this check for to few as well? (no [] or all dimensions given)
1204                        error("Too many array subscripts for access: " + getNumFSubscript() + 
1205                    " subscripts given, component has " + ndims + " dimensions");
1206                        allChecks(checkType);
1207                        for (int i = 0; i < ndims; i++)
1208                                getFSubscript(i).collectErrors(checkType);
1209                } else {
1210                super.collectErrors(checkType);
1211                }
1212        }
1213
1214    public void FArrayLitSubscripts.collectErrors(ErrorCheckType checkType) {
1215        /*
1216         * Does not need implementation since error checking is done in the instance tree,
1217         * and there should not be any FArrayLitSubscripts there.
1218         * The reason for that is information necessary for error printing (line and column number)
1219         * is not saved in FArrayLitSubscripts.
1220         */
1221        throw new UnsupportedOperationException();
1222    }
1223
1224    public void FBreakStmt.collectErrors(ErrorCheckType checkType) {
1225        if (enclosingLoop() == null)
1226            error("Break statement must be inside while- or for-statement");
1227    }
1228
1229        /**
1230         * Check if class has exactly one algorithm section or external function declaration.
1231         */
1232    public boolean InstClassDecl.isCompleteFunction() {
1233        return (numFAlgorithm() == 1);
1234    }
1235    syn boolean InstPartialFunction.isCompleteFunction() = true;
1236   
1237        syn boolean InstClassDecl.hasInstExternal() = false;
1238       
1239        syn int InstClassDecl.numInstExternal() {
1240                int n = hasInstExternal() ? 1 : 0;
1241                for (InstExtends ie : getInstExtendss())
1242                        n += ie.myInstClass().numInstExternal();
1243                return n;
1244        }
1245    eq InstSimpleShortClassDecl.numInstExternal() = actualInstClass().numInstExternal();
1246    eq InstLibNode.numInstExternal()              = actualInstClass().numInstExternal();
1247       
1248        syn int InstClassDecl.numFAlgorithm() {
1249                int n = 0;
1250                for (FAbstractEquation e : getFAbstractEquations())
1251                        if (e instanceof FAlgorithm)
1252                                n++;
1253                for (InstExtends ie : getInstExtendss())
1254                        n += ie.myInstClass().numFAlgorithm();
1255                return n;
1256        }
1257    eq InstSimpleShortClassDecl.numFAlgorithm() = actualInstClass().numFAlgorithm();
1258    eq InstLibNode.numFAlgorithm()              = actualInstClass().numFAlgorithm();
1259       
1260        public void InstExternalObject.collectErrors(ErrorCheckType checkType) {
1261            if (!errorChecked) {
1262                        super.collectErrors(checkType);
1263                errorChecked = true;
1264                if (!inFunction()) {
1265                if (!hasBindingExp() && !checkType.allowExternalObjectMissingBindingExpression()) {
1266                    ASTNode.EXTERNAL_OBJECT_MISSING_BINDING_EXPRESSION.invoke(this, name());
1267                }
1268                        getDestructorCall().collectErrors(checkType);
1269                        myInstClass().collectErrors(checkType);
1270                }
1271            }
1272        }
1273
1274    public static final SimpleProblemProducer ASTNode.EXTERNAL_OBJECT_MISSING_BINDING_EXPRESSION =
1275            new SimpleErrorProducer("EXTERNAL_OBJECT_MISSING_BINDING_EXPRESSION", ProblemKind.SEMANTIC,
1276                    "The external object '%s' does not have a binding expression");
1277
1278        public void InstForClauseE.collectErrors(ErrorCheckType checkType) {
1279            collectErrorsInFor(getFAbstractEquationList(), getInstForIndexList(), checkType);
1280        }
1281       
1282        public void InstForStmt.collectErrors(ErrorCheckType checkType) {
1283            collectErrorsInFor(getForStmtList(), getInstForIndexList(), checkType);
1284        }
1285       
1286        public void FIterExp.collectErrors(ErrorCheckType checkType) {
1287            collectErrorsInFor(getFExp(), getForIndexList(), checkType);
1288        }
1289
1290    public void ASTNode.collectErrorsInFor(
1291            ASTNode iterChild, List<? extends CommonForIndex> indices, ErrorCheckType checkType) {
1292        // Do the checks on the for itself
1293        allChecks(checkType);
1294       
1295        // Check everything except iterChild once
1296        for (ASTNode ch : this)
1297            if (ch != iterChild)
1298                ch.collectErrors(checkType);
1299       
1300        // Check array bounds in iterChild for each index combination
1301        try {
1302            indices.getChild(0).collectErrorsForAllIndices(indices, 0, iterChild, checkType);
1303        } catch (ConstantEvaluationException e) {
1304            // Do "general" check if we are unable to determine the indices.
1305            // Will probably give incorrect errors. However this is better than
1306            // passing along errors and then crash!
1307            iterChild.collectErrors(checkType);
1308        }
1309    }
1310
1311    /**
1312     * Collect errors in iterated node for all combinations of for indices.
1313     *
1314     * @param indices    the list of indices too loop for
1315     * @param i          next index to handle
1316     * @param child      the iterated node to check
1317     * @param checkType  type of check to perform
1318     */
1319    public void CommonForIndex.collectErrorsForAllIndices(
1320            List<? extends CommonForIndex> indices, int i, ASTNode child, ErrorCheckType checkType) {
1321        throw new UnsupportedOperationException();
1322    }
1323
1324    @Override
1325    public void InstForIndex.collectErrorsForAllIndices(
1326        List<? extends CommonForIndex> indices, int i, ASTNode child, ErrorCheckType checkType) {
1327        InstComponentDecl var = getInstPrimitive();
1328        CValue oldVal = var.evaluationValue;
1329        boolean last = i == indices.getNumChild() - 1;
1330        CommonForIndex next = last ? null : indices.getChild(i + 1);
1331        CValueArray ivals = getFExp().ceval().array();
1332
1333        if (ivals.hasUnknowns()) {
1334            return;
1335        }
1336
1337        for (Index j : ivals.indices()) {
1338            var.setLocalCachedEvaluationValue(ivals.getCell(j));
1339            if (last) {
1340                child.resetCollectErrors();
1341                child.collectErrors(checkType);
1342                child.flushAllRecursive();
1343            } else {
1344                next.collectErrorsForAllIndices(indices, i + 1, child, checkType);
1345            }
1346        }
1347        var.setLocalCachedEvaluationValue(oldVal);
1348    }
1349
1350    @Override
1351    public void InstForIndexNoExp.collectErrorsForAllIndices(
1352            List<? extends CommonForIndex> indices, int i, ASTNode child, ErrorCheckType checkType) {
1353        if (hasFExp()) {
1354            super.collectErrorsForAllIndices(indices, i, child, checkType);
1355        }
1356    }
1357
1358
1359    public void InstFunctionCall.collectErrors(ErrorCheckType checkType) {
1360        if (!errorChecked) {
1361            errorChecked = true;
1362            // Check that the function exists
1363            InstLookupResult<InstCallable> lp = getName().myInstLookupCallable();
1364            InstCallable func = getName().myInstCallable();
1365            String name = getName().name();
1366            if (lp.isError()) {
1367                // Function does not exist or can't be used due to constraining classes, or name refers to component
1368                getName().generateClassLookupProblems(lp, this);
1369            } else if (!func.isCallable()) {
1370                if (func.isExternalObject()) {
1371                    // Something is be wrong with constructor
1372                    name += ".constructor";
1373                    func = func.asInstClassDecl().myConstructor();
1374                    if (func.isUnknown()) {
1375                        // The constructor does not exist
1376                        error("Cannot find function declaration for " + name + "()");
1377                    }
1378                    // Constructor exists, but is not a function - delegate to default case
1379                }
1380                if (!func.isUnknown()) {
1381                    // Not a function
1382                    error("The class " + name + " is not a function");
1383                }
1384            } else if (!func.isRecord() && !func.isCompleteFunction()) {
1385                // TODO: add check if function is partial?
1386                if (!checkType.allowIncompleteReplaceableFunc() || !canBeReplacedForMe(func.asInstNode()))
1387                    error("Calling function " + getName().name() + 
1388                            "(): can only call functions that have one algorithm section or external function specification");
1389            } else {
1390                // Function exists, check everything
1391                errorChecked = false; // super also uses errorChecked
1392                super.collectErrors(checkType);
1393               
1394                // We need to check the function definition as well.
1395                func.collectErrors(checkType);
1396               
1397                // Check if there were any unbindable args
1398                boolean pos = true;
1399                String desc = functionCallDecription();
1400                for (InstFunctionArgument arg : unbindableArgs) 
1401                    pos = arg.generateUnbindableError(desc, pos);
1402            }
1403        }
1404    }
1405   
1406    public static final SimpleProblemProducer ASTNode.NEGATIVE_SIZE_FILL =
1407        new SimpleErrorProducer("NEGATIVE_SIZE_FILL", ProblemKind.SEMANTIC, "The dimension arguments of the fill()"
1408                + " operator may not be negative");
1409   
1410    public void FFillExp.collectErrors(ErrorCheckType checkType) {
1411        super.collectErrors(checkType);
1412        if (!lockBranch(checkType)) {
1413            for (FExp exp : getFExps()) {
1414                if (exp.variability().knownParameterOrLess()) {
1415                    try {
1416                        CValue val = exp.ceval();
1417                            if (val.hasIntValue()) {
1418                            int d = val.intValue();
1419                            if (d < 0) {
1420                                NEGATIVE_SIZE_FILL.invoke(exp);
1421                            }
1422                        }
1423                    } catch (ConstantEvaluationException e) {}
1424                }
1425            }
1426        }
1427    }
1428   
1429    /**
1430     * Can <code>node</code> be replaced as seen from here?
1431     */
1432    inh boolean ASTNode.canBeReplacedForMe(InstNode node);
1433    eq InstNode.getChild().canBeReplacedForMe(InstNode node) = node.canBeReplacedFor(this);
1434    eq Root.getChild().canBeReplacedForMe(InstNode node)     = false;
1435
1436    /**
1437     * Is this node or any node before the closest common ancestor with <code>source</code> replaceable?
1438     */
1439    syn boolean InstNode.canBeReplacedFor(InstNode source)        = canBeReplacedIn(commonAncestor(source));
1440    eq InstSimpleShortClassDecl.canBeReplacedFor(InstNode source) = 
1441        super.canBeReplacedFor(source) || myTargetInstClassDecl().canBeReplacedFor(source);
1442    eq InstShortClassDecl.canBeReplacedFor(InstNode source)       = 
1443        super.canBeReplacedFor(source) || myTargetInstClassDecl().canBeReplacedFor(source);
1444
1445    /**
1446     * Is this class or any class before <code>ancestor</code> replaceable?
1447     */
1448    syn boolean InstNode.canBeReplacedIn(InstNode ancestor) = isReplaceable() || canBeReplacedInHelper(ancestor);
1449
1450    /**
1451     * Helper method for {@link #canBeReplacedIn(InstNode)} - use it instead.
1452     */
1453    inh boolean InstNode.canBeReplacedInHelper(InstNode ancestor);
1454    eq InstNode.getChild().canBeReplacedInHelper(InstNode ancestor) = (ancestor != this) && canBeReplacedIn(ancestor);
1455    eq Root.getChild().canBeReplacedInHelper(InstNode ancestor)     = false;
1456
1457        public void FInfArgsFunctionCall.collectErrors(ErrorCheckType checkType) {
1458                super.collectErrors(checkType);
1459                if (unbindableArgs != null) {
1460                    boolean pos = true;
1461                    String desc = functionCallDecription();
1462                    for (InstFunctionArgument arg : unbindableArgs) 
1463                        pos = arg.generateUnbindableError(desc, pos);
1464                }
1465        }
1466       
1467        syn String FAbstractFunctionCall.functionCallDecription() = "Calling function " + name() + "()";
1468        eq FRecordConstructor.functionCallDecription()    = "Record constructor for " + name();
1469    eq InstRecordConstructor.functionCallDecription() = "Record constructor for " + name();
1470        eq InstFunctionCall.functionCallDecription()      = getName().myInstClassDecl().isRecord() ? 
1471                        "Record constructor for " + name() : super.functionCallDecription();
1472    eq InstPartialFunctionCall.functionCallDecription() = "Creating functional input argument " + name() + "()";
1473         
1474        public boolean InstFunctionArgument.generateUnbindableError(String desc, boolean genForPos) {
1475                return genForPos;
1476        }
1477         
1478        public boolean InstPositionalArgument.generateUnbindableError(String desc, boolean genForPos) {
1479                if (genForPos)
1480                        error(desc + ": too many positional arguments");
1481                return false;
1482        }
1483         
1484        public boolean InstNamedArgument.generateUnbindableError(String desc, boolean genForPos) {
1485                error(desc + ": no input matching named argument " + getName().name() + " found");
1486                return genForPos;
1487        }
1488       
1489        public void FBuiltInFunctionCall.collectErrors(ErrorCheckType checkType) {
1490            if (!errorChecked) {
1491                super.collectErrors(checkType);
1492                errorChecked = true;
1493                getOriginalArgs().collectErrors(checkType);
1494            }
1495        }
1496       
1497        public void FUnsupportedBuiltIn.collectErrors(ErrorCheckType checkType) {
1498                // Don't check arguments
1499                allChecks(checkType);
1500        }
1501 
1502        public void InstNamedArgument.collectErrors(ErrorCheckType checkType) {
1503                // TODO: This way, the FExp for each argument to a built-in function is checked twice - fix that
1504            if (!errorChecked) {
1505                        allChecks(checkType);
1506                        getFExp().collectErrors(checkType);
1507            }
1508        }
1509
1510    /**
1511     * Check if this node is in a recursive structure.
1512     */
1513    syn boolean InstNode       .isRecursed() = false;
1514    eq InstComponentDecl       .isRecursed() = !isPrimitive() && isWithin(myInstClass());
1515    eq InstExtends             .isRecursed() = isWithin(myInstClass());
1516    eq InstSimpleShortClassDecl.isRecursed() = isWithin(actualInstClass());
1517    eq InstArrayComponentDecl  .isRecursed() = instComponentDecl().isRecursed();
1518
1519        // TODO: check if we realy need this in addition to isRecursed()
1520        /**
1521         * Check if extends tree is recursive.
1522         */
1523        public boolean InstExtends.isRecursive() {
1524                if (recursiveCache == RECURSIVE_UNKNOWN)
1525                        calcIsRecursive(new HashSet<InstNode>());
1526                return recursiveCache == RECURSIVE_YES;
1527        }
1528
1529    /**
1530     * Check if extends tree is recursive.
1531     */
1532    public boolean InstSimpleShortClassDecl.isRecursive() {
1533        if (recursiveCache == RECURSIVE_UNKNOWN)
1534            calcIsRecursive(new HashSet<InstNode>());
1535        return recursiveCache == RECURSIVE_YES;
1536    }
1537
1538    /**
1539     * Check if extends tree is recursive.
1540     */
1541    public boolean InstLibNode.isRecursive() {
1542        if (recursiveCache == RECURSIVE_UNKNOWN)
1543            calcIsRecursive(new HashSet<InstNode>());
1544        return recursiveCache == RECURSIVE_YES;
1545    }
1546
1547        /**
1548         * Examine extends tree to find recursive extends nodes.
1549         */
1550        public void InstExtends.calcIsRecursive(HashSet<InstNode> visited) {
1551                recursiveCache = visited.contains(this) ? RECURSIVE_YES : RECURSIVE_NO;
1552                visited.add(this);
1553                if (recursiveCache == RECURSIVE_NO) 
1554                        myInstClass().calcIsRecursive(visited);
1555        }
1556       
1557        /**
1558         * Examine extends tree to find recursive extends nodes.
1559         */
1560        public void InstClassDecl.calcIsRecursive(HashSet<InstNode> visited) {
1561                for (InstExtends ie : getInstExtendss())
1562                        ie.calcIsRecursive(visited);
1563        }
1564
1565    public void InstSimpleShortClassDecl.calcIsRecursive(HashSet<InstNode> visited) {
1566        recursiveCache = visited.contains(this) ? RECURSIVE_YES : RECURSIVE_NO;
1567        visited.add(this);
1568        if (recursiveCache == RECURSIVE_NO) 
1569            myTargetInstClassDecl().calcIsRecursive(visited);
1570        // Can't use actualInstClass() here, since it uses isRecursive()
1571    }
1572
1573    public void InstLibNode.calcIsRecursive(HashSet<InstNode> visited) {
1574        recursiveCache = visited.contains(this) ? RECURSIVE_YES : RECURSIVE_NO;
1575        visited.add(this);
1576        if (recursiveCache == RECURSIVE_NO) 
1577            resolveLib().calcIsRecursive(visited);
1578        // Can't use actualInstClass() here, since it uses isRecursive()
1579    }
1580
1581    private byte InstExtends.recursiveCache              = RECURSIVE_UNKNOWN;
1582    private byte InstSimpleShortClassDecl.recursiveCache = RECURSIVE_UNKNOWN;
1583    private byte InstLibNode.recursiveCache              = RECURSIVE_UNKNOWN;
1584    protected static final byte InstNode.RECURSIVE_UNKNOWN = 0;
1585    protected static final byte InstNode.RECURSIVE_YES     = 1;
1586    protected static final byte InstNode.RECURSIVE_NO      = 2;
1587
1588    /**
1589     * Check if <code>icd</code> is an ancestor of this node or any ancestor is an
1590     *        instance of <code>icd</code>.
1591     */
1592    inh boolean InstComponentDecl.isWithin(InstClassDecl icd);
1593    inh boolean InstExtends      .isWithin(InstClassDecl icd);
1594    inh boolean InstClassDecl    .isWithin(InstClassDecl icd);
1595    eq InstNode         .getChild().isWithin(InstClassDecl icd) = isOfInstClassDecl(icd);
1596    eq InstComponentDecl.getChild().isWithin(InstClassDecl icd) = isOfInstClassDecl(icd) || isWithin(icd);
1597    eq InstClassDecl    .getChild().isWithin(InstClassDecl icd) = icd == this || (!isFunction() && isWithin(icd));
1598    eq InstExtends      .getChild().isWithin(InstClassDecl icd) = isOfInstClassDecl(icd) || isWithin(icd);
1599    eq Root             .getChild().isWithin(InstClassDecl icd) = false;
1600
1601        /**
1602         * Check if this node is equal to or an instance of <code>icd</code>.
1603         */
1604        syn boolean InstNode.isOfInstClassDecl(InstClassDecl icd) = false;
1605        eq InstClassDecl.isOfInstClassDecl(InstClassDecl icd)     = icd == this;
1606        eq InstComponentDecl.isOfInstClassDecl(InstClassDecl icd) = icd == myInstClass() && !icd.isUnknown();
1607        eq InstExtends.isOfInstClassDecl(InstClassDecl icd)       = icd == myInstClass() && !icd.isUnknown();
1608       
1609}
1610
1611aspect AssertEval {
1612
1613    public class FClass {
1614        /**
1615         * Evaluate asserts with constant tests, generate errors for failing ones,
1616         * and eliminate all evaluated assets.
1617         */
1618        public class evaluateAsserts extends Transformation {
1619            public void perform() {
1620                List<FAbstractEquation> l = new List<FAbstractEquation>();
1621                for (FAbstractEquation eqn : getFAbstractEquations()) {
1622                    if (!eqn.evaluateAsserts(true)) {
1623                        l.add(eqn);
1624                    }
1625                }
1626                setFAbstractEquationList(l);
1627            }
1628        }
1629    }
1630   
1631    /**
1632     * Try to evaluate asserts with constant tests in this equation.
1633     *
1634     * If this equation should be removed, returns true.
1635     */
1636    public boolean FAbstractEquation.evaluateAsserts(boolean inClause) {
1637        return false;
1638    }
1639   
1640    @Override
1641    public boolean FFunctionCallEquation.evaluateAsserts(boolean inClause) {
1642        return getCall().evaluateAsserts(inClause);
1643    }
1644   
1645    @Override
1646    public boolean FIfWhenEquation.evaluateAsserts(boolean inClause) {
1647        boolean res = super.evaluateAsserts(inClause);
1648        if (hasElse())
1649            res = res && getElse().evaluateAsserts(inClause);
1650        return res;
1651    }
1652   
1653    @Override
1654    public boolean FIfWhenElseEquation.evaluateAsserts(boolean inClause) {
1655        boolean res = true;
1656        List<FAbstractEquation> l = new List<FAbstractEquation>();
1657        for (FAbstractEquation eqn : getFAbstractEquations()) {
1658            if (!eqn.evaluateAsserts(false)) {
1659                l.add(eqn);
1660                res = false;
1661            }
1662        }
1663        setFAbstractEquationList(l);
1664        return res;
1665    }
1666   
1667    /**
1668     * If this call is an assert with constant test, try to evaluate it.
1669     *
1670     * @return  <code>true</code> if this is an assert that should be removed
1671     */
1672    public boolean FAbstractFunctionCall.evaluateAsserts(boolean error) {
1673        return false;
1674    }
1675   
1676    private static final String FAssert.LEVEL_ERROR = "error";
1677   
1678    public boolean FAssert.evaluateAsserts(boolean error) {
1679        boolean remove = false;
1680        if (getTest().isConstantExp()) {
1681            try {
1682                CValue cVal = getTest().ceval();
1683                if (cVal.hasBooleanValue()) {
1684                    boolean val = cVal.booleanValue();
1685                    if (error && !val) {
1686                        CValue cMsg = getMsg().ceval();
1687                        CValue cLevel = hasLevel() ? getLevel().ceval() : null;
1688                        if (cMsg.hasStringValue() && (cLevel == null || cLevel.hasStringValue())) {
1689                            String msg = "Assertion failed: " + cMsg.stringValue();
1690                            if (cLevel == null || cLevel.stringValue().equals(LEVEL_ERROR)) {
1691                                error(msg);
1692                            } else {
1693                                warning(msg);
1694                            }
1695                        }
1696                    }
1697                    remove = val || error;
1698                }
1699            } catch (ConstantEvaluationException e) {}
1700        }
1701        return remove;
1702    }
1703   
1704}
1705
1706aspect ScalarizationErrorCheck {
1707   
1708    /**
1709     * Check errors that can only be detected after scalarization.
1710     */
1711    public void FClass.scalarizationErrorCheck() {
1712        checkMultipleReinit();
1713        breakOnErrors();
1714    }
1715   
1716    /**
1717     * Check for variables with multiple reinits.
1718     */
1719    public void FClass.checkMultipleReinit() {
1720        Map<FAbstractVariable, Set<FReinit>> reinitMap = collectReinits();
1721        for (FAbstractVariable fv : reinitMap.keySet()) {
1722            if (!fv.isUnknown()) {
1723                Set<FWhenEquation> whens = new HashSet<FWhenEquation>();
1724                Set<FReinit> reinits = reinitMap.get(fv);
1725                for (FReinit r : reinits) {
1726                    FWhenEquation w = r.myWhen();
1727                    if (!whens.contains(w))
1728                        whens.add(w);
1729                }
1730                if (whens.size() > 1) {
1731                    StringBuilder buf = new StringBuilder();
1732                    buf.append("The variable ");
1733                    buf.append(fv.name());
1734                    buf.append(" is assigned in reinit() clauses in more than one when clause:\n");
1735                    for (FReinit r : reinits) {
1736                        buf.append("    ");
1737                        buf.append(r);
1738                        buf.append(";\n");
1739                    }
1740                    fv.error(buf.toString());
1741                }
1742            }
1743        }
1744    }
1745   
1746    /**
1747     * Find all reinits and map them to the assigned variable.
1748     */
1749    syn boolean FVariable.isReinit() = myFClass().collectReinits().keySet().contains(this);
1750   
1751    syn lazy Map<FAbstractVariable,Set<FReinit>> FClass.collectReinits() {
1752        Map<FAbstractVariable,Set<FReinit>> reinitMap = new HashMap<FAbstractVariable,Set<FReinit>>();
1753        for (FAbstractEquation e : getFAbstractEquations())
1754            e.collectReinits(reinitMap);
1755        return reinitMap;
1756    }
1757   
1758    public void FAbstractEquation.collectReinits(Map<FAbstractVariable,Set<FReinit>> map) {}
1759   
1760    public void FIfWhenEquation.collectReinits(Map<FAbstractVariable,Set<FReinit>> map) {
1761        if (isWhen()) {
1762                super.collectReinits(map);
1763                if (hasElse())
1764                    getElse().collectReinits(map);
1765        }
1766    }
1767   
1768    public void FIfWhenElseEquation.collectReinits(Map<FAbstractVariable,Set<FReinit>> map) {
1769        for (FAbstractEquation e : getFAbstractEquations())
1770            e.collectReinits(map);
1771    }
1772   
1773    public void FFunctionCallEquation.collectReinits(Map<FAbstractVariable,Set<FReinit>> map) {
1774        getCall().collectReinits(map);
1775    }
1776   
1777    public void FExp.collectReinits(Map<FAbstractVariable,Set<FReinit>> map) {}
1778   
1779    public void FReinit.collectReinits(Map<FAbstractVariable,Set<FReinit>> map) {
1780        Set<FReinit> set = map.get(myFV());
1781        if (set == null) {
1782            set = new LinkedHashSet<FReinit>();
1783            map.put(myFV(), set);
1784        }
1785        set.add(this);
1786    }
1787   
1788    /**
1789     * Get the when-equation that this reinit() belongs to.
1790     *
1791     * Gets the top when in a when-elsewhen-else.
1792     * Not valid after when-equations have been converted to if-equations.
1793     */
1794    inh FWhenEquation FReinit.myWhen();
1795    eq FWhenEquation.getChild().myWhen() = findTopWhen(this);
1796    eq FClass.getChild().myWhen()        = null;
1797    eq InstNode.getChild().myWhen()      = null;
1798   
1799    /**
1800     * Find the top when-equation in a when-elsewhen-else equation.
1801     *
1802     * @param last  will be returned if parent is not a when equation
1803     */
1804    inh FWhenEquation FWhenEquation.findTopWhen(FWhenEquation last);
1805    eq FWhenEquation.getChild().findTopWhen(FWhenEquation last) = findTopWhen(this);
1806    eq FClass.getChild().findTopWhen(FWhenEquation last)        = last;
1807    eq InstNode.getChild().findTopWhen(FWhenEquation last)      = last;
1808   
1809}
Note: See TracBrowser for help on using the repository browser.