source: branches/dev-mj-1626/Compiler/ModelicaFlatTree/src/jastadd/ConstantEvaluation/ConstantEvaluation.jrag @ 13095

Last change on this file since 13095 was 13095, checked in by tgutzmann, 5 months ago

Merge from trunk

File size: 185.9 KB
Line 
1/*
2    Copyright (C) 2009-2017 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.ArrayList;
18import java.util.Collections;
19import java.util.HashMap;
20import java.util.Iterator;
21import java.util.Locale;
22import java.util.Map;
23import java.util.Set;
24
25import org.jmodelica.util.BinaryOperation;
26import org.jmodelica.util.StringUtil;
27import org.jmodelica.util.collections.ConstArrayIterator;
28import org.jmodelica.util.collections.SingleIterator;
29import org.jmodelica.util.values.ConstValue;
30import org.jmodelica.util.values.Evaluable;
31import org.jmodelica.util.values.ConstantEvaluationException;
32import org.jmodelica.util.values.ConstantEvaluationNotReadyException;
33import org.jmodelica.util.values.FunctionEvaluationException;
34
35
36/**
37 * Provides methods to evaluate flat constant
38 * expressions.
39 *
40 * Evaluation of constants and parameters is needed in several locations in the
41 * compiler.
42 *
43 *  - Array sizes need to be evaluated during flattening and type checking.
44 *  - Expressions need to be evaluated in function calls.
45 *  - Attribute values for primitive variables need to be evaluated in the code
46 *    generation.
47 *
48 * The evaluation framework relies on the class CValue, which in turn is
49 * subclassed to CValueReal, CValueInteger, etc. Introducing explicit classes
50 * corresponding to constant values enables convenient type casts and also
51 * provides means to represent more complex types such as arrays. 
52 *
53 */
54aspect ConstantEvaluation {
55
56        /**
57         * CValue represents a constant value and serves as the super class
58         * for constant value classes of the primitive types.
59         */
60        public abstract class CValue extends ConstValue implements Iterable<CValue>, Cloneable {
61               
62                /**
63                 * An unknown value.
64                 */
65                public static final CValue UNKNOWN = new CValueUnknown();
66               
67                /**
68                 * An unknown value for an expression that constant evaluation
69                 *        isn't supported for.
70                 */
71                public static final CValue UNSUPPORTED = new CValueUnsupported();
72
73                /**
74                 * Default constructor.
75                 */
76            protected CValue() {
77            }
78
79        /**
80         * Copy this constant value.
81         */
82        public CValue clone() {
83            try {
84                return (CValue) super.clone();
85            } catch (CloneNotSupportedException e) {
86                throw new UnsupportedOperationException();
87            }
88        }
89
90        /**
91         * Create a literal AST node from constant, for use in flat tree.
92         *
93         * @return  literal expression AST node
94         */
95        public FExp buildLiteral() { 
96            throw new ConstantEvaluationException(this, "create literal expression from "); 
97        }
98
99        /**
100         * Create a literal AST node from constant, for use in instance tree.
101         *
102         * @return  literal expression AST node
103         */
104        public FExp buildInstLiteral() { 
105            return buildLiteral(); 
106        }
107
108        /**
109         * Constrain value to be between min and max, inclusively
110         */
111        public CValue constrainWithin(CValue min, CValue max) {
112            throw new ConstantEvaluationException(this, "do relational comparison on "); 
113        }
114
115        /**
116         * Convert to CValueInteger, default implementation.
117         */
118        public CValue convertInteger() {
119            return new CValueInteger(intValue());
120        }
121
122        /**
123         * Convert to CValueReal, default implementation.
124         */
125        public CValue convertReal() {
126            return new CValueReal(realValue());
127        }
128
129        /**
130         * Convert to CValueBoolean, default implementation.
131         */
132        public CValue convertBoolean() {
133            return new CValueBoolean(booleanValue());
134        }
135
136        /**
137         * Convert to CValueString, default implementation.
138         */
139        public CValue convertString() {
140            return new CValueString(stringValue());
141        }
142
143        /**
144         * Is {@link #convertInteger()} expected to succeed?
145         */
146        public boolean hasConvertInteger() {
147            return hasIntValue();
148        }
149
150        /**
151         * Is {@link #convertReal()} expected to succeed?
152         */
153        public boolean hasConvertReal() {
154            return hasRealValue();
155        }
156
157        /**
158         * Is {@link #convertBoolean()} expected to succeed?
159         */
160        public boolean hasConvertBoolean() {
161            return hasBooleanValue();
162        }
163
164        /**
165         * Is {@link #convertString()} expected to succeed?
166         */
167        public boolean hasConvertString() {
168            return hasStringValue();
169        }
170
171        /**
172         * Is {@link #buildLiteral()} expected to succeed?
173         */
174        public boolean hasBuildLiteral() {
175            return false;
176        }
177
178        public String stringExpValue() {
179            return stringValue();
180        }
181
182        /**
183         * Convenience method for accessing an array CValue as CValueArray.
184         *
185         * Only valid for arrays.
186         */
187        public CValueArray array() {
188                throw new ConstantEvaluationException(this, "use this as array: ");
189        }
190       
191        public CValue getCell(Index i) {
192            return UNKNOWN;
193        }
194       
195        public CValueUnknownUse unknownUse() {
196            throw new ConstantEvaluationException(this, "use this as unknown value use: ");
197        }
198       
199        /**
200         * Expand this CValue so that it represents an array of the given size,
201         * duplicating values as needed.
202         */
203        public CValue expandArray(Size s) {
204                if (s == Size.SCALAR)
205                        return this;
206                CValueArray res = new CValueArray(s);
207                while (!res.isFilled())
208                        res.addCell(this);
209                return res;
210        }
211           
212        /**
213         * Convenience method for accessing a record CValue as CValueRecord.
214         *
215         * Only valid for records.
216         */
217        public CValueRecord record() {
218                throw new ConstantEvaluationException(this, "use this as record: ");
219        }
220       
221        /**
222         * Reduce an array to a single value.
223         *
224         * For a scalar, returns itself. For an empty array, returns zero.
225         *
226         * @param op    the operation to use to combine two values
227         * @param zero  the start value
228         */
229        public CValue reduce(BinaryOperation<CValue> op, CValue zero) {
230                return this;
231        }
232       
233        /**
234         * Reduce an array of constant boolean values to a single boolean that is the logical
235         * or of the array.
236         *
237         * Used for the test expression of while statements. For scalar constant values,
238         * just returns the boolean value.
239         */
240        public boolean reduceBooleanOr() {
241                return reduce(OR_OPERATION, CValueBoolean.FALSE).booleanValue();
242        }
243       
244        private static final BinaryOperation<CValue> OR_OPERATION = new BinaryOperation<CValue>() {
245                public CValue op(CValue x, CValue y) {
246                        return (x.booleanValue() || y.booleanValue()) ? CValueBoolean.TRUE : CValueBoolean.FALSE;
247                }
248        };
249               
250        /**
251         * Reduce an array of constant boolean values to a single boolean that is the logical
252         * and of the array.
253         *
254         * Used for evaluation of fixed=false parameters when evalute=true.
255         */
256        public boolean reduceBooleanAnd() {
257            return reduce(AND_OPERATION, CValueBoolean.TRUE).booleanValue();
258        }
259       
260        private static final BinaryOperation<CValue> AND_OPERATION = new BinaryOperation<CValue>() {
261            public CValue op(CValue x, CValue y) {
262                return (x.booleanValue() && y.booleanValue()) ? CValueBoolean.TRUE : CValueBoolean.FALSE;
263            }
264        };
265       
266                /**
267                 * Returns the array size of this constant value.
268                 */
269                public Size size() {
270                        return Size.SCALAR;
271                }
272               
273                /**
274                 * Iterates over all array cells in CValue.
275                 *
276                 * A scalar CValue is considered to have a single array cell.
277                 */
278                public Iterator<CValue> iterator() {
279                        return new SingleIterator<CValue>(this);
280                }
281       
282        /**
283         * Evaluate this as a function call. Throws exception if not a partial function.
284         */
285        public void evaluateFunction(VariableEvaluator evaluator, CommonCallable partial, Map<CommonVariableDecl, CValue> values) {
286            throw new ConstantEvaluationException(this, "use this as a partial function: ");
287        }
288       
289        /**
290         * Evaluate this as a partial function call. Throws exception if not a partial function.
291         */
292        public CValue evaluatePartialFunction(CommonCallable partial, Map<CommonVariableDecl, CValue> values) {
293            throw new ConstantEvaluationException(this, "use this as a partial function: ");
294        }
295    }
296   
297    /**
298     * Constant integer value.
299     */
300    public class CValueInteger extends CValue {
301        private int value;
302       
303        /**
304         * Constructor.
305         *
306             * @param i Integer value.
307         */
308        public CValueInteger(int i) { 
309                this.value = i; 
310        }
311
312        /**
313         * Convert to int.
314         *
315         * @return Value converted to int.
316         */
317        public int intValue() {
318                return value;
319        }
320
321        /**
322         * Convert to Object, boxes value as an Integer.
323         *
324         * @return Value as an Integer.
325         */
326        @Override
327        public Integer objectValue() { 
328            return value;
329        }
330
331        /**
332         * Convert to double.
333         *
334         *  @return Value converted to double.
335         */
336        public double realValue() { 
337                return value; 
338        }
339
340        @Override
341        public double minValue() {
342            return value;
343        }
344
345        @Override
346        public double maxValue() {
347            return value;
348        }
349
350        public CValue constrainWithin(CValue min, CValue max) {
351            if (!min.isUnknown() && min.intValue() > value)
352                return min;
353            if (!max.isUnknown() && max.intValue() < value)
354                return max;
355            return this;
356        }
357
358        /**
359         * Convert to CValueInteger.
360         */
361        public CValue convertInteger() {
362            return this;
363        }
364
365        /**
366         * Convert to string.
367         *
368         * @return Value converted to string.
369         */
370        public String stringValue() { 
371            return Integer.toString(value); 
372        }
373
374        /**
375         * Create a new integer literal AST node.
376         *
377         * @return AST node of type FLitExp.
378         */
379        public FLitExp buildLiteral() { 
380                return new FIntegerLitExp(value); 
381        }
382
383        @Override
384        public boolean hasBuildLiteral() {
385            return true;
386        }
387
388        @Override
389        public boolean isInteger() {
390            return true;
391        }
392       
393        @Override
394        public boolean isReal() {
395            return true;
396        }
397
398        @Override
399        public boolean isNumeric() {
400            return true;
401        }
402
403        @Override
404        public boolean isNegative() {
405            return value < 0;
406        }
407
408        @Override
409        public boolean hasIntValue() {
410            return true;
411        }
412
413        @Override
414        public boolean hasRealValue() {
415            return true;
416        }
417
418        @Override
419        public boolean hasStringValue() {
420            return true;
421        }
422    }
423   
424        /**
425         * Constant real value.
426         */     
427    public class CValueReal extends CValue {
428        private double value;
429       
430        /**
431         * Constructor.
432         *
433         * @param d Double value.
434         */
435        public CValueReal(double d) { 
436                this.value = d; 
437        }
438
439        /**
440             * Convert to int.
441             *
442             * @return Value converted to int.
443             */
444        public int intValue() { 
445                // Round towards negative infinity to be compatible with integer() operator
446                return (int) StrictMath.floor(value); 
447        }
448       
449        /**
450             * Convert to double.
451             *
452             * @return Value converted to double.
453             */
454        public double realValue() { 
455                return value; 
456        }
457
458        /**
459         * Convert to Object, boxes value as a Double.
460         *
461         * @return Value as an Double.
462         */
463        @Override
464        public Double objectValue() { 
465            return value;
466        }
467
468        @Override
469        public double minValue() {
470            return value;
471        }
472
473        @Override
474        public double maxValue() {
475            return value;
476        }
477
478        public CValue constrainWithin(CValue min, CValue max) {
479            if (!min.isUnknown() && min.realValue() > value)
480                return min;
481            if (!max.isUnknown() && max.realValue() < value)
482                return max;
483            return this;
484        }
485
486        /**
487         * Convert to CValueReal.
488         */
489        public CValue convertReal() {
490            return this;
491        }
492
493        /**
494         * Convert to string.
495         *
496         * @return Value converted to string.
497         */
498        public String stringValue() { 
499            return Double.toString(value);
500        }
501
502        /**
503         * Create a new literal expression AST node.
504         *
505         * @return FRealLitExp AST node.
506         */
507        public FLitExp buildLiteral() { 
508                return new FRealLitExp(value); 
509        }
510
511        @Override
512        public boolean hasBuildLiteral() {
513            return true;
514        }
515
516        @Override
517        public boolean isReal() {
518            return true;
519        }
520
521        @Override
522        public boolean isNumeric() {
523            return true;
524        }
525
526        @Override
527        public boolean isNegative() {
528            return value < 0;
529        }
530
531        @Override
532        public boolean isValid() {
533            return !(Double.isInfinite(value) || Double.isNaN(value));
534        }
535
536        @Override
537        public boolean hasIntValue() {
538            return true;
539        }
540
541        @Override
542        public boolean hasRealValue() {
543            return true;
544        }
545
546        @Override
547        public boolean hasStringValue() {
548            return true;
549        }
550    }
551   
552        /**
553         * Constant boolean value.
554         */
555    public class CValueBoolean extends CValue {
556        /** A CValueBolean with the value <code>false</code>, for conveniance. */
557        public static final CValueBoolean FALSE = new CValueBoolean(false);
558
559        /** A CValueBolean with the value <code>true</code>, for conveniance. */
560        public static final CValueBoolean TRUE  = new CValueBoolean(true);
561       
562        private boolean value;
563
564        /**
565         * Constructor.
566         *
567         * @param b Boolean value.
568         */
569        public CValueBoolean(boolean b) { 
570                this.value = b; 
571        }
572
573        /**
574             * Convert to boolean.
575             *
576             * @return Value converted to boolean.
577             */
578        public boolean booleanValue() { 
579                return value; 
580        }
581
582        /**
583         * Convert to Object, boxes value as an Boolean.
584         *
585         * @return Value as an Boolean.
586         */
587        @Override
588        public Boolean objectValue() { 
589            return value;
590        }
591       
592        /**
593         * Convert to int.
594         *
595         * Used for array index and comparisons.
596             *
597             * @return Value converted to int.
598         */
599        public int intValue() {
600                return value ? 2 : 1;
601        }
602           
603            /**
604             * Convert to CValueBoolean.
605             */
606            public CValue convertBoolean() {
607                return this;
608            }
609       
610        /**
611             * Convert to string.
612             *
613             * @return Value converted to string.
614             */
615        public String stringValue() { 
616                return Boolean.toString(value); 
617        }
618
619        /**
620         * Create a new literal expression AST node.
621         *
622         * @return FBooleanLitExp AST node.
623         */
624        public FLitExp buildLiteral() { 
625            return FBooleanLitExp.create(value); 
626        }
627
628        @Override
629        public boolean hasBuildLiteral() {
630            return true;
631        }
632
633        @Override
634        public boolean isBoolean() {
635            return true;
636        }
637
638        @Override
639        public boolean hasIntValue() {
640            return true;
641        }
642
643        @Override
644        public boolean hasBooleanValue() {
645            return true;
646        }
647
648        @Override
649        public boolean hasStringValue() {
650            return true;
651        }
652    }
653
654        /**
655         * Constant string value.
656         */
657    public class CValueString extends CValue {
658        private String value;
659       
660        /**
661         * Constructor.
662         *
663         * @param s String value.
664         */       
665        public CValueString(String s) { this.value = s; }
666       
667        /**
668             * Convert to string.
669             *
670             * @return Value converted to string.
671             */       
672        public String stringValue() { return value; }
673
674        /**
675         * Convert to Object, just returns the value.
676         *
677         * @return Value as an String.
678         */
679        @Override
680        public String objectValue() { 
681            return value;
682        }
683           
684            /**
685             * Convert to CValueString.
686             */
687            public CValue convertString() {
688                return this;
689            }
690
691        /**
692         * Create a new literal expression AST node.
693         *
694         * @return FStringLitExp AST node.
695         */
696        public FLitExp buildLiteral() { 
697            return new FStringLitExp(ASTNode.escape(value)); 
698        }
699
700        @Override
701        public boolean hasBuildLiteral() {
702            return true;
703        }
704
705            public String toString() {
706                return '"' + value + '"';
707            }
708
709        @Override
710        public boolean isString() {
711            return true;
712        }
713
714        @Override
715        public boolean hasStringValue() {
716            return true;
717        }
718      }
719   
720        /**
721         * Constant unknown value. This class is used to represent
722         * non-constant values and values resulting from expressions with
723         * type errors.
724         */
725    public class CValueUnknown extends CValue {
726       
727        /**
728         * Convert to string.
729         *
730         * @return The string.
731         */
732        public String toString() { 
733            return "(unknown value)"; 
734        }
735
736        public boolean isUnknown() {
737            return true;
738        }
739
740        public boolean isValid() {
741            return false;
742        }
743       
744        @Override
745        public CValue clone() {
746            return this;
747        }
748       
749        /**
750         * Get a string describing this CValue for use in
751         *        ConstantEvaluationExceptions.
752         */
753        public String errorDesc() {
754            return getClass().getSimpleName();
755        }
756
757    }
758   
759    /**
760     * Unknown value. Keeps track of CommonAccessExps that this value is
761     * dependent on. Used when calculating incidences in function
762     * call equations.
763     */
764    public class CValueUnknownUse extends CValueUnknown {
765        Set<FAccessExp> deps;
766       
767        public CValueUnknownUse(Set<FAccessExp> deps) {
768            this.deps = deps;
769        }
770       
771        public CValueUnknownUse() {
772            this(new HashSet<FAccessExp>());
773        }
774       
775        public CValueUnknownUse(FAccessExp dep) {
776            this();
777            deps.add(dep);
778        }
779       
780        public CValueUnknownUse unknownUse() {
781            return this;
782        }
783       
784        public String toString() {
785            StringBuilder sb = new StringBuilder();
786            sb.append("(unknown value : \"");
787            for (CommonAccessExp dep : deps) {
788                sb.append(dep.name());
789                sb.append(", ");
790            }
791            sb.append("\")");
792            return sb.toString();
793        }
794       
795        public Set<FAccessExp> getDependencies() {
796            return deps;
797        }
798    }
799   
800    /**
801     * Unknown value. This class is used when an access cannot be evaluated.
802     */
803    public class CValueUnknownAccess extends CValueUnknown {
804        private String access;
805       
806        public CValueUnknownAccess(String access) {
807            this.access = access;
808        }
809       
810        @Override
811        public boolean isUnknownAccess() {
812            return true;
813        }
814       
815        @Override
816        public String access() {
817            return access;
818        }
819    }
820   
821    /**
822     * Constant unknown value generated by an expression that
823     *        constant evaluation isn't supported for. 
824     */
825    public class CValueUnsupported extends CValueUnknown {
826        public boolean isUnsupported() {
827                return true;
828        }
829    }
830   
831    /**
832     * Constant value for array.
833     *
834     * Note that this class is mutable, care must be taken not to modify
835     * arrays that have already been returned. The only place where that
836     * should be done is during function evaluation, where CValues are used
837     * to represent mutable variable values.
838     */
839    public class CValueArray extends CValue {
840       
841        /* TODO: If/when caching is introduced for ceval(), add lazy evaluation by
842         *       keeping a reference to the producing FExp and adding a method to FExp
843         *       that fills in a specific cell. This method can then be overridden as
844         *       constant eval support for arrays is added to specific expression types.
845         */ 
846       
847                protected Indices  indices;
848                protected CValue[] values;
849                private int add = 0;
850       
851                /**
852                 * Create a CValueArray of size <code>s</code>.
853                 *
854                 * The array is initially filled with unknown values.
855                 * Individual values must be set with setCell().
856                 */
857        public CValueArray(Size s) {
858            s = s.evaluated();
859                indices = Indices.create(s);
860                        values = new CValue[indices.numElements()];
861                        for (int i = 0; i < values.length; i++)
862                                values[i] = UNKNOWN;
863        }
864           
865            public CValue clone() {
866                CValueArray res = (CValueArray) super.clone();
867                res.values = new CValue[values.length];
868                for (int i = 0; i < values.length; i++) 
869                                res.values[i] = values[i].clone();
870                return res;
871            }
872
873        public boolean isArray() {
874            return true;
875        }
876
877        @Override
878        public int ndims() {
879            return indices.ndims();
880        }
881
882        /**
883         * Check if there was an error in any part of the evaluation.
884         *
885         * @return true if there was an error, otherwise false.
886         */
887        public boolean isPartlyUnknown() {
888            for (CValue cvalue : values)
889                if (cvalue.isPartlyUnknown())
890                    return true;
891            return false;
892        }
893
894        public CValue constrainWithin(CValue min, CValue max) {
895            CValueArray res = new CValueArray(size());
896            for (int i = 0; i < values.length; i++) {
897                CValue cellMin = min.isArray() ? min.array().getCell(i) : min;
898                CValue cellMax = max.isArray() ? max.array().getCell(i) : max;
899                res.values[i] = values[i].constrainWithin(cellMin, cellMax);
900            }
901            return res;
902        }
903
904        @Override
905        public boolean isReal() {
906            boolean res = true;
907            for (CValue cvalue : values)
908                res &= cvalue.isReal();
909            return res;
910        }
911
912        @Override
913        public boolean isInteger() {
914            boolean res = true;
915            for (CValue cvalue : values)
916                res &= cvalue.isInteger();
917            return res;
918        }
919
920        @Override
921        public boolean isString() {
922            boolean res = true;
923            for (CValue cvalue : values)
924                res &= cvalue.isString();
925            return res;
926        }
927
928        @Override
929        public boolean isBoolean() {
930            boolean res = true;
931            for (CValue cvalue : values)
932                res &= cvalue.isBoolean();
933            return res;
934        }
935
936        @Override
937        public boolean isEnum() {
938            boolean res = true;
939            for (CValue cvalue : values)
940                res &= cvalue.isEnum();
941            return res;
942        }
943
944        @Override
945        public boolean isValid() {
946            boolean res = true;
947            for (CValue cvalue : values)
948                res &= cvalue.isValid();
949            return res;
950        }
951
952        @Override
953        public boolean isUnknownAccess() {
954            boolean res = true;
955            for (CValue cvalue : values)
956                res &= cvalue.isUnknownAccess();
957            return res;
958        }
959
960        @Override
961        public int[] intVector() {
962            int[] vector = new int[values.length];
963            for (int i = 0; i < values.length; i++)
964                vector[i] = values[i].intValue();
965            return vector;
966        }
967
968        @Override
969        public double[] realVector() {
970            double[] vector = new double[values.length];
971            for (int i = 0; i < values.length; i++)
972                vector[i] = values[i].realValue();
973            return vector;
974        }
975
976        @Override
977        public double[][] realMatrix() { 
978            if (size().ndims() != 2) {
979                double[][] matrix = new double[values.length][];
980                for (int i = 0; i < values.length; i++) {
981                    matrix[i] = values[i].realVector();
982                }
983                return matrix;
984            }
985            int n = size().get(0);
986            int m = size().get(1);
987            double[][] matrix = new double[n][m];
988            for (Index i : indices()) {
989                matrix[i.get(0)-1][i.get(1)-1] = getCell(i).realValue();
990            }
991            return matrix;
992        }
993
994        @Override
995        public String[] stringVector() { 
996            String[] vector = new String[values.length];
997            for (int i = 0; i < values.length; i++)
998                vector[i] = values[i].stringValue();
999            return vector;
1000        }
1001
1002        @Override
1003        public String[] accessVector() { 
1004            String[] vector = new String[values.length];
1005            for (int i = 0; i < values.length; i++)
1006                vector[i] = values[i].access();
1007            return vector;
1008        }
1009
1010        /**
1011         * Convert to Object, Returns an Object array.
1012         *
1013         * @return Value as Object[].
1014         */
1015        @Override
1016        public Object[] objectValue() { 
1017            return objectValue(0, 0);
1018        }
1019       
1020        private Object[] objectValue(int dim, int pos) {
1021            int n = size().get(dim);
1022            dim++;
1023            Object[] res = new Object[n];
1024            if (dim == ndims()) {
1025                for (int i = 0; i < n; i++) {
1026                    res[i] = values[pos + i].objectValue();
1027                }
1028            } else {
1029                int m = size().numElements(dim);
1030                for (int i = 0; i < n; i++) {
1031                    res[i] = objectValue(dim, pos + m * i);
1032                }
1033            }
1034            return res;
1035        }
1036
1037        @Override
1038        public double minValue() {
1039            double min = Double.MAX_VALUE;
1040            for (CValue value : values)
1041                min = Math.min(value.minValue(), min);
1042            return min;
1043        }
1044
1045        @Override
1046        public double maxValue() {
1047            double max = Double.MIN_VALUE;
1048            for (CValue value : values)
1049                max = Math.max(value.minValue(), max);
1050            return max;
1051        }
1052
1053        /**
1054         * Convenience method for accessing an array CValue as CValueArray.
1055         *
1056         * Only valid for arrays.
1057         */
1058        public CValueArray array() {
1059                return this;
1060        }     
1061       
1062        /**
1063         * Expand this CValue so that it represents an array of the given size,
1064         * duplicating values as needed.
1065         */
1066        public CValue expandArray(Size s) {
1067                if (s.ndims() == indices.ndims())
1068                        return this;
1069                if (s.ndims() < indices.ndims())
1070                        throw new ConstantEvaluationException(this, "contract array to size " + s + ": "); 
1071               
1072                CValueArray res = new CValueArray(s);
1073                while (!res.isFilled())
1074                        for (CValue v : values)
1075                                res.addCell(v);
1076                return res;
1077        }
1078           
1079        /**
1080         * Set the value of a specific cell of an array constant value.
1081         */
1082        public void setCell(Index i, CValue val) {
1083                values[i.internal(indices)] = val;
1084        }
1085       
1086       /**
1087         * Is this array is sufficiently large to to represent the given index.
1088         */
1089        public boolean hasCell(Index i) {
1090            return indices.isValid(i);
1091        }
1092       
1093        /**
1094         * Set the value of the next free cell of an array constant value.
1095         *
1096         * "Free" here means the cell after the last one set by addCell(), or the
1097         * first cell if this is the first call.
1098         */
1099        public void addCell(CValue val) {
1100                values[add++] = val;
1101        }
1102       
1103        /**
1104         * Returns <code>false</code> until {@link #addCell(CValue)} has been called
1105         * once for each cell.
1106         */
1107        public boolean isFilled() {
1108                return add >= values.length;
1109        }
1110       
1111        /**
1112         * Get the value of a specific cell of an array constant value.
1113         */
1114        public CValue getCell(Index i) {
1115                if (!hasCell(i))
1116                        return UNKNOWN;
1117                return values[i.internal(indices)];
1118        }
1119
1120        /**
1121         * Get the value of a specific cell of an array constant value.
1122         */
1123        public CValue getCell(int i) {
1124            if (i < 0 || i >= values.length)
1125                return UNKNOWN;
1126            return values[i];
1127        }
1128
1129        /**
1130         * Get the part of this array corresponding to the given index.
1131         */
1132        public CValue getPart(Index i) {
1133                if (i == Index.NULL)
1134                        return this;
1135                if (indices.ndims() == i.ndims())
1136                        return getCell(i);
1137               
1138                CValueArray res = new CValueArray(size().contract(i.ndims(), 0));
1139                System.arraycopy(values, indices.internal(i), res.values, 0, res.values.length);
1140                return res;
1141        }
1142       
1143        /**
1144         * Reduce an array to a single value.
1145         *
1146         * For a scalar, returns itself. For an empty array, returns zero.
1147         *
1148         * @param op    the operation to use to combine two values
1149         * @param zero  the start value
1150         */
1151        public CValue reduce(BinaryOperation<CValue> op, CValue zero) {
1152                for (CValue val : values)
1153                        zero = op.op(zero, val);
1154                return zero;
1155        }
1156               
1157                /**
1158                 * Returns the Indices associated with this constant array.
1159                 */
1160                public Indices indices() {
1161                        return indices;
1162                }
1163               
1164                /**
1165                 * Returns the array size of this constant value.
1166                 */
1167                public Size size() {
1168                        return indices.size();
1169                }
1170           
1171            /**
1172             * Convert each cell to CValueInteger.
1173             */
1174            public CValue convertInteger() {
1175                CValueArray res = new CValueArray(indices.size());
1176                for (int i = 0; i < values.length; i++)
1177                        res.values[i] = values[i].convertInteger();
1178                return res;
1179            }
1180           
1181            /**
1182             * Convert each cell to CValueReal.
1183             */
1184            public CValue convertReal() {
1185                CValueArray res = new CValueArray(indices.size());
1186                for (int i = 0; i < values.length; i++)
1187                        res.values[i] = values[i].convertReal();
1188                return res;
1189            }
1190           
1191            /**
1192             * Convert each cell to CValueBoolean.
1193             */
1194            public CValue convertBoolean() {
1195                CValueArray res = new CValueArray(indices.size());
1196                for (int i = 0; i < values.length; i++)
1197                        res.values[i] = values[i].convertBoolean();
1198                return res;
1199            }
1200           
1201            /**
1202             * Convert each cell to CValueString.
1203             */
1204            public CValue convertString() {
1205                CValueArray res = new CValueArray(indices.size());
1206                for (int i = 0; i < values.length; i++)
1207                        res.values[i] = values[i].convertString();
1208                return res;
1209            }
1210
1211        /**
1212         * Is {@link #convertInteger()} expected to succeed?
1213         */
1214        public boolean hasConvertInteger() {
1215            for (CValue val : values) {
1216                if (!val.hasConvertInteger()) {
1217                    return false;
1218                }
1219            }
1220            return true;
1221        }
1222
1223        /**
1224         * Is {@link #convertReal()} expected to succeed?
1225         */
1226        public boolean hasConvertReal() {
1227            for (CValue val : values) {
1228                if (!val.hasConvertReal()) {
1229                    return false;
1230                }
1231            }
1232            return true;
1233        }
1234
1235        /**
1236         * Is {@link #convertBoolean()} expected to succeed?
1237         */
1238        public boolean hasConvertBoolean() {
1239            for (CValue val : values) {
1240                if (!val.hasConvertBoolean()) {
1241                    return false;
1242                }
1243            }
1244            return true;
1245        }
1246
1247        /**
1248         * Is {@link #convertString()} expected to succeed?
1249         */
1250        public boolean hasConvertString() {
1251            for (CValue val : values) {
1252                if (!val.hasConvertString()) {
1253                    return false;
1254                }
1255            }
1256            return true;
1257        }
1258
1259                public String toString() {
1260                        // TODO: Should this be stringValue() instead?
1261                        if (values.length == 0)
1262                                return "(zero-size array)";
1263                        StringBuilder buf = new StringBuilder();
1264                        toStringRec(buf, iterator(), 0);
1265                        return buf.toString();
1266                }
1267               
1268                private void toStringRec(StringBuilder buf, Iterator<CValue> it, int dim) {
1269                        if (dim < indices.ndims()) {
1270                                int n = indices.size().get(dim);
1271                                buf.append("{ ");
1272                                dim++;
1273                                toStringRec(buf, it, dim);
1274                                for (int i = 1; i < n; i++) {
1275                                        buf.append(", ");
1276                                        toStringRec(buf, it, dim);
1277                                }
1278                                buf.append(" }");
1279                        } else {
1280                                buf.append(it.next());
1281                        }
1282                }
1283
1284        /**
1285         * Create a literal AST node from constant, for use in flat tree.
1286         *
1287         * @return FArray AST node containing literal expression nodes.
1288         */
1289        public FExp buildLiteral() { 
1290            return buildLiteralRec(iterator(), 0, true);
1291        }
1292
1293        @Override
1294        public boolean hasBuildLiteral() {
1295            for (CValue val : values) {
1296                if (!val.hasBuildLiteral()) {
1297                    return false;
1298                }
1299            }
1300            return true;
1301        }
1302
1303        /**
1304         * Create a literal AST node from constant, for use in instance tree.
1305         *
1306         * @return FArray AST node containing literal expression nodes.
1307         */
1308        public FExp buildInstLiteral() { 
1309            return buildLiteralRec(iterator(), 0, false);
1310        }
1311
1312        private FExp buildLiteralRec(Iterator<CValue> it, int dim, boolean flat) {
1313            if (dim < indices.ndims()) {
1314                FArray arr = new FArray();
1315                int n = indices.size().get(dim);
1316                dim++;
1317                for (int i = 0; i < n; i++) 
1318                    arr.addFExp(buildLiteralRec(it, dim, flat));
1319                return arr;
1320            } else {
1321                return flat ? it.next().buildLiteral() : it.next().buildInstLiteral();
1322            }
1323        }
1324
1325            /**
1326             * An iterator that iterates over all cells in the array.
1327             *
1328             * Traverses the array in the same order as indices().iterator().
1329             */
1330                public Iterator<CValue> iterator() {
1331                        return new ConstArrayIterator<CValue>(values);
1332                }
1333
1334        /**
1335         * Checks whether or not this array has unknown members.
1336         *
1337         * @return
1338         *          {@code false} of all array members are known, {@code true} otherwise.
1339         */
1340        public boolean hasUnknowns() {
1341            for (CValue value : values) {
1342                if (value.isUnknown()) {
1343                    return true;
1344                }
1345            }
1346            return false;
1347        }
1348    }
1349   
1350    /**
1351     * Constant value for record.
1352     *
1353     * Note that this class is mutable, care must be taken not to modify
1354     * records that have already been returned. The only place where that
1355     * should be done is during function evaluation, where CValues are used
1356     * to represent mutable variable values.
1357     */
1358    public class CValueRecord extends CValue {
1359       
1360        protected String name;
1361        protected Map<String,Integer> members;
1362        protected CValue[] values;
1363       
1364        /**
1365         * Create a new record constant value for the described record.
1366         *
1367         * @param type  the FRecordType describing the record
1368         */
1369        public CValueRecord(FRecordType type) {
1370                name = type.getName();
1371                int n = type.getNumComponent();
1372                members = new HashMap<String,Integer>(n * 4 / 3 + 1);
1373                values = new CValue[n];
1374                int i = 0;
1375            for (FRecordComponentType mtype : type.getComponents()) {
1376                values[i] = CValue.UNKNOWN;
1377                members.put(mtype.getName(), i++);
1378            }
1379        }
1380           
1381            public CValueRecord clone() {
1382                CValueRecord res = (CValueRecord) super.clone();
1383                res.values = new CValue[values.length];
1384                for (int i = 0; i < values.length; i++) 
1385                                res.values[i] = values[i].clone();
1386                return res;
1387            }
1388           
1389        /**
1390         * Check if this is a record.
1391         */
1392        public boolean isRecord() {
1393                return true;
1394        }
1395       
1396        /**
1397         * Check if there was an error in any part of the evaluation.
1398         *
1399         * @return true if there was an error, otherwise false.
1400         */
1401        public boolean isPartlyUnknown() {
1402            for (CValue cvalue : values)
1403                if (cvalue.isPartlyUnknown())
1404                    return true;
1405            return false;
1406        }
1407       
1408        /**
1409         * Convenience method for accessing a record CValue as CValueRecord.
1410         *
1411         * Only valid for records.
1412         */
1413        public CValueRecord record() {
1414                return this;
1415        }
1416       
1417        /**
1418         * Get the internal index for a given member.
1419         */
1420        protected int index(String name) {
1421                Integer i = members.get(name);
1422                if (i == null)
1423                        throw new ConstantEvaluationException(this, "find record member '" + name + "'");
1424                return i.intValue();
1425        }
1426       
1427        /**
1428         * Get a map from member names to an index that can be used in the index
1429         * versions of methods.
1430         */
1431        public Map<String,Integer> members() {
1432                return members;
1433        }
1434       
1435        /**
1436         * Set the value of a specific member of a record constant value.
1437         */
1438        public void setMember(String name, CValue val) {
1439                values[index(name)] = val;
1440        }
1441       
1442        /**
1443         * Set the value of a specific member of a record constant value.
1444         *
1445         * @param i  the zero-based index of the member, according to the order
1446         *           in the record declaration
1447         */
1448        public void setMember(int i, CValue val) {
1449                values[i] = val;
1450        }
1451       
1452        /**
1453         * Get the value of a specific member of a record constant value.
1454         */
1455        public CValue getMember(String name) {
1456                return getMember(index(name));
1457        }
1458       
1459        /**
1460         * Get the value of a specific member of a record constant value.
1461         *
1462         * @param i  the zero-based index of the member, according to the order
1463         *           in the record declaration
1464         */
1465        public CValue getMember(int i) {
1466                CValue res = values[i];
1467                return res == null ? UNKNOWN : res;
1468        }
1469       
1470        public String toString() {
1471                StringBuilder buf = new StringBuilder(name);
1472                buf.append('(');
1473                String sep = "";
1474                for (CValue val : values) {
1475                        buf.append(sep);
1476                        buf.append(val == null ? UNKNOWN : val);
1477                        sep = ", ";
1478                }
1479                buf.append(')');
1480                return buf.toString();
1481        }
1482
1483        /**
1484         * Create a literal AST node from constant, for use in flat tree.
1485         *
1486         * @return FArray AST node containing literal expression nodes.
1487         */
1488        public FExp buildLiteral() { 
1489            FRecordConstructor res = new FRecordConstructor(name);
1490            for (CValue val : values)
1491                res.addArg(val.buildLiteral());
1492            return res;
1493        }
1494
1495        @Override
1496        public boolean hasBuildLiteral() {
1497            for (CValue val : values) {
1498                if (!val.hasBuildLiteral()) {
1499                    return false;
1500                }
1501            }
1502            return true;
1503        }
1504
1505        /**
1506         * Create a literal AST node from constant, for use in instance tree.
1507         *
1508         * @return FArray AST node containing literal expression nodes.
1509         */
1510        public FExp buildInstLiteral() { 
1511            InstAccess rec = new InstGlobalAccess(InstAccess.fromName(name));
1512            InstRecordConstructor res = new InstRecordConstructor(rec, new List());
1513            int i = 1;
1514            for (CValue val : values)
1515                res.addArg(new InstPositionalArgument(val.buildInstLiteral(), i++));
1516            return res;
1517        }
1518
1519    }
1520
1521
1522    public class CValueExternalObject extends CValue {
1523        protected CValue[] values;
1524        public CValueExternalObject(CValue[] values) {
1525            this.values = values;
1526        }
1527       
1528        public String toString() {
1529            StringBuilder buf = new StringBuilder();
1530            buf.append('{');
1531            String sep = "";
1532            for (CValue val : values) {
1533                buf.append(sep);
1534                buf.append(val == null ? UNKNOWN : val);
1535                sep = ", ";
1536            }
1537            buf.append('}');
1538            return buf.toString();
1539        }
1540    }
1541   
1542    public class CValuePartialFunction extends CValue {
1543        protected Map<String,CValue> values;
1544        protected CommonCallable func;
1545       
1546        public CValuePartialFunction(CommonCallable func, Map<String, CValue> values) {
1547            this.values = values;
1548            this.func   = func;
1549        }
1550       
1551        public static CValuePartialFunction create(CommonCallable func, Map<CommonVariableDecl,CValue> values) {
1552            Map<String,CValue> resValues = new HashMap<String,CValue>();
1553            for (CommonVariableDecl cvd : values.keySet())
1554                resValues.put(cvd.name(), values.get(cvd));
1555            return new CValuePartialFunction(func, resValues);
1556        }
1557       
1558        @Override
1559        public String toString() {
1560            StringBuilder buf = new StringBuilder();
1561            buf.append(func.name());
1562            buf.append('(');
1563            String sep = "";
1564            for (String cvd : values.keySet()) {
1565                buf.append(sep);
1566                buf.append(cvd);
1567                buf.append("=");
1568                buf.append(values.get(cvd));
1569                sep = ", ";
1570            }
1571            buf.append(')');
1572            return buf.toString();
1573        }
1574       
1575        @Override
1576        public void evaluateFunction(VariableEvaluator evaluator, CommonCallable partial, Map<CommonVariableDecl, CValue> values) {
1577            Iterator<? extends CommonVariableDecl> partials = partial.myInputs().iterator();
1578            for (CommonVariableDecl fullCvd : func.myInputs()) {
1579                if (this.values.containsKey(fullCvd.name())) {
1580                    values.put(fullCvd, this.values.get(fullCvd.name()));
1581                } else {
1582                    CommonVariableDecl partCvd = partials.next();
1583                    values.put(fullCvd, values.get(partCvd));
1584                    values.remove(partCvd);
1585                }
1586            }
1587            func.evaluate(evaluator, values);
1588            partials = partial.myOutputs().iterator();
1589            for (CommonVariableDecl fullCvd : func.myOutputs()) {
1590                if (partials.hasNext()) {
1591                    values.put(partials.next(), values.get(fullCvd));
1592                }
1593                values.remove(fullCvd);
1594            }
1595        }
1596       
1597        @Override
1598        public CValue evaluatePartialFunction(CommonCallable partial, Map<CommonVariableDecl, CValue> values) {
1599            Map<String,CValue> resValues = new HashMap<String,CValue>();
1600            resValues.putAll(this.values);
1601            for (CommonVariableDecl partCvd : partial.myInputs()) {
1602                if (values.containsKey(partCvd)) {
1603                    resValues.put(partCvd.name(), values.get(partCvd));
1604                }
1605            }
1606            return new CValuePartialFunction(func, resValues);
1607        }
1608
1609    }
1610
1611    /**
1612     * Constant value for enumeration literal.
1613     */
1614    public class CValueEnum extends CValue {
1615
1616        private FEnumType type;
1617        private String value;
1618        private int index;
1619
1620        /**
1621         * Create a new constant value for enumeration literal.
1622         *
1623         * @param type   the type of the enumeration
1624         * @param value  the name of the enumeration literal
1625         */
1626        public CValueEnum(FType type, String value) {
1627            this.type = (FEnumType) type;
1628            this.value = value;
1629            index = 0;
1630            int n = this.type.getNumFEnumLiteralType();
1631            for (int i = 0; i < n && index == 0; i++)
1632                if (this.type.getFEnumLiteralType(i).getName().equals(value))
1633                    index = i + 1;
1634        }
1635
1636        /**
1637         * Create a new constant value for enumeration literal.
1638         *
1639         * @param type   the type of the enumeration
1640         * @param index  the ordinal for the enumeration literal
1641         */
1642        public CValueEnum(FType type, int index) {
1643            this.type = (FEnumType) type;
1644            if (index < 0)
1645                index = this.type.getNumFEnumLiteralType() + index + 1;
1646            this.index = index;
1647            value = this.type.getFEnumLiteralType(index - 1).getName();
1648        }
1649
1650        @Override
1651        public int intValue() {
1652            return index;
1653        }
1654
1655        @Override
1656        public double realValue() {
1657            return index;
1658        }
1659
1660        @Override
1661        public String stringValue() {
1662            return type.getName() + "." + value;
1663        }
1664
1665        @Override
1666        public String stringExpValue() {
1667            return value;
1668        }
1669
1670        @Override
1671        public String toString() {
1672            return type.getName() + "." + value;
1673        }
1674
1675        @Override
1676        public boolean isEnum() {
1677            return true;
1678        }
1679
1680        @Override
1681        public boolean hasIntValue() {
1682            return true;
1683        }
1684
1685        @Override
1686        public boolean hasRealValue() {
1687            return true;
1688        }
1689
1690        @Override
1691        public boolean hasStringValue() {
1692            return true;
1693        }
1694
1695        /**
1696         * Create a literal AST node from constant.
1697         *
1698         * Always creates node for the flat tree.
1699         * 
1700         *  @return an CommonAccessExp pointing to the literal in the FEnumDecl.
1701         */
1702        public FExp buildLiteral() {
1703            return type.createLiteral(index);
1704        }
1705
1706        @Override
1707        public FExp buildInstLiteral() {
1708            return new FEnumLitExp(type, index);
1709        }
1710
1711        @Override
1712        public boolean hasBuildLiteral() {
1713            return true;
1714        }
1715
1716        public CValue constrainWithin(CValue min, CValue max) {
1717            if (!min.isUnknown() && min.intValue() > index)
1718                return min;
1719            if (!max.isUnknown() && max.intValue() < index)
1720                return max;
1721            return this;
1722        }
1723
1724    }
1725
1726
1727    /**
1728     * Create a CValue with the zero value for this type, if applicable.
1729     */
1730    public CValue FType.zeroCValue() {
1731        if (isArray() && !zeroCValueScalar().isUnknown()) {
1732            CValueArray res = new CValueArray(size());
1733            while (!res.isFilled())
1734                res.addCell(zeroCValueScalar());
1735            return res; 
1736        } else {
1737            return zeroCValueScalar();
1738        }
1739    }
1740
1741    public CValue FType.zeroCValueScalar()        { return CValue.UNKNOWN; }
1742    public CValue FArrayType.zeroCValueScalar()   { return getFPrimitiveType().zeroCValueScalar(); }
1743    public CValue FRealType.zeroCValueScalar()    { return new CValueReal(0.0); }
1744    public CValue FIntegerType.zeroCValueScalar() { return new CValueInteger(0); }
1745    public CValue FEnumType.zeroCValueScalar()    { return new CValueEnum(this, 1); }
1746    public CValue FStringType.zeroCValueScalar()  { return new CValueString(""); }
1747    public CValue FBooleanType.zeroCValueScalar() { return new CValueBoolean(false); }
1748   
1749    public CValue FType.createCValue(int v) {
1750        if (isArray()) {
1751            CValueArray res = new CValueArray(size());
1752            while (!res.isFilled())
1753                res.addCell(createCValueScalar(v));
1754            return res;
1755        } else {
1756            return createCValueScalar(v);
1757        }
1758    }
1759   
1760    public CValue FType.createCValueScalar(int v)     { return new CValueInteger(v); }
1761    public CValue FRealType.createCValueScalar(int v) { return new CValueReal(v); }
1762
1763    public CValue FType.convert(CValue v)        { return v; }
1764    public CValue FRealType.convert(CValue v)    { return v.convertReal(); }
1765    public CValue FIntegerType.convert(CValue v) { return v.convertInteger(); }
1766    public CValue FStringType.convert(CValue v)  { return v.convertString(); }
1767    public CValue FBooleanType.convert(CValue v) { return v.convertBoolean(); }
1768
1769    public CValue FType.limitCValueScalar(boolean high)        { return CValue.UNSUPPORTED; }
1770    public CValue FRealType.limitCValueScalar(boolean high)    { return new CValueReal(      high ? Double.MAX_VALUE  : -Double.MAX_VALUE); }
1771    public CValue FIntegerType.limitCValueScalar(boolean high) { return new CValueInteger(   high ? Integer.MAX_VALUE : Integer.MIN_VALUE); }
1772    public CValue FBooleanType.limitCValueScalar(boolean high) { return new CValueBoolean(   high ? true : false); }
1773    public CValue FEnumType.limitCValueScalar(boolean high)    { return new CValueEnum(this, high ? getNumFEnumLiteralType() : 1); }
1774
1775    public boolean CValue.isZero()        { return false; }
1776    public boolean CValueReal.isZero()    { return value == 0; }
1777    public boolean CValueInteger.isZero() { return value == 0; }
1778   
1779   
1780    private boolean CValueArray.cached = false;
1781    private boolean CValueRecord.cached = false;
1782    public CValueArray CValueArray.markAsCached() { this.cached = true; return this; }
1783    public CValueRecord CValueRecord.markAsCached() { this.cached = true; return this; }
1784   
1785    public CValue CValue.cached()       { return this; }
1786    public CValue CValueArray.cached()  {
1787        CValueArray res = this;
1788        if (cached) {
1789            res = (CValueArray) res.clone();
1790        } else {
1791            for (int i = 0; i < values.length; i++) {
1792                values[i] = values[i].cached();
1793            }
1794        }
1795        return res.markAsCached();
1796    }
1797    public CValue CValueRecord.cached()  {
1798        CValueRecord res = this;
1799        if (cached) {
1800            res = res.clone();
1801        } else {
1802            for (int i = 0; i < values.length; i++) {
1803                values[i] = values[i].cached();
1804            }
1805        }
1806        return res.markAsCached();
1807    }
1808   
1809   
1810    public CValue FType.unknownCValue() {
1811        if (isArray()) {
1812            CValueArray arr = new CValueArray(size());
1813            for (Index i : indices()) {
1814                arr.setCell(i, CValue.UNKNOWN);
1815            }
1816            return arr;
1817        } else {
1818            return CValue.UNKNOWN;
1819        }
1820    }
1821   
1822   
1823    public boolean CValue.equals(CValue other) {
1824        return super.equals(other);
1825    }
1826   
1827    public boolean CValueUnknown.equals(CValue other) {
1828        if (other instanceof CValueUnknown) {
1829            return true;
1830        }
1831        return super.equals(other);
1832    }
1833   
1834    public boolean CValueReal.equals(CValue other) {
1835        if (other instanceof CValueReal || 
1836                other instanceof CValueInteger) {
1837            return realValue() == other.realValue();
1838        }
1839        return super.equals(other);
1840    }
1841   
1842    public boolean CValueInteger.equals(CValue other) {
1843        if (other instanceof CValueReal || 
1844                other instanceof CValueInteger) {
1845            return realValue() == other.realValue();
1846        }
1847        return super.equals(other);
1848    }
1849   
1850    public boolean CValueBoolean.equals(CValue other) {
1851        if (other instanceof CValueBoolean) {
1852            return booleanValue() == other.booleanValue();
1853        }
1854        return super.equals(other);
1855    }
1856   
1857    public boolean CValueEnum.equals(CValue other) {
1858        if (other instanceof CValueEnum) {
1859            return intValue() == other.intValue();
1860        }
1861        return super.equals(other);
1862    }
1863   
1864    public boolean CValueString.equals(CValue other) {
1865        if (other instanceof CValueString) {
1866            return stringValue() == other.stringValue();
1867        }
1868        return super.equals(other);
1869    }
1870   
1871    public boolean CValueRecord.equals(CValue other) {
1872        if (other instanceof CValueRecord) {
1873            CValueRecord o = (CValueRecord) other;
1874            for (int i = 0; i < values.length; i++) {
1875                if (!values[i].equals(o.values[i])) {
1876                    return false;
1877                }
1878            }
1879            return true;
1880        }
1881        return super.equals(other);
1882    }
1883   
1884    public boolean CValueArray.equals(CValue other) {
1885        if (other instanceof CValueArray) {
1886            CValueArray o = (CValueArray) other;
1887            if (values.length != o.values.length)
1888                return false;
1889            for (int i = 0; i < values.length; i++) {
1890                if (!values[i].equals(o.values[i])) {
1891                    return false;
1892                }
1893            }
1894            return true;
1895        }
1896        return super.equals(other);
1897    }
1898   
1899    public abstract boolean CValue.typeMatches(CValue other);
1900   
1901    public boolean CValueUnknown.typeMatches(CValue other) {
1902        return other.isUnknown();
1903    }
1904   
1905    public boolean CValueReal.typeMatches(CValue other) {
1906        return other.isReal() || other.isInteger();
1907    }
1908   
1909    public boolean CValueInteger.typeMatches(CValue other) {
1910        return other.isReal() || other.isInteger();
1911    }
1912   
1913    public boolean CValueBoolean.typeMatches(CValue other) {
1914        return other.isBoolean();
1915    }
1916   
1917    public boolean CValueEnum.typeMatches(CValue other) {
1918        return other.isEnum();
1919    }
1920   
1921    public boolean CValueString.typeMatches(CValue other) {
1922        return other.isString();
1923    }
1924   
1925    public boolean CValueRecord.typeMatches(CValue other) {
1926        if (other instanceof CValueRecord) {
1927            CValueRecord o = (CValueRecord) other;
1928            if (values.length != o.values.length)
1929                return false;
1930            for (int i = 0; i < values.length; i++) {
1931                if (!values[i].typeMatches(o.values[i])) {
1932                    return false;
1933                }
1934            }
1935            return true;
1936        }
1937        return false;
1938    }
1939   
1940    public boolean CValueArray.typeMatches(CValue other) {
1941        if (other instanceof CValueArray) {
1942            CValueArray o = (CValueArray) other;
1943            if (values.length != o.values.length)
1944                return false;
1945            for (int i = 0; i < values.length; i++) {
1946                if (!values[i].typeMatches(o.values[i])) {
1947                    return false;
1948                }
1949            }
1950            return true;
1951        }
1952        return false;
1953    }
1954   
1955   
1956    public boolean CValueExternalObject.typeMatches(CValue other) {
1957        throw new UnsupportedOperationException("typeMatches() not implemented for "+getClass().getSimpleName());
1958    }
1959    public boolean CValuePartialFunction.typeMatches(CValue other) {
1960        throw new UnsupportedOperationException("typeMatches() not implemented for "+getClass().getSimpleName());
1961    }
1962
1963    /**
1964     * Modifies <code>this</code> CValue so that components that do not match to
1965     * <code>other</code> are replaced with <code>CValue.UNKNOWN</code>.
1966     * @param other CValue to merge from
1967     * @return Possibly modified <code>this</code> if composite or equals
1968     *         <code>other</code>, else <code>CValue.UNKNOWN</code>
1969     */
1970    public CValue CValue.merge(CValue other) {
1971        if (equals(other)) {
1972            return this;
1973        }
1974        if (isUnknown() && !other.isUnknown()) {
1975            return this;
1976        } else if (!isUnknown() && other.isUnknown()) {
1977            return other;
1978        }
1979        return CValue.UNKNOWN;
1980    }
1981   
1982    @Override
1983    public CValue CValueArray.merge(CValue other) {
1984        if (other instanceof CValueArray) {
1985            CValueArray o = (CValueArray) other;
1986            if (values.length != o.values.length)
1987                return CValue.UNKNOWN;
1988            for (int i = 0; i < values.length; i++) {
1989                values[i] = values[i].merge(o.values[i]);
1990            }
1991            return this;
1992        }
1993        return CValue.UNKNOWN;
1994    }
1995   
1996    @Override
1997    public CValue CValueRecord.merge(CValue other) {
1998        if (other instanceof CValueRecord) {
1999            CValueRecord o = (CValueRecord) other;
2000            if (values.length != o.values.length)
2001                return CValue.UNKNOWN;
2002            for (int i = 0; i < values.length; i++) {
2003                values[i] = values[i].merge(o.values[i]);
2004            }
2005            return this;
2006        }
2007        return CValue.UNKNOWN;
2008    }
2009   
2010    @Override
2011    public CValue CValueUnknown.merge(CValue other) {
2012        return this;
2013    }
2014   
2015    @Override
2016    public CValue CValueUnknownUse.merge(CValue other) {
2017        if (other instanceof CValueUnknownUse) {
2018            CValueUnknownUse o = other.unknownUse();
2019            CValueUnknownUse res = new CValueUnknownUse();
2020            res.deps.addAll(deps);
2021            res.deps.addAll(o.deps);
2022            return res;
2023        }
2024        return super.merge(other);
2025    }
2026   
2027   
2028    /**
2029     * \build Creates an FExp with literals from this Array.
2030     *
2031     * Creates a (possibly nested) FArray containing FLitExp nodes.
2032     *
2033     * @param toReal  if <code>true</code>, convert all values to real.
2034     */
2035    public FExp FExp.buildLiteral(boolean toReal) {
2036        return toReal ? ceval().convertReal().buildLiteral() : ceval().buildLiteral();
2037    }
2038
2039    /**
2040     * Convenience function for savely checking if an expression as a particular value.
2041     *
2042     */ 
2043    syn boolean FExp.equalsRealValue(double val) {
2044        try {
2045                return variability().lessOrEqual(Variability.CONSTANT) && ceval().realValue()==val;
2046        } catch(Exception e) {
2047                return false;
2048        }
2049    } 
2050
2051
2052    /**
2053     * Returns the constant value of a flat expression.
2054     *
2055     * If the expression is not constant, or if it contains type errors,
2056     * <code>CValue.UNKNOWN</code> is returned.
2057     *
2058     * The actual evaluation of concrete FExp nodes is performed by dispatching
2059     * with respect to the primitive type of the expression. For example, when an
2060     * FAddExp node is evaluated, the computation proceeds in the following steps:
2061     *
2062     *  - The primitive type of the expression is retrieved using the type()
2063     *    attribute.
2064     *  - The method add() defined for FType is invoked.
2065     *  - The resulting CValue is returned.
2066     * 
2067     *  Using this strategy, a particular FExp node does not need to know the details of
2068     *  how to evaluate itself in the case of operands of different types. Rather,
2069     *  these computations are delegated to the respective types. In particular,
2070     *  this design simplifies the task of extending the evaluation framework
2071     *  to composite types such as arrays and complex numbers. In addition,
2072     *  the type dispatch makes implementation of support for operator overloading
2073     *  simpler.
2074     * 
2075     *  Note that function evaluation depends on nothing being cached in constant
2076     *  evaluation. If caching is needed later on, an argument to avoid caching must be
2077     *  added to cevalCalc() and an alternate ceval() created. Also, the form taking
2078     *  an Index should then probably be removed.
2079     * 
2080     *  The VariableEvaluator argument is designed to only work reliably after
2081     *  scalarization. This is due to that the fact that size, type, array and
2082     *  some other functions use ceval() without propagation of the evaluator.
2083     *
2084     * @return The constant value of the expression.
2085     */
2086    syn CValue FExp.ceval() = ceval(defaultVariableEvaluator());
2087
2088    syn CValue FExp.ceval(VariableEvaluator evaluator) {
2089        if (isCircular()) 
2090            return CValue.UNKNOWN;
2091        if (isArray()) {
2092            if (size().evaluated().isUnknown())
2093                return CValue.UNKNOWN;
2094            return cevalArray(evaluator, Index.NULL);
2095        }
2096        CValue resOver = cevalOverloaded(evaluator);
2097        return (resOver != null) ? resOver : cevalCalc(evaluator);
2098    }
2099   
2100    /**
2101     * Like {@link #ceval()}, but in the case of an array, only calculate
2102     *        the given cell, if possible.
2103     */
2104    syn CValue FExp.ceval(VariableEvaluator evaluator, Index i) {
2105        if (isCircular()) 
2106            return CValue.UNKNOWN;
2107        if (isArray())
2108            return cevalArray(evaluator, i);
2109        CValue resOver = cevalOverloaded(evaluator);
2110        return (resOver != null) ? resOver : cevalCalc(evaluator);
2111    }
2112
2113
2114    syn Set<String> FExp.collectAccessNames() {
2115        final Set<String> names = new HashSet<>();
2116        collectAccessNames(names);
2117        return names;
2118    }
2119
2120    public void FExp.collectAccessNames(Set<String> collectedNames) {
2121        for (FExp child : childFExps()) {
2122            child.collectAccessNames(collectedNames);
2123        }
2124    }
2125
2126    @Override
2127    public void FTimeExp.collectAccessNames(Set<String> collectedNames) {
2128        collectedNames.add("time");
2129    }
2130
2131    @Override
2132    public void InstAccessExp.collectAccessNames(Set<String> collectedNames) {
2133        if (isArray()) {
2134            for (FExp fexp: getArray().iterable()) {
2135                fexp.collectAccessNames(collectedNames);
2136            }
2137        } else {
2138            final InstAccess access = getInstAccess();
2139            if (!access.isPackageConstantAccess() && !access.isEnumLiteralAccess()) {
2140                access.collectAccessNames(collectedNames);
2141                access.collectAccessNamesInArraySubscripts(collectedNames);
2142            }
2143        }
2144    }
2145
2146    @Override
2147    public void InstFunctionCall.collectAccessNames(Set<String> collectedNames) {
2148      for (InstFunctionArgument arg : getArgList()) {
2149          arg.getFExp().collectAccessNames(collectedNames);
2150      }
2151    }
2152
2153    public boolean InstAccess.isPackageConstantAccess() { return myInstComponentDecl().isPackageConstant(); }
2154    public boolean InstAccess.isEnumLiteralAccess()     { return myInstComponentDecl().isEnumLiteral(); }
2155
2156    public abstract void InstAccess.collectAccessNames(Set<String> collectedNames);
2157
2158    @Override
2159    public void InstDot.collectAccessNames(Set<String> collectedNames) {
2160        final String qualifiedName = qualifiedName();
2161
2162        final ArrayList<String> prefixes = new ArrayList<>();
2163        for (InstAccess instAccess : getInstAccesss()) {
2164            if (instAccess.isClassAccess()) {
2165                prefixes.add(instAccess.name());
2166            }
2167        }
2168        final String prefix = StringUtil.join(".", prefixes);
2169
2170        final Set<String> names = new HashSet<>();
2171        getLastInstAccess().collectAccessNames(names);
2172        for (String name : names) {
2173            collectedNames.add(prefix.isEmpty() ? name : prefix +"." + name);
2174        }
2175    }
2176
2177    @Override
2178    public void InstGlobalAccess.collectAccessNames(Set<String> collectedNames) {
2179        getInstAccess().collectAccessNames(collectedNames);
2180    }
2181
2182    @Override
2183    public void InstArrayAccess.collectAccessNames(Set<String> collectedNames) {
2184        myInstComponentElement().collectScalarPrimitives(collectedNames);
2185    }
2186
2187    @Override
2188    public void InstClassAccess.collectAccessNames(Set<String> collectedNames) {
2189    }
2190
2191    @Override
2192    public void InstScalarAccess.collectAccessNames(Set<String> collectedNames) {
2193        myInstComponentDecl().collectScalarPrimitives(collectedNames);
2194    }
2195
2196    public void InstComponentDecl.collectScalarPrimitives(Set<String> collectedNames) {
2197        for (InstComponentDecl instComponentDecl : getInstComponentDecls()) {
2198            instComponentDecl.collectScalarPrimitives(collectedNames);
2199        }
2200    }
2201
2202    @Override
2203    public void InstPrimitive.collectScalarPrimitives(Set<String> collectedNames) {
2204        final String qualifiedName = qualifiedName();
2205
2206        if (isArray()) {
2207            for (Index index : Indices.create(size())) {
2208                collectedNames.add(qualifiedName + index);
2209            }
2210        } else if (!isForIndex()) {
2211            collectedNames.add(qualifiedName);
2212        }
2213    }
2214
2215    public void FArraySubscripts.collectAccessNames(Set<String> collectedNames) {
2216    }
2217
2218    @Override
2219    public void FArrayExpSubscripts.collectAccessNames(Set<String> collectedNames) {
2220        for (FSubscript sub : getFSubscripts()) {
2221            sub.collectAccessNames(collectedNames);
2222        }
2223    }
2224
2225
2226    public void FSubscript.collectAccessNames(Set<String> collectedNames) {
2227    }
2228
2229    @Override
2230    public void FExpSubscript.collectAccessNames(Set<String> collectedNames) {
2231        getFExp().collectAccessNames(collectedNames);
2232    }
2233
2234    @Override
2235    public void FIterExp.collectAccessNames(Set<String> collectedNames) {
2236        for (CommonForIndex cfi : getForIndexs()) {
2237            cfi.collectAccessNames(collectedNames);
2238        }
2239       
2240        getFExp().collectAccessNames(collectedNames);
2241    }
2242
2243    public abstract void CommonForIndex.collectAccessNames(Set<String> collectedNames);
2244
2245    @Override
2246    public void FForIndex.collectAccessNames(Set<String> collectedNames) {
2247        throw new UnsupportedOperationException();
2248    }
2249
2250    @Override
2251    public void InstForIndexWithExp.collectAccessNames(Set<String> collectedNames) {
2252        getFExp().collectAccessNames(collectedNames);
2253    }
2254
2255    @Override
2256    public void InstForIndexNoExp.collectAccessNames(Set<String> collectedNames) {
2257    }
2258
2259    public void InstAccess.collectAccessNamesInArraySubscripts(Set<String> collectedNames) {
2260    }
2261
2262    @Override
2263    public void InstDot.collectAccessNamesInArraySubscripts(Set<String> collectedNames) {
2264        for (InstAccess access : getInstAccesss()) {
2265            access.collectAccessNamesInArraySubscripts(collectedNames);
2266        }
2267    }
2268
2269    @Override
2270    public void InstGlobalAccess.collectAccessNamesInArraySubscripts(Set<String> collectedNames) {
2271        getInstAccess().collectAccessNamesInArraySubscripts(collectedNames);
2272    }
2273
2274    @Override
2275    public void InstArrayAccess.collectAccessNamesInArraySubscripts(Set<String> collectedNames) {
2276        if (myInstComponentDecl().isPrimitive()) {
2277            getFArraySubscripts().collectAccessNames(collectedNames);
2278        }
2279    }
2280
2281
2282    /**
2283     * If this is an overloaded operator expression, evaluate it as such, otherwise return null.
2284     */
2285    syn CValue FExp.cevalOverloaded(VariableEvaluator evaluator) {
2286        if (!shouldUseOverloadedOperator() || operatorName() == null)
2287            return null;
2288        InstClassDecl func = overloadedOperator();
2289        return (func == null) ? CValue.UNKNOWN : func.evaluateFirst(evaluator, childFExps());
2290    }
2291
2292    /**
2293     * Check if this expression can be constant evaluated.
2294     *
2295     * Calls ceval and checks that no exception is thrown, and that the result isn't unknown.
2296     * Use only for error checking, since it does not guarantee that the expression can be
2297     * evaluated at the moment - only after calculating overconstrained connection graph.
2298     */
2299    syn boolean FExp.canCeval() = canCeval(defaultVariableEvaluator());
2300   
2301    syn boolean FExp.canCeval(VariableEvaluator evaluator) {
2302          try {
2303              return !ceval(evaluator).isUnknown();
2304        } catch (ConstantEvaluationNotReadyException e) {
2305          // Will be evaluatable later, ignore for now
2306          return true;
2307          } catch (Exception e) {
2308              return false;
2309          }
2310    }
2311   
2312    /**
2313     * Constant evaluation for arrays.
2314     *
2315     * @param i  the index of the cell to calculate,
2316     *           where Index.NULL means to calculate all cells
2317     * @see #ceval()
2318     */
2319    syn CValue FExp.cevalArray(Index i) = cevalArray(defaultVariableEvaluator(), i);
2320    syn CValue FExp.cevalArray(VariableEvaluator evaluator, Index i) {
2321        CValueArray res = new CValueArray(size());
2322        if (size().evaluated().isUnknown())
2323            return CValue.UNKNOWN;
2324        Array arr = getArray();
2325        if (i == Index.NULL)
2326          for (Index j : arr.indices())
2327              res.setCell(j, arr.get(j).ceval(evaluator));
2328        else if (size().isOKIndex(i))
2329          res.setCell(i, arr.get(i).ceval(evaluator));
2330        else
2331          throw new ConstantEvaluationException();
2332        return res;
2333    }
2334   
2335    eq FDeferExp.cevalArray(VariableEvaluator evaluator, Index i) = getFExp().cevalArray(evaluator, i);
2336   
2337    // Bypass for nodes with inherent support for constant evaluation of arrays.
2338    eq FFunctionCall.cevalArray(VariableEvaluator evaluator, Index i)    = cevalCalc(evaluator);
2339    eq InstFunctionCall.cevalArray(VariableEvaluator evaluator, Index i) = cevalCalc(evaluator);
2340    eq CommonAccessExp.cevalArray(VariableEvaluator evaluator, Index i)  = isSlice() ? super.cevalArray(evaluator, i) : cevalCalc(evaluator);
2341    eq FIfExp.cevalArray(VariableEvaluator evaluator, Index i)           = cevalSelectExp(evaluator).cevalArray(evaluator, i);
2342
2343    /**
2344     * Delegate attribute for ceval().
2345     *
2346     * This needs to be overridden for subclasses of FExp.
2347     */
2348    syn CValue FExp.cevalCalc(VariableEvaluator evaluator);
2349    eq FUnsupportedExp.cevalCalc(VariableEvaluator evaluator) = CValue.UNSUPPORTED;
2350    eq FAbstractArrayExp.cevalCalc(VariableEvaluator evaluator) { throw new ConstantEvaluationException(null, "Can not evaluate scalar array expression ");}
2351    eq InstPreExp.cevalCalc(VariableEvaluator evaluator) = CValue.UNSUPPORTED;
2352    eq FNoExp.cevalCalc(VariableEvaluator evaluator) = CValue.UNSUPPORTED;
2353
2354    eq FTimeExp.cevalCalc(VariableEvaluator evaluator) = evaluator.timeValue();
2355   
2356    eq FInStreamEpsExp.cevalCalc(VariableEvaluator evaluator) = evaluator.inStreamEpsilon();
2357
2358    eq FDeferExp.cevalCalc(VariableEvaluator evaluator) = getFExp().ceval(evaluator);
2359   
2360    eq FBinExp.cevalCalc(VariableEvaluator evaluator) = evaluator.evalBinOp(this, getLeft().ceval(evaluator), getRight().ceval(evaluator));
2361    eq FDotMulExp.cevalCalc(VariableEvaluator evaluator) {
2362        CValue left = getLeft().ceval(evaluator);
2363        CValue right = getRight().ceval(evaluator);
2364        if (left.isZero() || right.isZero()) {
2365            return type().zeroCValue();
2366        }
2367        return evaluator.evalBinOp(this, left, right);
2368    }
2369    eq FDotDivExp.cevalCalc(VariableEvaluator evaluator) {
2370        CValue left = getLeft().ceval(evaluator);
2371        CValue right = getRight().ceval(evaluator);
2372        if (left.isZero()) {
2373            return type().zeroCValue();
2374        }
2375        return evaluator.evalBinOp(this, left, right);
2376    }
2377   
2378
2379    eq FMulExp.cevalCalc(VariableEvaluator evaluator) {
2380        if (isElementWise() || isArray())
2381          return super.cevalCalc(evaluator);
2382       
2383        FType t = type();
2384        CValue sum = new CValueInteger(0);
2385        CValueArray l = getLeft().ceval(evaluator).array();
2386        CValueArray r = getRight().ceval(evaluator).array();
2387        for (Index i : l.indices())
2388          sum = t.add(sum, t.mul(l.getCell(i), r.getCell(i)));
2389        return sum;
2390    }
2391
2392    syn CValue FBinExp.cevalEval(CValue left, CValue right);
2393    eq FDotAddExp.cevalEval(CValue left, CValue right) = type().add(left, right);
2394    eq FDotSubExp.cevalEval(CValue left, CValue right) = type().sub(left, right);
2395    eq FDotMulExp.cevalEval(CValue left, CValue right) = type().mul(left, right);
2396    eq FDotDivExp.cevalEval(CValue left, CValue right) = type().div(left, right);
2397    eq FDotPowExp.cevalEval(CValue left, CValue right) = type().pow(left, right);
2398   
2399    eq FAndExp.cevalEval(CValue left, CValue right) = type().and(left, right);
2400    eq FOrExp.cevalEval(CValue left, CValue right)  = type().or(left, right);
2401   
2402    syn FType FRelExp.cevalType() = getLeft().type().typePromotion(getRight().type());
2403   
2404    eq FEqExp.cevalEval(CValue left, CValue right)  = cevalType().equ(left, right);
2405    eq FNeqExp.cevalEval(CValue left, CValue right) = cevalType().neq(left, right);
2406    eq FGtExp.cevalEval(CValue left, CValue right)  = cevalType().gt(left, right);
2407    eq FGeqExp.cevalEval(CValue left, CValue right) = cevalType().geq(left, right);
2408    eq FLtExp.cevalEval(CValue left, CValue right)  = cevalType().lt(left, right);
2409    eq FLeqExp.cevalEval(CValue left, CValue right) = cevalType().leq(left, right);
2410   
2411    eq FUnaryExp.cevalCalc(VariableEvaluator evaluator) = evaluator.evalUnOp(this, getFExp().ceval(evaluator));
2412   
2413    syn CValue FUnaryExp.cevalEval(CValue val);
2414    eq InstDerExp.cevalEval(CValue val) { 
2415        throw new ConstantEvaluationException(null, 
2416                 "Doesn't support evaluation of derivatives." + System.lineSeparator() +
2417                 "Replace expression with a variable and provide the value."); 
2418    }
2419   
2420    /**
2421     * Doesn't support evaluation of derivatives due to potential problems with
2422     * use of the Differentiation framework in the instance tree before the transformation steps.
2423     */
2424    eq InstDerExp.cevalCalc(VariableEvaluator evaluator) {
2425        throw new ConstantEvaluationException(null, 
2426                 "Doesn't support evaluation of derivatives." + System.lineSeparator() +
2427                 "Replace expression with a variable and provide the value.");
2428    }
2429   
2430
2431    eq FNegExp.cevalEval(CValue val) = type().neg(val);
2432    eq FNotExp.cevalEval(CValue val) = type().not(val);
2433
2434
2435    eq FIfExp.cevalCalc(VariableEvaluator evaluator) = cevalSelectExp(evaluator).ceval(evaluator);
2436    eq FHomotopyExp.cevalCalc(VariableEvaluator evaluator)   = getActual().ceval(evaluator);
2437    eq FSemiLinearExp.cevalCalc(VariableEvaluator evaluator) = type().mul(getX().ceval(evaluator),cevalSelectExp(evaluator).ceval(evaluator));
2438
2439    syn FExp FIfExp.cevalSelectExp() = cevalSelectExp(defaultVariableEvaluator());
2440    syn FExp FIfExp.cevalSelectExp(VariableEvaluator evaluator) =
2441        getIfExp().ceval(evaluator).booleanValue() ? getThenExp() : getElseExp();
2442    syn FExp FSemiLinearExp.cevalSelectExp(VariableEvaluator evaluator) = type().geq(getX().ceval(evaluator), type().zeroCValue()).booleanValue() ? getPosSlope() : getNegSlope();
2443
2444    eq FRecordConstructor.cevalCalc(VariableEvaluator evaluator) {
2445        CValueRecord res = new CValueRecord((FRecordType) type());
2446        int i = 0;
2447        for (FExp arg : getArgs())
2448          res.setMember(i++, arg.ceval(evaluator));
2449        return res;
2450    }
2451
2452    eq InstRecordConstructor.cevalCalc(VariableEvaluator evaluator) {
2453        CValueRecord res = new CValueRecord((FRecordType) type());
2454        int i = 0;
2455        for (InstComponentDecl icd : getRecord().myInstClassDecl().allInstComponentDecls()) {
2456            CValue val;
2457            if (icd.isModifiable()) {
2458                val = getArg(i).getFExp().ceval(evaluator);
2459            } else {
2460                val = icd.ceval(evaluator);
2461            }
2462            res.setMember(i++, val);
2463        }
2464        return res;
2465    }
2466   
2467    eq FComponentExp.cevalCalc(VariableEvaluator evaluator) = getFExp().ceval().component(getName());
2468   
2469    public CValue CValue.component(String name) {
2470        return CValue.UNKNOWN;
2471    }
2472   
2473    public CValue CValueRecord.component(String name) {
2474        return getMember(name);
2475    }
2476   
2477    eq FEndExp.cevalCalc(VariableEvaluator evaluator) = mySize().ceval(evaluator, 0);
2478    eq FNdimsExp.cevalCalc(VariableEvaluator evaluator) = new CValueInteger(getFExp().ndims());
2479   
2480    eq FSubscriptedExp.cevalCalc(VariableEvaluator evaluator) {
2481        Index i = getFArraySubscripts().createIndex(evaluator);
2482        return getFExp().ceval(evaluator, i).getCell(i);
2483    }
2484
2485    eq FCardinality.cevalCalc(VariableEvaluator evaluator) {
2486        final int v = getFExp().cardinalityValue();
2487        return (v <= 0) ? CValue.UNKNOWN : new CValueInteger(v);
2488    }
2489
2490    eq FDecouple.cevalCalc(VariableEvaluator evaluator) = getFExp().ceval(evaluator);
2491
2492    eq FConnectionsOp.cevalCalc(VariableEvaluator evaluator) {
2493        throw new ConstantEvaluationException();
2494    }
2495    eq FConnBoolOp.cevalCalc(VariableEvaluator evaluator) {
2496        if (connectionGraph != null && connectionGraph.builtTreesDone()) 
2497          return new CValueBoolean(cevalFromGraph());
2498        else
2499          throw new ConstantEvaluationNotReadyException();
2500    }
2501
2502    syn boolean FConnBoolOp.cevalFromGraph();
2503    eq FConnIsRoot.cevalFromGraph() = connectionGraph.ops(getA()).isRoot;
2504    eq FConnRooted.cevalFromGraph() = connectionGraph.ops(getA()).rooted;
2505
2506    eq FTerminate.cevalCalc(VariableEvaluator evaluator) {
2507        throw new ConstantEvaluationException();
2508    }
2509    eq FReinit.cevalCalc(VariableEvaluator evaluator) {
2510        throw new ConstantEvaluationException();
2511    }
2512    eq FAssert.cevalCalc(VariableEvaluator evaluator) {
2513        throw new ConstantEvaluationException();
2514    }
2515
2516    eq FDelayExp.cevalCalc(VariableEvaluator evaluator) = getFExp().ceval(evaluator);
2517    eq FSpatialDistExp.cevalCalc(VariableEvaluator evaluator) = evaluate(evaluator)[0];
2518   
2519    public CValue[] FSpatialDistExp.evaluate(VariableEvaluator evaluator) {
2520        CValue[] res = new CValue[2];
2521        CValueArray vals = getInitialValues().ceval(evaluator).array();
2522        if (getPositiveVelocity().ceval(evaluator).booleanValue()) {
2523            res[1] = vals.getCell(vals.values.length-1);
2524            res[0] = vals.getCell(0);
2525        } else {
2526            res[0] = vals.getCell(vals.values.length-1);
2527            res[1] = vals.getCell(0);
2528        }
2529        return res;
2530    }
2531   
2532    /**
2533     * The connections graph to use when constat evaluating a Connections.x() operator with boolean result.
2534     */
2535    protected OverconstrainedConnectionGraph FConnBoolOp.connectionGraph = null;
2536
2537    eq FSizeExp.cevalCalc(VariableEvaluator evaluator) =
2538            getFExp().size().ceval(evaluator, dimension());
2539    eq FUnknownSizeExp.cevalCalc(VariableEvaluator evaluator) =
2540            inFunction() ? getFExp().cevalCalc(evaluator).size().ceval(evaluator, dimension()) : CValue.UNKNOWN;
2541   
2542    public CValue Size.ceval(VariableEvaluator evaluator, int d) {
2543        int s = get(d);
2544        return (s == Size.UNKNOWN) ? CValue.UNKNOWN : new CValueInteger(s);
2545    }
2546
2547    eq FMinMaxExp.cevalCalc(VariableEvaluator evaluator) {
2548        if (hasY()) {
2549          CValue x = getX().ceval(evaluator);
2550          CValue y = getY().ceval(evaluator);
2551          boolean selectX = type().lt(x, y).booleanValue() ^ !selectLesser();
2552          return selectX ? x : y;
2553        } else {
2554            if (getX().size().evaluated().isUnknown())
2555                return CValue.UNKNOWN;
2556          Iterator<FExp> it = getX().getArray().iteratorFExp();
2557          boolean less = selectLesser();
2558          CValue sel = it.next().ceval(evaluator);
2559          while (it.hasNext()) {
2560              CValue val = it.next().ceval(evaluator);
2561              if (type().lt(val, sel).booleanValue() ^ !less)
2562                  sel = val;
2563          }
2564          return sel;
2565        }
2566    }
2567
2568    eq FReductionExp.cevalCalc(VariableEvaluator evaluator) {
2569        if (getFExp().size().evaluated().isUnknown())
2570            return CValue.UNKNOWN;
2571        Iterator<FExp> it = getFExp().getArray().iteratorFExp();
2572        CValue value = reduceStartValue();
2573        while (it.hasNext())
2574          value = reduceOperation(value, it.next().ceval(evaluator));
2575        return value;
2576    }
2577
2578    syn CValue FReductionExp.reduceStartValue();
2579    eq FSumExp.reduceStartValue()     = type().createCValue(0);
2580    eq FProductExp.reduceStartValue() = type().createCValue(1);
2581
2582    syn CValue FBuiltInFunctionCall.scalarReduceStartValue() = CValue.UNKNOWN;
2583    eq FSumExp.scalarReduceStartValue()     = type().createCValueScalar(0);
2584    eq FProductExp.scalarReduceStartValue() = type().createCValueScalar(1);
2585    eq FMaxExp.scalarReduceStartValue()     = type().limitCValueScalar(false);
2586    eq FMinExp.scalarReduceStartValue()     = type().limitCValueScalar(true);
2587
2588    syn CValue FReductionExp.reduceOperation(CValue leftValue, CValue rightValue);
2589    eq FSumExp.reduceOperation(CValue leftValue, CValue rightValue)     = type().add(leftValue, rightValue);
2590    eq FProductExp.reduceOperation(CValue leftValue, CValue rightValue) = type().mul(leftValue, rightValue);
2591
2592
2593    eq FNoEventExp.cevalCalc(VariableEvaluator evaluator) = getFExp().ceval(evaluator);
2594    eq FSmoothExp.cevalCalc(VariableEvaluator evaluator)  = getFExp().ceval(evaluator);
2595    eq FLoadResource.cevalCalc(VariableEvaluator evaluator) {
2596        String arg = getFExp().ceval(evaluator).stringValue();
2597        if (!new File(arg).isAbsolute())
2598            arg = URIResolver.DEFAULT.resolve(this, arg).replace("\\", "\\\\");
2599        return new CValueString(arg);
2600    }
2601
2602    eq FEdgeExp.cevalCalc(VariableEvaluator evaluator)    = variability().constantVariability() ? CValueBoolean.FALSE : CValue.UNKNOWN;
2603    eq FChangeExp.cevalCalc(VariableEvaluator evaluator)  = variability().constantVariability() ? CValueBoolean.FALSE : CValue.UNKNOWN;
2604    eq FSampleExp.cevalCalc(VariableEvaluator evaluator)  = CValue.UNKNOWN;
2605
2606    /** Decides what initial() is currently evaluated to. */
2607    private static CValue FInitialExp.evaluationValue = CValueBoolean.FALSE;
2608
2609    /** Set the value for initial() to evaluate to. */
2610    public static void FInitialExp.setIsInitial(boolean value) {
2611          evaluationValue = new CValueBoolean(value);
2612    }
2613
2614    /** Set if constant evaluation should consider simulation to be during initialization or not. */
2615    public void FClass.setIsInitial(boolean initial) {
2616          FInitialExp.setIsInitial(initial);
2617    }
2618
2619    eq FInitialExp.cevalCalc(VariableEvaluator evaluator)  = evaluationValue;
2620    eq FTerminalExp.cevalCalc(VariableEvaluator evaluator) = CValueBoolean.FALSE;
2621
2622    syn boolean FMinMaxExp.selectLesser();
2623    eq FMinExp.selectLesser() = true;
2624    eq FMaxExp.selectLesser() = false;
2625
2626    eq FRealLitExp.cevalCalc(VariableEvaluator evaluator)         = new CValueReal(getValue());
2627    eq FIntegerLitExp.cevalCalc(VariableEvaluator evaluator)      = new CValueInteger(getValue());
2628    eq FBooleanLitExpTrue.cevalCalc(VariableEvaluator evaluator)  = new CValueBoolean(true);
2629    eq FBooleanLitExpFalse.cevalCalc(VariableEvaluator evaluator) = new CValueBoolean(false);
2630    eq FStringLitExp.cevalCalc(VariableEvaluator evaluator)       = new CValueString(unEscape());
2631    eq FEnumLitExp.cevalCalc(VariableEvaluator evaluator)         = new CValueEnum(type(), getValue());
2632
2633    syn CValue CommonAccess.unknownCValue() = new CValueUnknownAccess(name());
2634
2635    syn CValue CommonAccess.ceval(VariableEvaluator evaluator);
2636    eq FAccess.ceval(VariableEvaluator evaluator) {
2637        boolean func = inFunction();
2638        FAbstractVariable var = myFV();
2639        if (var != null && !var.isUnknown()) {
2640            Index i = Index.NULL;
2641            if (var.ndims() > 0 && hasFArraySubscripts()) {
2642                i = getFArraySubscripts().createIndex(evaluator);
2643            }
2644            if (i != Index.NULL) {
2645                if(var.inRecord()) {
2646                    CValue cevalRecordMember = cevalRecordMember(evaluator, this);
2647                    if (cevalRecordMember.isUnknown()) {
2648                        return CValue.UNKNOWN; 
2649                    } else {
2650                        return cevalRecordMember.getCell(i);
2651                    }
2652                } else {
2653                    return evaluator.ceval(var, i);
2654                }
2655            } else {
2656                return var.inRecord() ? cevalRecordMember(evaluator, this) : evaluator.ceval(var);
2657            }
2658        } else {
2659            return unknownCValue();
2660        }
2661    }
2662
2663    /**
2664     * Perform constant evaluation of an access to a record member.
2665     */
2666    syn CValue FAccess.cevalRecordMember(VariableEvaluator evaluator, FAccess name) {
2667        if (name.numDots() < 1)
2668          return CValue.UNKNOWN;
2669        String last = name.lastActualPartName();
2670        FAccess prefix = name.copyPrefix();
2671        prefix.parent = this;
2672        FAbstractVariable var = prefix.myFV();
2673        CValue res = var.inRecord() ? cevalRecordMember(evaluator, prefix) : evaluator.ceval(var);
2674        if (res.isUnknown()) return CValue.UNKNOWN;
2675        if (prefix.hasFArraySubscripts())
2676          res = res.getCell(prefix.getFArraySubscripts().createIndex(evaluator));
2677        if (res.isUnknown()) return CValue.UNKNOWN;
2678        return res.record().getMember(last);
2679    }
2680
2681    eq CommonAccessExp.cevalCalc(VariableEvaluator evaluator) = evaluator.cevalUse(this);
2682   
2683    syn CValue CommonAccessExp.cevalUse(VariableEvaluator evaluator) = getAccess().ceval(evaluator);
2684    eq FAbstractDerExp.cevalUse(VariableEvaluator evaluator) {
2685        if (getFAccess().variability().discreteOrLess())
2686            return new CValueInteger(0);
2687        FAbstractVariable decl = myFV();
2688        return decl == null ? CValue.UNKNOWN : evaluator.ceval(decl);
2689    }
2690    eq FPreExp.cevalUse(VariableEvaluator evaluator) {
2691        if (variability().constantVariability())
2692            return super.cevalUse(evaluator);
2693        FAbstractVariable decl = myFV();
2694        return decl == null ? CValue.UNKNOWN : evaluator.ceval(decl);
2695    }
2696   
2697   
2698    syn CValue InstAccess.ceval(VariableEvaluator evaluator)          = ceval(evaluator, Index.NULL);
2699    syn CValue InstAccess.ceval(VariableEvaluator evaluator, Index i) = unknownCValue();
2700    eq InstDot.ceval(VariableEvaluator evaluator, Index i)            = getLastInstAccess().ceval(evaluator, i);
2701    eq InstGlobalAccess.ceval(VariableEvaluator evaluator, Index i)   = getInstAccess().ceval(evaluator, i);
2702    eq InstNamedAccess.ceval(VariableEvaluator evaluator, Index i) {
2703        CValue res = unknownCValue();
2704        if (myInstComponentDecl().isAssignable()) {
2705          Index iHere = Index.NULL;
2706          InstComponentDecl var = myInstComponentDecl();
2707         
2708          if (isSlice()) {
2709              FArraySubscripts fas = getFArraySubscripts();
2710              iHere = fas.createIndex(evaluator);
2711              i = iHere.expand(i);
2712          }
2713         
2714          if (shouldCevalThroughParent(var)) {
2715              res = cevalRecordMember(evaluator, this);
2716              if (i != Index.NULL)
2717                  res = res.getCell(i);
2718              return res;
2719          } else {
2720              res = evaluator.ceval(var, i);
2721          }
2722          if (iHere != Index.NULL)
2723              res = res.getCell(iHere);
2724        } else if (myInstClassDecl().isEnum()) {
2725            res = new CValueInteger(myInstClassDecl().enumLiterals().size());
2726        } else if (myInstClassDecl().isBoolean()) {
2727            res = new CValueInteger(2);
2728        }
2729        return res;
2730    }
2731
2732    /**
2733     * Check if constant evaluation should go through surrounding record.
2734     */
2735    protected boolean InstNamedAccess.shouldCevalThroughParent(InstComponentDecl var) {
2736        if (!var.inRecord())
2737            return false;
2738        if (!var.inFunction()) 
2739            return !var.hasBindingFExp() && var.hasParentRecordWithBindingExp();
2740        if (containingInstComponent() == var.containingInstComponent())
2741            return false;
2742        InstAccess first = getTopInstAccess().getFirstInstAccess();
2743        return !first.myInstComponentDecl().evaluationValue(defaultVariableEvaluator()).isUnknown();
2744    }
2745
2746    /**
2747     * Check if there is a parent record that has a binding expression.
2748     */
2749    inh boolean InstComponentDecl.hasParentRecordWithBindingExp();
2750    eq Root.getChild().hasParentRecordWithBindingExp()           = false;
2751    eq InstBaseNode.getChild().hasParentRecordWithBindingExp()   = false;
2752    eq InstAssignable.getChild().hasParentRecordWithBindingExp() = 
2753        isRecord() && (hasBindingFExp() || hasParentRecordWithBindingExp());
2754
2755    /**
2756     * Perform constant evaluation of an access to a record member.
2757     */
2758    inh CValue InstAccess.cevalRecordMember(VariableEvaluator evaluator, InstNamedAccess access);
2759    eq BaseNode.getChild().cevalRecordMember(VariableEvaluator evaluator, InstNamedAccess access)          = 
2760        access.myInstComponentDecl().cevalParentRecord(evaluator).record().getMember(access.getID());
2761    eq InstDot.getInstAccess(int i).cevalRecordMember(VariableEvaluator evaluator, InstNamedAccess access) = 
2762        (i == 0) ? cevalRecordMember(evaluator, access) : getInstAccess(i - 1).ceval(evaluator).record().getMember(access.getID());
2763
2764    /**
2765     * Perform constant evaluation of a record member.
2766     */
2767    inh CValue InstComponentDecl.cevalParentRecord(VariableEvaluator evaluator);
2768    eq Root.getChild().cevalParentRecord(VariableEvaluator evaluator)         = CValue.UNKNOWN;
2769    eq InstBaseNode.getChild().cevalParentRecord(VariableEvaluator evaluator) = CValue.UNKNOWN;
2770    eq InstRecord.getChild().cevalParentRecord(VariableEvaluator evaluator)   = 
2771        hasParentRecordWithBindingExp() ? cevalParentRecord(evaluator).record().getMember(name()) : ceval(evaluator);
2772    eq InstArrayComponentDecl.getChild().cevalParentRecord(VariableEvaluator evaluator) {
2773        CValue v = cevalParentRecord(evaluator);
2774        return isArray() ? v : v.getCell(myIndex());
2775    }
2776
2777    // TODO: if caching, use cevalFunction() instead
2778    eq FFunctionCall.cevalCalc(VariableEvaluator evaluator)    = evaluate(evaluator)[0];
2779    eq InstFunctionCall.cevalCalc(VariableEvaluator evaluator) = hasOutputs() ? evaluate(evaluator)[0] : CValue.UNKNOWN;
2780
2781    eq FAbsExp.cevalCalc(VariableEvaluator evaluator)  = type().abs(getFExp().ceval(evaluator));
2782    eq FSignExp.cevalCalc(VariableEvaluator evaluator) = type().sign(getFExp().ceval(evaluator));
2783    eq FSqrtExp.cevalCalc(VariableEvaluator evaluator)  = new CValueReal(StrictMath.sqrt(getFExp().ceval(evaluator).realValue()));
2784    eq FEnumIntegerExp.cevalCalc(VariableEvaluator evaluator) = getFExp().ceval(evaluator).convertInteger();
2785    eq FStringExp.cevalCalc(VariableEvaluator evaluator) {
2786        Object value;
2787        if (getValue().type().isReal())
2788          value = getValue().ceval(evaluator).realValue();
2789        else if (getValue().type().isInteger())
2790          value = getValue().ceval(evaluator).intValue();
2791        else if (getValue().type().isBoolean() || getValue().type().isEnum())
2792          value = getValue().ceval(evaluator).stringExpValue();
2793        else
2794          return CValue.UNKNOWN;
2795        return new CValueString(String.format((Locale) null, formatString(), value));
2796    }
2797    eq FGetInstanceName.cevalCalc(VariableEvaluator evaluator) = new CValueString(calcInstanceName());
2798
2799    /**
2800     * Calculate the value of a getInstanceName() call.
2801     */
2802    inh String FGetInstanceName.calcInstanceName();
2803    eq FClass.getChild().calcInstanceName() {
2804        throw new UnsupportedOperationException("The getInstanceName() operator is not allowed in the flat tree.");
2805    }
2806
2807    // TODO: support format args
2808    syn String FStringExp.formatString() = "%" + formatFlags() + formatWidth() + formatPrecision() + formatSpecifier();
2809
2810    syn String FStringExp.formatWidth()     = minimumLength() > 0 ? String.valueOf(minimumLength()) : "";
2811    syn String FStringExp.formatFlags()     = leftJustified() && minimumLength() > 0 ? "-" : "";
2812    syn String FStringExp.formatPrecision() = getValue().type().isReal() ? "." + significantDigits() : "";
2813    syn String FStringExp.formatSpecifier() = getValue().type().formatSpecifier();
2814    syn int FStringExp.minimumLength()     = hasMinimumLength() ? getMinimumLength().ceval().intValue() : 0;
2815    syn boolean FStringExp.leftJustified() = hasLeftJustified() ? getLeftJustified().ceval().booleanValue() : true;
2816    syn int FStringExp.significantDigits() = hasSignificantDigits() ? getSignificantDigits().ceval().intValue() : DEFAULT_PRECISION;
2817    syn String FType.formatSpecifier() {
2818        throw new UnsupportedOperationException();
2819    }
2820    eq FRealType.formatSpecifier()    = "g";
2821    eq FIntegerType.formatSpecifier() = "d";
2822    eq FBooleanType.formatSpecifier() = "s";
2823    eq FEnumType.formatSpecifier()    = "s";
2824    public static final int FStringExp.DEFAULT_PRECISION = 6;
2825
2826    eq FDivFuncExp.cevalCalc(VariableEvaluator evaluator)         = type().truncToZero(type().div(getX().ceval(evaluator), getY().ceval(evaluator)));
2827    eq FModFuncExp.cevalCalc(VariableEvaluator evaluator)         = type().sub(getX().ceval(evaluator), type().mul(type().div(getX().ceval(evaluator), getY().ceval(evaluator)).convertInteger(),    getY().ceval(evaluator)));
2828    eq FRemFuncExp.cevalCalc(VariableEvaluator evaluator)         = type().sub(getX().ceval(evaluator), type().mul(type().truncToZero(type().div(getX().ceval(evaluator), getY().ceval(evaluator))), getY().ceval(evaluator)));
2829    eq FCeilFuncExp.cevalCalc(VariableEvaluator evaluator)        = type().ceil(getX().ceval(evaluator));
2830    eq FFloorFuncExp.cevalCalc(VariableEvaluator evaluator)       = getX().ceval(evaluator).convertInteger().convertReal();
2831    eq FIntegerFuncExp.cevalCalc(VariableEvaluator evaluator)     = getX().ceval(evaluator).convertInteger();
2832
2833    eq FSinExp.cevalCalc(VariableEvaluator evaluator)   = new CValueReal(StrictMath.sin(getFExp().ceval(evaluator).realValue()));
2834    eq FCosExp.cevalCalc(VariableEvaluator evaluator)   = new CValueReal(StrictMath.cos(getFExp().ceval(evaluator).realValue()));
2835    eq FTanExp.cevalCalc(VariableEvaluator evaluator)   = new CValueReal(StrictMath.tan(getFExp().ceval(evaluator).realValue()));
2836    eq FAsinExp.cevalCalc(VariableEvaluator evaluator)  = new CValueReal(StrictMath.asin(getFExp().ceval(evaluator).realValue()));
2837    eq FAcosExp.cevalCalc(VariableEvaluator evaluator)  = new CValueReal(StrictMath.acos(getFExp().ceval(evaluator).realValue()));
2838    eq FAtanExp.cevalCalc(VariableEvaluator evaluator)  = new CValueReal(StrictMath.atan(getFExp().ceval(evaluator).realValue()));
2839    eq FAtan2Exp.cevalCalc(VariableEvaluator evaluator) = new CValueReal(StrictMath.atan2(getFExp().ceval(evaluator).realValue(),
2840                                                               getY().ceval(evaluator).realValue()));
2841    eq FSinhExp.cevalCalc(VariableEvaluator evaluator)  = new CValueReal(StrictMath.sinh(getFExp().ceval(evaluator).realValue()));
2842    eq FCoshExp.cevalCalc(VariableEvaluator evaluator)  = new CValueReal(StrictMath.cosh(getFExp().ceval(evaluator).realValue()));
2843    eq FTanhExp.cevalCalc(VariableEvaluator evaluator)  = new CValueReal(StrictMath.tanh(getFExp().ceval(evaluator).realValue()));
2844    eq FExpExp.cevalCalc(VariableEvaluator evaluator)   = new CValueReal(StrictMath.exp(getFExp().ceval(evaluator).realValue()));
2845    eq FLogExp.cevalCalc(VariableEvaluator evaluator)   = new CValueReal(StrictMath.log(getFExp().ceval(evaluator).realValue()));
2846    eq FLog10Exp.cevalCalc(VariableEvaluator evaluator) = new CValueReal(StrictMath.log10(getFExp().ceval(evaluator).realValue()));
2847
2848    eq FExInStream.cevalCalc(VariableEvaluator evaluator) {
2849        int n = 0;
2850        for (InStreamPart cont : contributors()) {
2851            n++;
2852            break;
2853        }
2854        if (n == 0) {
2855            return getDefault().ceval(evaluator);
2856        } else if (n == 1) {
2857            return contributors().iterator().next().stream.ceval(evaluator);
2858        } else {
2859            double eps = -1.0;
2860            double val = 0.0;
2861            double sum = 0.0;
2862            double div = 0.0;
2863            for (InStreamPart cont : contributors()) {
2864                double flow = cont.flow.ceval(evaluator).realValue();
2865                if (!cont.outside) {
2866                    flow = -flow;
2867                }
2868                if (eps < 0.0) {
2869                    eps = getEps().ceval(evaluator).realValue();
2870                }
2871                flow = Math.max(flow, eps);
2872                sum += flow * cont.stream.ceval(evaluator).realValue();
2873                div += flow;
2874            }
2875            return new CValueReal(sum / div);
2876        }
2877    }
2878
2879    eq FScalarExp.cevalCalc(VariableEvaluator evaluator) = getFExp().ceval(evaluator).array().getCell(0);
2880
2881    syn CValue FSubscript.ceval() = ceval(defaultVariableEvaluator());
2882        syn CValue FSubscript.ceval(VariableEvaluator evaluator) = CValue.UNSUPPORTED;
2883        eq FExpSubscript.ceval(VariableEvaluator evaluator)      = getFExp().ceval(evaluator);
2884        eq FIntegerSubscript.ceval(VariableEvaluator evaluator)  = new CValueInteger(getValue());
2885       
2886        syn int FSubscript.value()   = ceval(defaultVariableEvaluator()).intValue();
2887        eq FIntegerSubscript.value() = getValue();
2888       
2889    public int Subscript.value(VariableEvaluator evaluator);
2890    public int FSubscript.value(VariableEvaluator evaluator) { return ceval(evaluator).intValue();}
2891    public int IntegerSubscript.value(VariableEvaluator evaluator) { return value();}
2892
2893    syn CValue InstComponentDecl.ceval() = ceval(defaultVariableEvaluator());
2894        syn CValue InstComponentDecl.ceval(VariableEvaluator evaluator) = 
2895                (evaluationValue == null) ? CValue.UNKNOWN : evaluationValue;
2896    syn CValue InstComponentDecl.ceval(VariableEvaluator evaluator, Index i) = CValue.UNKNOWN;
2897
2898        /**
2899         * Evaluation of a assignable instance node located in the instance
2900         * AST.
2901         *
2902         * In some situations, expressions are evaluated in the instance AST.
2903         * Such expressions are then instantiated, but not yet flattened. As a
2904         * consequence, identifiers in expressions refers to InstAssignable nodes,
2905         * and accordingly, it it necessary to compute the constant value
2906         * corresponding to an InstAssignable node. If the assignable is a
2907         * constant or a parameter, and if it has a binding expression, then
2908         * a corresponding CValue object is returned, otherwise, CValueUnknown
2909         * is returned.
2910         *
2911         * @return The constant value.
2912         */
2913        eq InstAssignable.ceval(VariableEvaluator evaluator) = ceval(evaluator, Index.NULL);
2914       
2915
2916    /**
2917     * Evaluation of a assignable instance node located in the instance
2918     * AST. Evaluates a specific cell if this assignable is an array.
2919     *
2920     * If assignable is not an array, <code>i</code> should be Index.NULL.
2921     * 
2922     * In some situations, expressions are evaluated in the instance AST.
2923     * Such expressions are then instantiated, but not yet flattened. As a
2924     * consequence, identifiers in expressions refers to InstAssignable nodes,
2925     * and accordingly, it it necessary to compute the constant value
2926     * corresponding to an InstAssignable node. If the assignable is a
2927     * constant or a parameter, and if it has a binding expression, then
2928     * a corresponding CValue object is returned, otherwise, CValueUnknown
2929     * is returned. If the variable has <code>evaluationValue</code> set,
2930     * then that value is always returned.
2931     *
2932     * Outside of functions, the calculated value is cached.
2933     *
2934     * @return The constant value.
2935     */
2936    eq InstAssignable.ceval(VariableEvaluator evaluator, Index i) {
2937        CValue val = CValue.UNKNOWN;
2938        if (hasEvaluationValue(evaluator)) {
2939            val = evaluationValue(evaluator);
2940        } else if ((variability().fixedParameterOrLess() || (inFunction() && !isInput())) && !isForIndex()) {
2941            boolean func = inFunction();
2942            i = func ? i : Index.NULL;
2943            if (hasBindingFExp()) {
2944                FExp bexp = getBindingFExp();
2945                if (!bexp.type().isUnknown())
2946                    val = bexp.ceval(evaluator, i);
2947            } else if ((!func && !inRecordDecl()) || isRecord()) {
2948                val = cevalNoBExp(evaluator, i);
2949            }
2950            if (!func) {
2951                setEvaluationValue(evaluator, val);
2952            }
2953        }
2954        return val;
2955    }
2956   
2957    eq InstExternalObject.ceval(VariableEvaluator evaluator, Index i) {
2958        CValue val = super.ceval(evaluator, i);
2959        val.markExternalObject(qualifiedName());
2960        return val;
2961    }
2962   
2963    syn CValue InstAssignable.cevalNoBExp(VariableEvaluator evaluator, Index i) {
2964        CValue val = startAttributeCValue(evaluator);
2965        if (i != Index.NULL) 
2966            val = val.getCell(i);
2967        if ((isInteger() || isReal() || isEnum()) && !val.isUnknown()) {
2968            try {
2969                CValue min = minAttributeCValue(evaluator);
2970                if (i != Index.NULL) 
2971                    min = min.getCell(i);
2972                CValue max = maxAttributeCValue(evaluator);
2973                if (i != Index.NULL) 
2974                    max = max.getCell(i);
2975                val =  val.constrainWithin(min, max);
2976            } catch (ConstantEvaluationException e) {}
2977        }
2978        return val;
2979    }
2980   
2981    eq InstRecord.cevalNoBExp(VariableEvaluator evaluator, Index i) {
2982        if (isArray()) {
2983            if (size().isUnknown()) {
2984                return CValue.UNKNOWN;
2985            }
2986            CValueArray val = new CValueArray(size());
2987            if (size().numElements() > 0) {
2988                cevalNoBExpArray(evaluator, this, val, ndims());
2989            }
2990            return i == Index.NULL ? val : val.getCell(i);
2991        } else {
2992            return cevalNoBExpCell(evaluator, allInstComponentDecls());
2993        }
2994    }
2995
2996    eq InstExternalObject.cevalNoBExp(VariableEvaluator evaluator, Index i) = CValue.UNKNOWN;
2997
2998    public void InstComponentDecl.cevalNoBExpArray(VariableEvaluator evaluator, InstRecord top, CValueArray a, int ndims) {
2999        if (ndims > 0) {
3000            for (InstComponentDecl icd : allInstComponentDecls()) {
3001                icd.cevalNoBExpArray(evaluator, top, a, ndims-1);
3002            }
3003        } else {
3004            a.addCell(top.cevalNoBExpCell(evaluator, allInstComponentDecls()));
3005        }
3006    }
3007   
3008    syn CValue InstRecord.cevalNoBExpCell(VariableEvaluator evaluator, Iterable<InstComponentDecl> icds) {
3009        CValueRecord rec = new CValueRecord(myInstClass().recordType());
3010        for (InstComponentDecl icd : icds) {
3011            rec.setMember(icd.name(), icd.ceval(evaluator));
3012        }
3013        return rec;
3014    }
3015
3016    // Can never be an array - assume i == Index.NULL
3017    eq InstEnumLiteral.ceval(VariableEvaluator evaluator, Index i) = new CValueEnum(type(), myIndex());
3018
3019
3020    /**
3021     * Find and evaluate the "start" attribute. If it is not found, use default value.
3022     */
3023    syn CValue InstComponentDecl.startAttributeCValue(VariableEvaluator evaluator)  = CValue.UNKNOWN;
3024    syn lazy CValue InstPrimitive.startAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.START);
3025
3026    /**
3027     * Find and evaluate the "fixed" attribute. If it is not found, use default value.
3028     */
3029    syn CValue InstComponentDecl.fixedAttributeCValue() = fixedAttributeCValue(defaultVariableEvaluator());
3030    syn CValue InstComponentDecl.fixedAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.FIXED);
3031
3032    /**
3033     * Find and evaluate the "quantity" attribute. If it is not found, use default value.
3034     */
3035    syn CValue InstComponentDecl.quantityAttributeCValue() = quantityAttributeCValue(defaultVariableEvaluator());
3036    syn CValue InstComponentDecl.quantityAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.QUANTITY);
3037
3038    /**
3039     * Find and evaluate the "unit" attribute. If it is not found, use default value.
3040     */
3041    syn CValue InstComponentDecl.unitAttributeCValue() = unitAttributeCValue(defaultVariableEvaluator());
3042    syn CValue InstComponentDecl.unitAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.UNIT);
3043
3044    /**
3045     * Find and evaluate the "displayUnit" attribute. If it is not found, use default value.
3046     */
3047    syn CValue InstComponentDecl.displayUnitAttributeCValue() = displayUnitAttributeCValue(defaultVariableEvaluator());
3048    syn CValue InstComponentDecl.displayUnitAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.DISPLAY_UNIT);
3049
3050    /**
3051     * Find and evaluate the "min" attribute. If it is not found, use default value.
3052     */
3053    syn CValue InstComponentDecl.minAttributeCValue() = minAttributeCValue(defaultVariableEvaluator());
3054    syn CValue InstComponentDecl.minAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.MIN);
3055
3056    /**
3057     * Find and evaluate the "max" attribute. If it is not found, use default value.
3058     */
3059    syn CValue InstComponentDecl.maxAttributeCValue() = maxAttributeCValue(defaultVariableEvaluator());
3060    syn CValue InstComponentDecl.maxAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.MAX);
3061
3062    /**
3063     * Find and evaluate the "nominal" attribute. If it is not found, use default value.
3064     */
3065    syn CValue InstComponentDecl.nominalAttributeCValue() = nominalAttributeCValue(defaultVariableEvaluator());
3066    syn CValue InstComponentDecl.nominalAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.NOMINAL);
3067
3068    /**
3069     * Find and evaluate the "stateSelect" attribute. If it is not found, use default value.
3070     */
3071    syn CValue InstComponentDecl.stateSelectAttributeCValue() = stateSelectAttributeCValue(defaultVariableEvaluator());
3072    syn CValue InstComponentDecl.stateSelectAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.STATE_SELECT);
3073
3074    /**
3075     * Find and evaluate the attribute <code>name</code>. If it is not found, use default value.
3076     */
3077    syn CValue InstComponentDecl.attributeCValueGeneric(VariableEvaluator evaluator, String name) = CValue.UNKNOWN;
3078    eq InstAssignable.attributeCValueGeneric(VariableEvaluator evaluator, String name) {
3079       
3080        CValue val = attributeCValueSet(evaluator, name);
3081        if (val != null) {
3082            return val;
3083        }
3084       
3085        CValue res = attributeCValueDefault(name);
3086        if (isArray()) {
3087            res = arrayCValue(res);
3088        }
3089        return res;
3090    }
3091   
3092    syn CValue InstAssignable.attributeCValueSet(VariableEvaluator evaluator, String name) {
3093        for (InstModification im : totalMergedEnvironment()) {
3094            FExp exp = im.findAttribute(name);
3095            if (exp != null) {
3096                CValue val = exp.ceval(evaluator);
3097                if (im.hasEach()) {
3098                    val = arrayCValue(val);
3099                }
3100                return val;
3101            }
3102        }
3103        return null;
3104    }
3105   
3106    syn CValueArray InstAssignable.arrayCValue(CValue val) {
3107        CValueArray array = new CValueArray(size());
3108        for (Index i : indices()) {
3109            array.setCell(i, val);
3110        }
3111        return array;
3112    }
3113   
3114
3115    /**
3116     * Get the default value for attribute <code>name</code> for a given type.
3117     */
3118    syn CValue InstComponentDecl.attributeCValueDefault(String name) = CValue.UNKNOWN;
3119    eq InstPrimitive.attributeCValueDefault(String name) {
3120        if (name.equals(FAttribute.FIXED))
3121            return new CValueBoolean(isConstant() || isParameter() || isString());
3122        CValue res = attributeCValueDefaultMap().get(name);
3123        return (res == null) ? CValue.UNKNOWN : res;
3124    }
3125    eq InstEnum.attributeCValueDefault(String name) {
3126        if (name.equals(FAttribute.START) || name.equals(FAttribute.MIN))
3127            return new CValueEnum(type(), 1);
3128        else if (name.equals(FAttribute.MAX))
3129            return new CValueEnum(type(), -1);
3130        else
3131            return super.attributeCValueDefault(name);
3132    }
3133
3134    private static Map<String,CValue> InstPrimitive.REAL_DEFAULT_ATTRIBUTES = null;
3135    private static Map<String,CValue> InstPrimitive.INTEGER_DEFAULT_ATTRIBUTES = null;
3136    private static Map<String,CValue> InstPrimitive.BOOLEAN_DEFAULT_ATTRIBUTES = null;
3137    private static Map<String,CValue> InstPrimitive.STRING_DEFAULT_ATTRIBUTES = null;
3138    private static Map<String,CValue> InstPrimitive.ENUM_DEFAULT_ATTRIBUTES = null;
3139
3140    protected Map<String,CValue> InstPrimitive.attributeCValueDefaultMap() {
3141        if (REAL_DEFAULT_ATTRIBUTES == null) {
3142            CValue emptyStr = new CValueString("");
3143            Map<String,CValue> real = new HashMap<String,CValue>();
3144            real.put(FAttribute.QUANTITY, emptyStr);
3145            real.put(FAttribute.UNIT, emptyStr);
3146            real.put(FAttribute.DISPLAY_UNIT, emptyStr);
3147            real.put(FAttribute.START, new CValueReal(0.0));
3148            // TODO: add stateSelect, but how to get type?
3149            REAL_DEFAULT_ATTRIBUTES = real;
3150            Map<String,CValue> integer = new HashMap<String,CValue>();
3151            integer.put(FAttribute.QUANTITY, emptyStr);
3152            integer.put(FAttribute.START, new CValueInteger(0));
3153            INTEGER_DEFAULT_ATTRIBUTES = integer;
3154            Map<String,CValue> bool = new HashMap<String,CValue>();
3155            bool.put(FAttribute.QUANTITY, emptyStr);
3156            bool.put(FAttribute.START, CValueBoolean.FALSE);
3157            BOOLEAN_DEFAULT_ATTRIBUTES = bool;
3158            Map<String,CValue> string = new HashMap<String,CValue>();
3159            string.put(FAttribute.QUANTITY, emptyStr);
3160            string.put(FAttribute.START, emptyStr);
3161            STRING_DEFAULT_ATTRIBUTES = string;
3162            Map<String,CValue> enumeration = new HashMap<String,CValue>();
3163            enumeration.put(FAttribute.QUANTITY, emptyStr);
3164            ENUM_DEFAULT_ATTRIBUTES = enumeration;
3165        }
3166        if (isReal())
3167            return REAL_DEFAULT_ATTRIBUTES;
3168        else if (isInteger())
3169            return INTEGER_DEFAULT_ATTRIBUTES;
3170        else if (isBoolean())
3171            return BOOLEAN_DEFAULT_ATTRIBUTES;
3172        else if (isString())
3173            return STRING_DEFAULT_ATTRIBUTES;
3174        else if (isEnum())
3175            return ENUM_DEFAULT_ATTRIBUTES;
3176        throw new UnsupportedOperationException("No default CValue map for " + type());
3177    }
3178
3179    /**
3180     * Find the expression for the attribute <code>name</code>.
3181     */
3182    public FExp InstModification.findAttribute(String name) { 
3183        return null;
3184    }
3185
3186    public FExp InstComponentModification.findAttribute(String name) {
3187        if (getName().name().equals(name) && getInstModification().hasInstValueMod())
3188            return getInstModification().getInstValueMod().instValueMod();
3189        return null;
3190    }
3191
3192
3193        /**
3194         * Constant evaluation of FVariable binding expressions.
3195         *
3196         * If an expression is evaluated in an FClass, then identifiers are
3197         * referencing FVariables. The constant value of an FVariable is computed
3198         * by evaluating the binding expression of the variable, if any. If the
3199         * FVariable is not a constant or a parameter, or if it has no binding
3200         * expressions, then a CValueUnknown object is returned.
3201         *
3202         *  @return The constant value.
3203         */
3204    syn CValue FAbstractVariable.ceval() = ceval(defaultVariableEvaluator());
3205   
3206        syn CValue FAbstractVariable.ceval(VariableEvaluator evaluator) = CValue.UNKNOWN;
3207        eq FFunctionVariable.ceval(VariableEvaluator evaluator)         = evaluationValue(evaluator);
3208        eq FVariable.ceval(VariableEvaluator evaluator)                 = ceval(evaluator, isParameter());
3209        syn CValue FVariable.ceval(VariableEvaluator evaluator, boolean inParameterRecord) {
3210                CValue val;
3211                if (isForIndex())
3212                        val = evaluationValue(evaluator);
3213                else if (hasParameterEquation())
3214                        val = parameterEquation().cevalParameter(evaluator, this);
3215                else if (hasBindingExp())
3216                        val = getBindingExp().ceval(evaluator);
3217                else
3218                        val = defaultCValue(evaluator, inParameterRecord);
3219        if (isReal() && !val.isUnknown()) {
3220            val = val.convertReal();
3221        }
3222                return val;
3223        }
3224   
3225    eq FExternalObjectVariable.ceval(VariableEvaluator evaluator, boolean inParameterRecord) {
3226        CValue val = super.ceval(evaluator, inParameterRecord);
3227        val.markExternalObject(name());
3228        return val;
3229    }
3230   
3231       
3232        /**
3233         * Constant evaluation of FVariable binding expressions.
3234         *
3235         * If an expression is evaluated in an FClass, then identifiers are
3236         * referencing FVariables. The constant value of an FVariable is computed
3237         * by evaluating the binding expression of the variable, if any. If the
3238         * FVariable is not a constant or a parameter, or if it has no binding
3239         * expressions, then a CValueUnknown object is returned.
3240         *
3241         * This version only evaluates a specific cell in an array, and returns
3242         * the value for that specific cell.
3243         *
3244         *  @return The constant value.
3245         */
3246        syn CValue FAbstractVariable.ceval(VariableEvaluator evaluator, Index i) = CValue.UNKNOWN;
3247        eq FFunctionVariable.ceval(VariableEvaluator evaluator, Index i)         = evaluationValue(evaluator).getCell(i);
3248        eq FVariable.ceval(VariableEvaluator evaluator, Index i) {
3249        CValue val;
3250        if (isForIndex())
3251            val = evaluationValue(evaluator);
3252        else if (hasParameterEquation())
3253            val = parameterEquation().cevalParameter(evaluator, this, i);
3254        else if (hasBindingExp())
3255            val = getBindingExp().ceval(evaluator, i);
3256        else
3257            val = startAttributeCValue();
3258        val = val.getCell(i);
3259        if (isReal())
3260            val = val.convertReal();
3261        return val;
3262    }
3263   
3264    eq FExternalObjectVariable.ceval(VariableEvaluator evaluator, Index i) {
3265        CValue val = super.ceval(evaluator, i);
3266        val.markExternalObject(name());
3267        return val;
3268    }
3269
3270  /**
3271   * Constant evaluation of binding equation for dependent parameter.
3272   */
3273  syn CValue FAbstractEquation.cevalParameter(VariableEvaluator evaluator, FVariable fv) = CValue.UNKNOWN;
3274  eq FEquation.cevalParameter(VariableEvaluator evaluator, FVariable fv)                 = getRight().ceval(evaluator);
3275  eq FFunctionCallEquation.cevalParameter(VariableEvaluator evaluator, FVariable fv) {
3276          CValue[] vals = getCall().cevalFunction(evaluator);
3277          for (int i = 0; i < getNumLeft(); i++) {
3278                  CValue res = getLeft(i).extractCValue(vals[i], fv);
3279                  if (res != null)
3280                          return res;
3281          }
3282          return CValue.UNKNOWN;
3283  }
3284 
3285  /**
3286   * Constant evaluation of binding equation for dependent parameter.
3287   */
3288  syn CValue FAbstractEquation.cevalParameter(VariableEvaluator evaluator, FVariable fv, Index i) = CValue.UNKNOWN;
3289  eq FEquation.cevalParameter(VariableEvaluator evaluator, FVariable fv, Index i)                 = getRight().ceval(evaluator, i);
3290 
3291  /**
3292   * Given that <code>val</code> is the value of this use expression,
3293   *        extract the part of it referring to <code>fv</code>,
3294   *        or <code>null</code> if none match.
3295   */
3296  syn CValue FFunctionCallLeft.extractCValue(CValue val, FVariable fv) =
3297          hasFExp() ? getFExp().extractCValue(val, fv) : null;
3298 
3299  /**
3300   * Given that <code>val</code> is the value of this use expression,
3301   *        extract the part of it referring to <code>fv</code>,
3302   *        or <code>null</code> if none match.
3303   */
3304  syn CValue FExp.extractCValue(CValue val, FVariable fv) = null;
3305  eq FAccessExp.extractCValue(CValue val, FVariable fv)    = getFAccess().myFV() == fv ? val : null;
3306  eq FArray.extractCValue(CValue val, FVariable fv) {
3307          CValueArray arr = val.array();
3308          for (Index i : indices()) {
3309                  CValue res = getArray().get(i).extractCValue(arr.getCell(i), fv);
3310                  if (res != null)
3311                          return res;
3312          }
3313          return null;
3314  }
3315  eq FRecordConstructor.extractCValue(CValue val, FVariable fv) {
3316          CValueRecord rec = val.record();
3317          int n = getNumArg();
3318          for (int i = 0; i < n; i++) {
3319                  CValue res = getArg(i).extractCValue(rec.getMember(i), fv);
3320                  if (res != null)
3321                          return res;
3322          }
3323          return null;
3324  }
3325 
3326  /**
3327   * Constant eval for variables without any binding expression, or binding equation.
3328   * Uses the start value for non-records.
3329   */
3330  syn CValue FVariable.defaultCValue(VariableEvaluator evaluator, boolean inParameterRecord) = startAttributeCValue();
3331  eq FRecordVariable.defaultCValue(VariableEvaluator evaluator, boolean inParameterRecord) {
3332          if (isArray()) {
3333                  CValueArray res = new CValueArray(size());
3334                  for (Index i : indices())
3335                          res.setCell(i, defaultCValueCell(evaluator, i, inParameterRecord));
3336                  return res;
3337          } else {
3338                  return defaultCValueCell(evaluator, Index.NULL, inParameterRecord);
3339          }
3340  }
3341 
3342  /**
3343   * Constant eval for variables without any binding expression, or binding equation.
3344   * Uses the start value for non-records.
3345   */
3346  syn CValue FVariable.defaultCValueCell(VariableEvaluator evaluator, Index i, boolean inParameterRecord) = startAttributeCValue();
3347   
3348    private boolean FRecordVariable.circular = false;
3349    eq FRecordVariable.defaultCValueCell(VariableEvaluator evaluator, Index i, boolean inParameterRecord) {
3350        if (circular) {
3351            throw new ConstantEvaluationException(null, "Circular evaluation in record component");
3352        }
3353        circular = true;
3354        try {
3355            CValueRecord res = new CValueRecord((FRecordType) type().scalarType());
3356            FRecordDecl rec = myFRecordDecl();
3357            for (int j = 0, n = rec.getNumFVariable(); j < n; j++) {
3358                FVariable fv = rec.getFVariable(j);
3359                if (inParameterRecord || fv.isParameter() || fv.isRecord())
3360                    res.setMember(j, fv.ceval(evaluator, inParameterRecord));
3361                else
3362                    res.setMember(j, CValue.UNKNOWN);
3363            }
3364            for (FAttribute a : getFAttributes())
3365                a.applyToCValue(evaluator, res, i);
3366            return res;
3367        } finally {
3368            circular = false;
3369        }
3370    }
3371 
3372  /**
3373   * Apply any binding expressions for record members to a record CValue.
3374   */
3375  public void FAttribute.applyToCValue(VariableEvaluator evaluator, CValueRecord rec, Index i) {
3376          if (rec.members().containsKey(name())) {
3377                  int j = rec.members().get(name());
3378                  if (hasValue()) {
3379                          CValue val = getValue().ceval(evaluator);
3380                          if (i != Index.NULL && rec.getMember(j).size().ndims() + i.ndims() == val.size().ndims())
3381                                  val = val.array().getPart(i);
3382                          if (!rec.getMember(j).isUnknown())
3383                                  rec.setMember(j, val);
3384                  } else {
3385                          if (!rec.getMember(j).isUnknown())
3386                                  rec.getMember(j).applyAttributes(getFAttributes(), i);
3387                  }
3388          }
3389  }
3390 
3391  /**
3392   * Apply attributes in attrs to any records in this value.
3393   */
3394  public void CValue.applyAttributes(List<FAttribute> attrs, Index i) {}
3395 
3396  public void CValueArray.applyAttributes(List<FAttribute> attrs, Index i) {
3397          if (values.length > 0 && values[0].isRecord()) 
3398                  for (Index j : indices) 
3399                          getCell(j).applyAttributes(attrs, i.expand(j));
3400  }
3401 
3402  public void CValueRecord.applyAttributes(List<FAttribute> attrs, Index i) {
3403          for (FAttribute a : attrs)
3404                  a.applyToCValue(ASTNode.defaultVariableEvaluator(), this, i);
3405  }
3406 
3407 
3408  /**
3409   * Constant evaluate all dimensions described by expressions.
3410   */
3411  public Size Size.ceval() {
3412      return ceval(ASTNode.defaultVariableEvaluator());
3413  }
3414 
3415  public Size Size.ceval(VariableEvaluator evaluator) {
3416          return this;
3417  }
3418 
3419  public Size MutableSize.ceval(VariableEvaluator evaluator) {
3420          int[] ns = size.clone();
3421          for (int i = 0; i < size.length; i++) 
3422                  if (size[i] == UNKNOWN && exps[i] != null) 
3423                          ns[i] = exps[i].ceval(evaluator).intValue();
3424          return new Size(ns);
3425  }
3426 
3427 
3428  /**
3429   * Check if this node is in a function that is being evaluated.
3430   */
3431  inh boolean FExp.duringFunctionEval();
3432  inh boolean InstNamedAccess.duringFunctionEval();
3433  eq FFunctionDecl.getChild().duringFunctionEval()     = currentEvaluationValues != null;
3434  eq InstBaseClassDecl.getChild().duringFunctionEval() = currentEvaluationValues != null;
3435  eq FClass.getChild().duringFunctionEval()            = false;
3436  eq Root.getChild().duringFunctionEval()              = false;
3437 
3438  /**
3439   * Perform constant evaluation of functions, with caching.
3440   *
3441   * Delegates to {@link #evaluate()};
3442   *
3443   * @return  constant values for the outputs
3444   */
3445  syn CValue[] FAbstractFunctionCall.cevalFunction(VariableEvaluator evaluator) = new CValue[] { ceval(evaluator) };
3446  syn lazy CValue[] FFunctionCall.cevalFunction(VariableEvaluator evaluator)    = evaluate(evaluator);
3447  syn lazy CValue[] InstFunctionCall.cevalFunction(VariableEvaluator evaluator) = evaluate(evaluator);
3448
3449    /**
3450     * Interface for variable declarations in flat and instance trees.
3451     */
3452    public interface CommonVariableDecl {
3453        public void readEvaluationValue(Map<CommonVariableDecl, CValue> map);
3454        public void setEvaluationValue(VariableEvaluator evaluator, CValue val);
3455        public void clearEvaluationValue(VariableEvaluator evaluator);
3456        public void setLocalCachedEvaluationValue(CValue val);
3457        public CValue getLocalCachedEvaluationValue();
3458        public void clearLocalCachedEvaluationValue();
3459        public void resetAfterCeval();
3460        public CValue evaluationValue(VariableEvaluator evaluator);
3461        public CValue ceval();
3462        public CValue ceval(VariableEvaluator evaluator);
3463        public CValue ceval(VariableEvaluator evaluator, Index i);
3464        public String name();
3465        public String qualifiedName();
3466        public Size size();
3467        public boolean isConstant();
3468        public boolean isPackageConstant();
3469        public boolean inSameInstClass(InstNode instNode);
3470        public TypePrefixVariability variability();
3471
3472        // Added for codegeneration when evaluating external functions
3473        public FType   type();
3474        public String  name_C();
3475        public boolean isInput();
3476        public boolean isOutput();
3477       
3478        // Added for type checking
3479        public boolean shouldBeDifferentiated();
3480        public boolean isUnknown();
3481     
3482        public FAbstractVariable asFAbstractVariable();
3483    }
3484   
3485    public boolean FAbstractVariable.isInstClassConstant() { return false;}
3486
3487    public boolean FAbstractVariable.isPackageConstant() { return false;}
3488    public boolean InstComponentDecl.isPackageConstant() { return isConstant() && containingInstClass().isPackage();}
3489   
3490    public boolean FAbstractVariable.inSameInstClass(InstNode instNode) { return false;}
3491    public boolean InstComponentDecl.inSameInstClass(InstNode instNode) {
3492        InstNode classDecl = instNode;
3493        if (!classDecl.isClassDecl()) {
3494                classDecl = classDecl.containingInstClass();
3495        }
3496        InstNode node = containingEntity();
3497        if (node.equals(classDecl)) {
3498                return true;
3499        }
3500        return false;
3501    }
3502   
3503   
3504   
3505    FAbstractVariable implements CommonVariableDecl;
3506    InstComponentDecl implements CommonVariableDecl;
3507   
3508    syn FAbstractVariable FAbstractVariable.asFAbstractVariable() = this;
3509    syn FAbstractVariable InstComponentDecl.asFAbstractVariable() = null;
3510 
3511  syn FExp FAbstractFunctionCall.argument(int i) {
3512          for (FExp e : childFExps())
3513                  if (i-- == 0)
3514                          return e;
3515          return null;
3516  }
3517  eq FFunctionCall.argument(int i)    = getArg(i);
3518  eq InstFunctionCall.argument(int i) = getArg(i).getFExp();
3519
3520  /**
3521   * Perform constant evaluation of functions.
3522   *
3523   * @return  constant values for the outputs
3524   */
3525  public CValue[] FAbstractFunctionCall.evaluate(VariableEvaluator evaluator) {
3526          Map<CommonVariableDecl, CValue> values = new HashMap<CommonVariableDecl, CValue>();
3527          int i = 0;
3528          for (CommonVariableDecl var : myCallInputs()) {
3529                  FExp arg = argument(i++);
3530            if (arg != null) {
3531                values.put(var, arg.ceval(evaluator));
3532            } else {
3533                throw new ConstantEvaluationException();
3534            }
3535          }
3536         
3537          evaluate(evaluator, values);
3538         
3539          CValue[] res = new CValue[myCallOutputs().size()];
3540          i = 0;
3541          for (CommonVariableDecl var : myCallOutputs()) {
3542                  CValue val = values.get(var);
3543                  res[i] = (val == null) ? CValue.UNKNOWN : val;
3544                  i++;
3545          }
3546          return res;
3547  }
3548   
3549   
3550    public void FAbstractFunctionCall.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3551        evaluateCell(evaluator, values);
3552    }
3553   
3554    @Override
3555    public void FVectorFunctionCall.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3556        evaluateVector(evaluator, values);
3557    }
3558   
3559    @Override
3560    public void InstVectorFunctionCall.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3561        evaluateVector(evaluator, values);
3562    }
3563   
3564   
3565    public void FAbstractFunctionCall.evaluateCell(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3566        values.clear();
3567    }
3568   
3569    @Override
3570    public void FAssert.evaluateCell(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3571        boolean val = getTest().ceval().booleanValue();
3572        if (!val && (!hasLevel() || getLevel().ceval().stringValue().equals(LEVEL_ERROR))) {
3573            String msg = "Assertion failed: " + getMsg().ceval().stringValue();
3574            throw new ConstantEvaluationException(null , msg);
3575        }
3576    }
3577   
3578   
3579    @Override
3580    public void FFunctionCall.evaluateCell(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3581        myCommonCallable().evaluate(evaluator, values);
3582    }
3583   
3584    @Override
3585    public void InstFunctionCall.evaluateCell(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3586        myCommonCallable().evaluate(evaluator, values);
3587    }
3588   
3589    @Override
3590    public void FPartialFunctionCall.evaluateCell(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3591        evaluatePartial(values);
3592    }
3593   
3594    @Override
3595    public void InstPartialFunctionCall.evaluateCell(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3596        evaluatePartial(values);
3597    }
3598   
3599   
3600    public void FAbstractFunctionCall.evaluateVector(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3601        Size vectorizedSize = sizeOfOutput(0);
3602        CommonVariableDecl output = myCallOutputs().get(0);
3603        Map<CommonVariableDecl, CValue> input  = new HashMap<CommonVariableDecl, CValue>(values.size());
3604        input.putAll(values);
3605        values.put(output, new CValueArray(vectorizedSize));
3606       
3607        Map<CommonVariableDecl, Boolean> isVectorized = new HashMap<CommonVariableDecl, Boolean>(input.size());
3608        for (CommonVariableDecl cvd : input.keySet()) {
3609            isVectorized.put(cvd, cvd.size().expand(vectorizedSize).equivalent(input.get(cvd).size(), true));
3610        }
3611       
3612        for (Index i : Indices.create(vectorizedSize)) {
3613            Map<CommonVariableDecl, CValue> valuesCell = new HashMap<CommonVariableDecl, CValue>();
3614            for (CommonVariableDecl cvd : input.keySet()) {
3615                if (isVectorized.get(cvd)) {
3616                    valuesCell.put(cvd, input.get(cvd).array().getPart(i));
3617                } else {
3618                    valuesCell.put(cvd, input.get(cvd));
3619                }
3620            }
3621            evaluateCell(evaluator, valuesCell);
3622            CValue val = valuesCell.get(output);
3623            if (val == null) {
3624                val = CValue.UNKNOWN;
3625            }
3626            values.get(output).array().setCell(i, val);
3627        }
3628    }
3629   
3630    public void FAbstractFunctionCall.evaluatePartial(Map<CommonVariableDecl, CValue> values) {
3631        values.put(myCallOutputs().get(0), myCommonCallable().evaluatePartial(values));
3632    }
3633   
3634    public interface CommonCallable {
3635        public void evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values);
3636        public CValue evaluatePartial(Map<CommonVariableDecl, CValue> values);
3637    }
3638   
3639    syn CValue InstClassDecl.evaluatePartial(Map<CommonVariableDecl, CValue> values) = 
3640        CValuePartialFunction.create(this, values);
3641    syn CValue FFunctionDecl.evaluatePartial(Map<CommonVariableDecl, CValue> values) = 
3642        CValuePartialFunction.create(this, values);
3643    syn CValue InstPartialFunction.evaluatePartial(Map<CommonVariableDecl, CValue> values) =
3644        evaluationValue.evaluatePartialFunction(this, values);
3645    syn CValue FFunctionVariable.evaluatePartial(Map<CommonVariableDecl, CValue> values) =
3646        evaluationValue.evaluatePartialFunction(this, values);
3647   
3648    public static Map<CommonVariableDecl, CValue> FFunctionDecl.resetAfterCeval(CommonCallable cc, ASTNode n, Map<CommonVariableDecl, CValue> values) {
3649        Map<CommonVariableDecl, CValue> oldVal = cc.getCurrentEvaluationValues();
3650        cc.setCurrentEvaluationValues(values);
3651        for (CommonVariableDecl cvd : cc.myInputs()) {
3652            cvd.resetAfterCeval();
3653        }
3654        for (CommonVariableDecl cvd : cc.myNonInputs()) {
3655            cvd.resetAfterCeval();
3656        }
3657        n.resetAfterCeval();
3658        if (values != null) {
3659            for (CommonVariableDecl cvd : values.keySet()) {
3660                cvd.setLocalCachedEvaluationValue(values.get(cvd));
3661            }
3662        }
3663        return oldVal;
3664    }
3665   
3666    public void ASTNode.resetAfterCeval() {
3667        for (ASTNode n : this) {
3668            n.resetAfterCeval();
3669        }
3670    }
3671   
3672    public void FFunctionVariable.resetAfterCeval() {
3673        super.resetAfterCeval();
3674        clearLocalCachedEvaluationValue();
3675        size().resetAfterCeval();
3676    }
3677   
3678    public void InstAssignable.resetAfterCeval() {
3679        super.resetAfterCeval();
3680        clearLocalCachedEvaluationValue();
3681        if (hasBindingFExp()) {
3682            myBindingInstExp().resetAfterCeval();
3683        }
3684        size().resetAfterCeval();
3685    }
3686   
3687    public void Size.resetAfterCeval() {
3688       
3689    }
3690   
3691    public void MutableSize.resetAfterCeval() {
3692        for (int i = 0; i < exps.length; i++) {
3693            if (exps[i] != null) {
3694                exps[i].resetAfterCeval();
3695                evaluated[i] = false;
3696                size[i] = Size.UNKNOWN;
3697            }
3698        }
3699    }
3700   
3701   
3702    public void FExp.resetAfterCeval() {
3703        flushAllRecursive();
3704    }
3705
3706    @Override
3707    public void FInitArrayStmt.resetAfterCeval() {
3708        flushAllRecursive();
3709    }
3710
3711    // TODO: reduce code duplication
3712
3713    /**
3714     * Perform constant evaluation of functions.
3715     *
3716     * @param values  constant values for the variables.
3717     *                Should be filled with the values of the inputs.
3718     */
3719    public void FFunctionDecl.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3720        FFunctionDecl.evaluate(evaluator, values, this, getFAlgorithm());
3721    }
3722   
3723    public static void FFunctionDecl.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values, CommonCallable cc, FAlgorithm fab) {
3724        AlgorithmEvaluator algoEvaluator = evaluator.createAlgorithmEvaluator(fab.myOptions(), values);
3725        Map<CommonVariableDecl, CValue> oldVal = FFunctionDecl.resetAfterCeval(cc, fab, values);
3726        try {
3727            for (CommonVariableDecl cvd : cc.myInputs()) {
3728                // Only here because operator record functions does not evaluate default values of inputs
3729                cvd.readEvaluationValue(values);
3730            }
3731            for (CommonVariableDecl cvd : cc.myNonInputs()) {
3732                // Only here because scalar primitives does not have init statements.
3733                cvd.readEvaluationValue(values);
3734            }
3735            if (oldVal == null || algoEvaluator.recursive(cc)) {
3736                fab.getFStatements().evaluateList(algoEvaluator);
3737            }
3738        } catch (ConstantEvaluationException e) {
3739            algoEvaluator.failed(cc, e);
3740        } finally {
3741            FFunctionDecl.resetAfterCeval(cc, fab, oldVal);
3742        }
3743    }
3744   
3745    public void FFunctionVariable.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3746        evaluationValue.evaluateFunction(evaluator, myFCallable(), values);
3747    }
3748   
3749    interface CommonCallable {
3750        public Map<CommonVariableDecl, CValue> getCurrentEvaluationValues();
3751        public void setCurrentEvaluationValues(Map<CommonVariableDecl, CValue> values);
3752    }
3753   
3754    private Map<CommonVariableDecl, CValue> FFunctionDecl.currentEvaluationValues = null;
3755    public Map<CommonVariableDecl, CValue> FFunctionDecl.getCurrentEvaluationValues() { return currentEvaluationValues; }
3756    public void FFunctionDecl.setCurrentEvaluationValues(Map<CommonVariableDecl, CValue> values) { currentEvaluationValues = values; }
3757   
3758    private Map<CommonVariableDecl, CValue> InstBaseClassDecl.currentEvaluationValues = null;
3759    public Map<CommonVariableDecl, CValue> InstBaseClassDecl.getCurrentEvaluationValues() { return currentEvaluationValues; }
3760    public void InstBaseClassDecl.setCurrentEvaluationValues(Map<CommonVariableDecl, CValue> values) { currentEvaluationValues = values; }
3761   
3762    public Map<CommonVariableDecl, CValue> InstNode.getCurrentEvaluationValues() { return null; }
3763    public void InstNode.setCurrentEvaluationValues(Map<CommonVariableDecl, CValue> values) {}
3764   
3765    public Map<CommonVariableDecl, CValue> FFunctionVariable.getCurrentEvaluationValues() { return null; }
3766    public void FFunctionVariable.setCurrentEvaluationValues(Map<CommonVariableDecl, CValue> values) {}
3767   
3768    /**
3769     * Constant-evaluate function with given set of arguments and return value for first output.
3770     *
3771     * @param args  arguments of the function call
3772     */
3773    public CValue InstClassDecl.evaluateFirst(VariableEvaluator evaluator, Iterable<FExp> args) {
3774        Map<CommonVariableDecl, CValue> values = new HashMap<CommonVariableDecl, CValue>();
3775        int i = 0;
3776        for (FExp arg : args) {
3777            if (i < myInputs().size()) {
3778                CommonVariableDecl cvd = myInputs().get(i);
3779                if (cvd.type().typeCompatible(arg.type(), true)) {
3780                    values.put(cvd, arg.ceval(evaluator));
3781                } else {
3782                    InstClassDecl constructor = cvd.type().matchOverloadedConstructor(arg.type());
3783                    ArrayList<FExp> l = new ArrayList<FExp>();
3784                    l.add(arg);
3785                    CValue v = constructor.evaluateFirst(evaluator, l);
3786                    values.put(cvd, v);
3787                }
3788            } else {
3789                throw new ConstantEvaluationException();
3790            }
3791            i++;
3792        }
3793       
3794        evaluate(evaluator, values);
3795       
3796        CValue res = myOutputs().isEmpty() ? null : values.get(myOutputs().get(0));
3797        return (res == null) ? CValue.UNKNOWN : res;
3798    }
3799
3800    /**
3801     * Perform constant evaluation of functions.
3802     *
3803     * @param values  constant values for the variables.
3804     *                Should be filled with the values of the inputs.
3805     */
3806    public void InstClassDecl.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3807        values.clear(); // Make sure evaluation returns CValue.UNKNOWN
3808    }
3809
3810    public void InstSimpleShortClassDecl.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3811       actualInstClass().evaluate(evaluator, values);
3812    }
3813
3814    public void InstLibNode.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3815       actualInstClass().evaluate(evaluator, values);
3816    }
3817
3818    public void InstBaseClassDecl.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3819        // We assume that this class is a function
3820       
3821        FAlgorithm fab = findFunctionAlgorithm();
3822        if (fab == null) {
3823            InstExternal ie = findFunctionExternal();
3824            if (ie == null) {
3825                values.clear();
3826                return;
3827            }
3828            fab = ie.getFAlgorithm();
3829        }
3830       
3831        FFunctionDecl.evaluate(evaluator, values, this, fab);
3832    }
3833   
3834    public void InstPartialFunction.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3835        evaluationValue.evaluateFunction(evaluator, myInstClass(), values);
3836    }
3837   
3838   
3839   
3840    /**
3841     * Read current function evaluation value from map.
3842     *
3843     * If this variable isn't in the map, set to value of binding expression.
3844     */
3845    public void FAbstractVariable.readEvaluationValue(Map<CommonVariableDecl, CValue> map) {
3846        CValue val = map.get(this);
3847        if (val == null) {
3848            val = cevalFunctionBindingExp(ASTNode.defaultVariableEvaluator());
3849        }
3850        if (!isInput()) {
3851            val = val.cached();
3852        }
3853        map.put(this, val);
3854        setLocalCachedEvaluationValue(val);
3855    }
3856
3857    /**
3858     * Read current function evaluation value from map.
3859     *
3860     * If this variable isn't in the map, set to value of binding expression.
3861     */
3862    public void InstComponentDecl.readEvaluationValue(Map<CommonVariableDecl, CValue> map) {
3863        CValue val = map.get(this);
3864        if (val == null) {
3865            val = cevalFunctionBindingExp(ASTNode.defaultVariableEvaluator());
3866        }
3867        if (!isInput()) {
3868            val = val.cached();
3869        }
3870        map.put(this, val);
3871        setLocalCachedEvaluationValue(val);
3872    }
3873   
3874   
3875    protected CValue FAbstractVariable.cevalFunctionBindingExp(VariableEvaluator evaluator) {
3876        return CValue.UNKNOWN;
3877    }
3878
3879    protected CValue FFunctionVariable.cevalFunctionBindingExp(VariableEvaluator evaluator) {
3880        if (hasBindingExp()) {
3881            return getBindingExp().ceval(evaluator);
3882        } else if (isArray()) {
3883            return CValue.UNKNOWN;
3884        } else {
3885            return type().zeroCValue();
3886        }
3887    }
3888
3889    protected CValue InstComponentDecl.cevalFunctionBindingExp(VariableEvaluator evaluator) {
3890        return CValue.UNKNOWN;
3891    }
3892
3893    protected CValue InstAssignable.cevalFunctionBindingExp(VariableEvaluator evaluator) {
3894        return hasBindingFExp() ? myBindingInstExp().ceval(evaluator) : type().zeroCValue();
3895    }
3896
3897    protected CValue InstRecord.cevalFunctionBindingExp(VariableEvaluator evaluator) {
3898        if (hasBindingFExp())
3899            return myBindingInstExp().ceval(evaluator);
3900        FRecordType type = (FRecordType) type().scalarType();
3901        if (isArray()) {
3902            CValueArray res = new CValueArray(size());
3903            int ndims = ndims();
3904            for (InstComponentDecl ch : allInstComponentDecls())
3905                ch.cevalBindingExpForRecordArray(evaluator, type, res, ndims);
3906            return res;
3907        } else {
3908            return cevalBindingExpForRecord(evaluator, type);
3909        }
3910    }
3911
3912    protected void InstComponentDecl.cevalBindingExpForRecordArray(VariableEvaluator evaluator, FRecordType type, CValueArray arr, int ndims) {
3913        throw new UnsupportedOperationException("Only valid for InstArrayComponentDecls.");
3914    }
3915
3916    protected void InstArrayComponentDecl.cevalBindingExpForRecordArray(VariableEvaluator evaluator, FRecordType type, CValueArray arr, int ndims) {
3917        ndims--;
3918        if (ndims > 0) {
3919            for (InstComponentDecl ch : allInstComponentDecls())
3920                ch.cevalBindingExpForRecordArray(evaluator, type, arr, ndims);
3921        } else {
3922            arr.addCell(cevalBindingExpForRecord(evaluator, type));
3923        }
3924    }
3925
3926    protected CValue InstComponentDecl.cevalBindingExpForRecord(VariableEvaluator evaluator, FRecordType type) {
3927        CValueRecord res = new CValueRecord(type);
3928        evaluationValue = res;
3929        for (InstComponentDecl ch : allInstComponentDecls())
3930            res.setMember(ch.name(), ch.cevalFunctionBindingExp(evaluator));
3931        return res;
3932    }
3933
3934    /**
3935     * Set the current evaluation value.
3936     */
3937    public void CommonForIndex.setEvaluationValue(CValue val) {
3938        setEvaluationValue(ASTNode.defaultVariableEvaluator(), val);
3939    }
3940   
3941    /**
3942     * Get the current evaluation value.
3943     */
3944    public CValue CommonForIndex.evaluationValue() {
3945        return evaluationValue(ASTNode.defaultVariableEvaluator());
3946    }
3947   
3948    syn CommonVariableDecl CommonForIndex.myCVD();
3949    eq FForIndex.myCVD() = getFVariable();
3950    eq InstForIndex.myCVD() = getInstPrimitive();
3951   
3952    public void CommonForIndex.setEvaluationValue(VariableEvaluator evaluator, CValue val) {
3953        if (val == null) {
3954            clearEvaluationValue(ASTNode.defaultVariableEvaluator());
3955        } else {
3956            myCVD().setEvaluationValue(evaluator, val);
3957        }
3958    }
3959   
3960    public CValue CommonForIndex.evaluationValue(VariableEvaluator evaluator) {
3961        return myCVD().evaluationValue(evaluator);
3962    }
3963   
3964    public void CommonForIndex.clearEvaluationValue() {
3965        clearEvaluationValue(defaultVariableEvaluator());
3966    }
3967   
3968    public void CommonForIndex.clearEvaluationValue(VariableEvaluator evaluator) {
3969        myCVD().clearEvaluationValue(evaluator);
3970    }
3971   
3972  /**
3973   * Set the current function evaluation value.
3974   *
3975   * Also updates value map.
3976   */
3977    public void FAbstractVariable.setEvaluationValue(VariableEvaluator evaluator, CValue val) {
3978        evaluator.setEvaluationValue(this, val.cached());
3979    }
3980 
3981  /**
3982   * Set the current function evaluation value.
3983   *
3984   * Also updates value map.
3985   */
3986    public void InstComponentDecl.setEvaluationValue(VariableEvaluator evaluator, CValue val) {
3987        evaluator.setEvaluationValue(this, val.cached());
3988    }
3989 
3990  /**
3991   * Check if this variable has a current function evaluation value.
3992   */
3993  public boolean FAbstractVariable.hasEvaluationValue(VariableEvaluator evaluator) {
3994          return evaluator.hasEvaluationValue(this);
3995  }
3996 
3997  /**
3998   * Check if this variable has a current function evaluation value.
3999   */
4000  public boolean InstComponentDecl.hasEvaluationValue(VariableEvaluator evaluator) {
4001          return evaluator.hasEvaluationValue(this);
4002  }
4003 
4004  /**
4005   * Get the current evaluation value.
4006   */
4007  public CValue FAbstractVariable.evaluationValue(VariableEvaluator evaluator) {
4008          return evaluator.evaluationValue(this);
4009  }
4010 
4011  /**
4012   * Get the current evaluation value.
4013   */
4014  public CValue InstComponentDecl.evaluationValue(VariableEvaluator evaluator) {
4015          return evaluator.evaluationValue(this);
4016  }
4017 
4018    /**
4019     * Remove the current evaluation value
4020     */
4021    public void FAbstractVariable.clearEvaluationValue(VariableEvaluator evaluator) {
4022        evaluator.clearEvaluationValue(this);
4023    }
4024   
4025    /**
4026     * Remove the current evaluation value
4027     */
4028    public void InstComponentDecl.clearEvaluationValue(VariableEvaluator evaluator) {
4029        evaluator.clearEvaluationValue(this);
4030    }
4031   
4032  protected CValue FAbstractVariable.evaluationValue = null;
4033  protected CValue InstComponentDecl.evaluationValue = null;
4034 
4035    public CValue FAbstractVariable.getLocalCachedEvaluationValue() {
4036        return evaluationValue;
4037    }
4038   
4039    public CValue InstComponentDecl.getLocalCachedEvaluationValue() {
4040        return evaluationValue;
4041    }
4042 
4043    public void FAbstractVariable.setLocalCachedEvaluationValue(CValue value) {
4044        evaluationValue = value;
4045    }
4046   
4047    public void InstComponentDecl.setLocalCachedEvaluationValue(CValue value) {
4048        evaluationValue = value;
4049    }
4050   
4051    public void FAbstractVariable.clearLocalCachedEvaluationValue() {
4052        evaluationValue = null;
4053    }
4054   
4055    public void InstComponentDecl.clearLocalCachedEvaluationValue() {
4056        evaluationValue = null;
4057    }
4058   
4059    /**
4060     * Kept for legacy reasons.
4061     * @deprecated Use {@link #setLocalCachedEvaluationValue} instead.
4062     */
4063    public void FAbstractVariable.setEvaluationValue(CValue value) {
4064        setLocalCachedEvaluationValue(value);
4065    }
4066   
4067    /**
4068     * Kept for legacy reasons.
4069     * @deprecated Use {@link #setLocalCachedEvaluationValue} instead.
4070     */
4071    public void InstComponentDecl.setEvaluationValue(CValue value) {
4072        setLocalCachedEvaluationValue(value);
4073    }
4074 
4075
4076    public class EvaluationValueCache {
4077
4078        private Map<CommonVariableDecl,CValue> values;
4079        private Map<CommonVariableDecl,CValue> old;
4080
4081        public EvaluationValueCache(ASTNode source) {
4082            values = source.collectEvaluationValues(null);
4083        }
4084       
4085        public void apply() {
4086            if (values != null) {
4087                old = new HashMap<CommonVariableDecl,CValue>();
4088                for (CommonVariableDecl var : values.keySet()) {
4089                    CValue prev = var.evaluationValue(ASTNode.defaultVariableEvaluator());
4090                    if (!prev.isUnknown())
4091                        old.put(var, prev);
4092                    if (values.get(var) != null)
4093                        var.setEvaluationValue(ASTNode.defaultVariableEvaluator(), values.get(var));
4094                }
4095            }
4096        }
4097       
4098        public void reset() {
4099            if (values != null)
4100                for (CommonVariableDecl var : values.keySet())
4101                    if (old.get(var) != null)
4102                        var.setEvaluationValue(ASTNode.defaultVariableEvaluator(), old.get(var));
4103            old = null;
4104        }
4105
4106    }
4107
4108    public Map<CommonVariableDecl,CValue> ASTNode.collectEvaluationValues(Map<CommonVariableDecl,CValue> map) {
4109        for (ASTNode n : this)
4110            map = n.collectEvaluationValues(map);
4111        return map;
4112    }
4113
4114    public Map<CommonVariableDecl,CValue> InstComponentAccess.collectEvaluationValues(Map<CommonVariableDecl,CValue> map) {
4115        return super.collectEvaluationValues(myInstComponentDecl().collectMyEvaluationValue(map));
4116    }
4117
4118    public Map<CommonVariableDecl,CValue> InstComponentDecl.collectEvaluationValues(Map<CommonVariableDecl,CValue> map) {
4119        return super.collectEvaluationValues(collectMyEvaluationValue(map));
4120    }
4121
4122    public Map<CommonVariableDecl,CValue> CommonAccess.collectEvaluationValues(Map<CommonVariableDecl,CValue> map) {
4123        return super.collectEvaluationValues(collectMyEvaluationValue(map));
4124    }
4125
4126    public Map<CommonVariableDecl,CValue> FAbstractVariable.collectEvaluationValues(Map<CommonVariableDecl,CValue> map) {
4127        return super.collectEvaluationValues(collectMyEvaluationValue(map));
4128    }
4129   
4130    public Map<CommonVariableDecl,CValue> FAttribute.collectEvaluationValues(Map<CommonVariableDecl,CValue> map) {
4131        return map;
4132    }
4133   
4134    public abstract Map<CommonVariableDecl,CValue> CommonAccess.collectMyEvaluationValue(Map<CommonVariableDecl,CValue> map);
4135   
4136    public Map<CommonVariableDecl,CValue> FAccess.collectMyEvaluationValue(Map<CommonVariableDecl,CValue> map) {
4137        return myFV().collectMyEvaluationValue(map);
4138    }
4139   
4140    public Map<CommonVariableDecl,CValue> InstAccess.collectMyEvaluationValue(Map<CommonVariableDecl,CValue> map) {
4141        return map;
4142    }
4143
4144    public Map<CommonVariableDecl,CValue> InstComponentDecl.collectMyEvaluationValue(Map<CommonVariableDecl,CValue> map) {
4145        if (evaluationValue != null) {
4146            if (map == null)
4147                map = new HashMap<CommonVariableDecl,CValue>();
4148            map.put(this, evaluationValue);
4149        }
4150        return map;
4151    }
4152
4153    public Map<CommonVariableDecl,CValue> FAbstractVariable.collectMyEvaluationValue(Map<CommonVariableDecl,CValue> map) {
4154        if (evaluationValue != null) {
4155            if (map == null)
4156                map = new HashMap<CommonVariableDecl,CValue>();
4157            map.put(this, evaluationValue);
4158        }
4159        return map;
4160    }
4161
4162    /**
4163     * Addition of constant values.
4164     *
4165     * @param v1 Constant value of left operand.
4166     * @param v2 Constant value of right operand.
4167     * @return Resulting constant value.
4168     */
4169    syn CValue FType.add(CValue v1, CValue v2) = CValue.UNKNOWN;
4170
4171    eq FRealType.add(CValue v1, CValue v2) {
4172        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4173            return CValue.UNKNOWN;
4174        }
4175        return new CValueReal(v1.realValue() + v2.realValue());
4176    }
4177
4178    eq FIntegerType.add(CValue v1, CValue v2) {
4179        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4180            return CValue.UNKNOWN;
4181        }
4182        return new CValueInteger(v1.intValue() + v2.intValue());
4183    }
4184
4185    eq FStringType.add(CValue v1, CValue v2) {
4186        if (!v1.isString() || !v2.isString()) {
4187            return CValue.UNKNOWN;
4188        }
4189        return new CValueString(v1.stringValue() + v2.stringValue());
4190    }
4191
4192    /**
4193     * Subtraction of constant values.
4194     *
4195     * @param v1 Constant value of left operand.
4196     * @param v2 Constant value of right operand.
4197     * @return Resulting constant value.
4198     */
4199    syn CValue FType.sub(CValue v1, CValue v2) = CValue.UNKNOWN;
4200
4201    eq FRealType.sub(CValue v1, CValue v2) {
4202        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4203            return CValue.UNKNOWN;
4204        }
4205        return new CValueReal(v1.realValue() - v2.realValue());
4206    }
4207
4208    eq FIntegerType.sub(CValue v1, CValue v2) {
4209        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4210            return CValue.UNKNOWN;
4211        }
4212        return new CValueInteger(v1.intValue() - v2.intValue());
4213    }
4214
4215    /**
4216     * Multiplication of constant values.
4217     *
4218     * @param v1 Constant value of left operand.
4219     * @param v2 Constant value of right operand.
4220     * @return Resulting constant value.
4221     */
4222    syn CValue FType.mul(CValue v1, CValue v2) = CValue.UNKNOWN;
4223
4224    eq FRealType.mul(CValue v1, CValue v2) {
4225        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4226            return CValue.UNKNOWN;
4227        }
4228        return new CValueReal(v1.realValue() * v2.realValue());
4229    }
4230
4231    eq FIntegerType.mul(CValue v1, CValue v2) {
4232        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4233            return CValue.UNKNOWN;
4234        }
4235        return new CValueInteger(v1.intValue() * v2.intValue());
4236    }
4237
4238    /**
4239     * Division of constant values.
4240     *
4241     * @param v1 Constant value of left operand.
4242     * @param v2 Constant value of right operand.
4243     * @return Resulting constant value.
4244     */
4245    syn CValue FType.div(CValue v1, CValue v2) = CValue.UNKNOWN;
4246
4247    eq FRealType.div(CValue v1, CValue v2) {
4248        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4249            return CValue.UNKNOWN;
4250        }
4251        return new CValueReal(v1.realValue() / v2.realValue());
4252    }
4253
4254    eq FIntegerType.div(CValue v1, CValue v2) {
4255        if (!v1.isReal() || !v2.isReal()) {
4256            return CValue.UNKNOWN;
4257        }
4258        return new CValueReal(v1.realValue() / v2.realValue());
4259    }
4260
4261    /**
4262     * Power expression for constant values.
4263     *
4264     * @param v1 Constant value of left operand.
4265     * @param v2 Constant value of right operand.
4266     * @return Resulting constant value.
4267     */
4268    syn CValue FType.pow(CValue v1, CValue v2) = CValue.UNKNOWN;
4269
4270    eq FRealType.pow(CValue v1, CValue v2) {
4271        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4272            return CValue.UNKNOWN;
4273        }
4274        return new CValueReal(java.lang.StrictMath.pow(v1.realValue(), v2.realValue()));
4275    }
4276
4277    /**
4278     * Negation of a constant value.
4279     *
4280     * @param v Constant value of operand.
4281     * @return Resulting constant value.
4282     */
4283    syn CValue FType.neg(CValue v) = CValue.UNKNOWN;
4284    eq FRealType.neg(CValue v) = v.hasRealValue() ? new CValueReal(-v.realValue()) : CValue.UNKNOWN;
4285    eq FIntegerType.neg(CValue v) = v.hasIntValue() ? new CValueInteger(-v.intValue()) : CValue.UNKNOWN;
4286
4287    /**
4288     * Abs expression for constant values.
4289     *
4290     * @param v Constant value of operand.
4291     * @return Resulting constant value.
4292     */
4293    syn CValue FType.abs(CValue v) = CValue.UNKNOWN;
4294    eq FRealType.abs(CValue v) = v.hasRealValue() ? new CValueReal(StrictMath.abs(v.realValue())) : CValue.UNKNOWN;
4295    eq FIntegerType.abs(CValue v) =
4296            v.hasIntValue() ? new CValueInteger(StrictMath.abs(v.intValue())) : CValue.UNKNOWN;
4297
4298    /**
4299     * Sign expression for constant values.
4300     *
4301     * @param v Constant value of operand.
4302     * @return Resulting constant value.
4303     */
4304    syn CValue FType.sign(CValue v) = CValue.UNKNOWN;
4305
4306    eq FIntegerType.sign(CValue v) =
4307            v.hasIntValue() ? new CValueInteger((int) StrictMath.signum(v.realValue())) : CValue.UNKNOWN;
4308
4309    /**
4310     * Ceil expression for constant values.
4311     *
4312     * @param v Constant value of operand.
4313     * @return Resulting constant value.
4314     */
4315    syn CValue FType.ceil(CValue v) = CValue.UNKNOWN;
4316
4317    eq FRealType.ceil(CValue v) = v.hasRealValue() ? new CValueReal(StrictMath.ceil(v.realValue())) : CValue.UNKNOWN;
4318
4319    eq FIntegerType.ceil(CValue v) =
4320            v.hasIntValue() ? new CValueInteger((int) StrictMath.ceil(v.realValue())) : CValue.UNKNOWN;
4321
4322    /**
4323     * Truncation to zero for constant values.
4324     *
4325     * @param v Constant value of operand.
4326     * @return Resulting constant value.
4327     */
4328    syn CValue FType.truncToZero(CValue v) = CValue.UNKNOWN;
4329
4330    eq FRealType.truncToZero(CValue v) {
4331        if (!v.hasRealValue()) {
4332            return CValue.UNKNOWN;
4333        }
4334        return v.realValue() < 0 ? ceil(v) : v.convertInteger().convertReal();
4335    }
4336
4337    eq FIntegerType.truncToZero(CValue v) {
4338        if (!v.hasIntValue()) {
4339            return CValue.UNKNOWN;
4340        }
4341        return v.realValue() < 0 ? ceil(v) : v.convertInteger();
4342    }
4343
4344    /**
4345     * And expression for constant values.
4346     *
4347     * @param v1 Constant value of left operand.
4348     * @param v2 Constant value of right operand.
4349     * @return Resulting constant value.
4350     */
4351    syn CValue FType.and(CValue v1, CValue v2) = CValue.UNKNOWN;
4352
4353    eq FBooleanType.and(CValue v1, CValue v2) {
4354        if (!v1.isBoolean() || !v2.isBoolean()) {
4355            return CValue.UNKNOWN;
4356        }
4357        return new CValueBoolean(v1.booleanValue() && v2.booleanValue());
4358    }
4359
4360    /**
4361     * Or expression for constant values.
4362     *
4363     * @param v1 Constant value of left operand.
4364     * @param v2 Constant value of right operand.
4365     * @return Resulting constant value.
4366     */
4367    syn CValue FType.or(CValue v1, CValue v2) = CValue.UNKNOWN;
4368
4369    eq FBooleanType.or(CValue v1, CValue v2) {
4370        if (!v1.isBoolean() || !v2.isBoolean()) {
4371            return CValue.UNKNOWN;
4372        } 
4373        return new CValueBoolean(v1.booleanValue() || v2.booleanValue());
4374    }
4375
4376    /**
4377     * Not expression for constant values.
4378     *
4379     * @param v Constant value of operand.
4380     * @return Resulting constant value.
4381     */
4382    syn CValue FType.not(CValue v) = CValue.UNKNOWN;
4383    eq FBooleanType.not(CValue v) = v.isBoolean() ? new CValueBoolean(!v.booleanValue()) : CValue.UNKNOWN;
4384
4385    /* Machine epsilon */
4386    public static double FRealType.MACHINE_EPSILON = 2.2204460492503131e-16;
4387
4388    /* Epsilon used for Real-type comparisons */
4389    public static double FRealType.ALMOST_EPSILON = MACHINE_EPSILON;
4390
4391    syn boolean FRealType.almostZero(double op)   = almostLtZero(op) && almostGtZero(op);
4392    syn boolean FRealType.almostLtZero(double op) = op <= ALMOST_EPSILON;
4393    syn boolean FRealType.almostGtZero(double op) = op >= -ALMOST_EPSILON;
4394    syn boolean FRealType.surelyLtZero(double op) = op < -ALMOST_EPSILON;
4395    syn boolean FRealType.surelyGtZero(double op) = op > ALMOST_EPSILON;
4396
4397    /**
4398     * Equals comparison for constant values.
4399     *
4400     * @param v1 Constant value of left operand.
4401     * @param v2 Constant value of right operand.
4402     * @return Resulting constant value.
4403     */
4404    syn CValue FType.equ(CValue v1, CValue v2) {
4405        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4406            return CValue.UNKNOWN;
4407        }
4408        return new CValueBoolean(v1.intValue() == v2.intValue());
4409    }
4410
4411    eq FRealType.equ(CValue v1, CValue v2) {
4412        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4413            return CValue.UNKNOWN;
4414        }
4415        return new CValueBoolean(almostZero(v1.realValue() - v2.realValue()));
4416    }
4417
4418    eq FStringType.equ(CValue v1, CValue v2) {
4419        if (!v1.hasStringValue() || !v2.hasStringValue()) {
4420            return CValue.UNKNOWN;
4421        }
4422        return new CValueBoolean(v1.stringValue().compareTo(v2.stringValue()) == 0);
4423    }
4424
4425    eq CValueUnknown.equ(CValue v1, CValue v2) = CValue.UNKNOWN;
4426
4427    /**
4428     * Not equal comparison for constant values.
4429     *
4430     * @param v1 Constant value of left operand.
4431     * @param v2 Constant value of right operand.
4432     * @return Resulting constant value.
4433     */
4434    syn CValue FType.neq(CValue v1, CValue v2) {
4435        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4436            return CValue.UNKNOWN;
4437        }
4438        return new CValueBoolean(v1.intValue() != v2.intValue());
4439    }
4440
4441    eq FRealType.neq(CValue v1, CValue v2) {
4442        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4443            return CValue.UNKNOWN;
4444        }
4445        return new CValueBoolean(v1.realValue() != v2.realValue());
4446    }
4447
4448    eq FStringType.neq(CValue v1, CValue v2) {
4449        if (!v1.hasStringValue() || !v2.hasStringValue()) {
4450            return CValue.UNKNOWN;
4451        }
4452        return new CValueBoolean(v1.stringValue().compareTo(v2.stringValue()) != 0);
4453    }
4454
4455    eq CValueUnknown.neq(CValue v1, CValue v2) = CValue.UNKNOWN;
4456
4457    /**
4458     * Greater or equal than comparison for constant values.
4459     *
4460     * @param v1 Constant value of left operand.
4461     * @param v2 Constant value of right operand.
4462     * @return Resulting constant value.
4463     */
4464    syn CValue FType.geq(CValue v1, CValue v2) {
4465        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4466            return CValue.UNKNOWN;
4467        }
4468        return new CValueBoolean(v1.intValue() >= v2.intValue());
4469    }
4470
4471    eq FRealType.geq(CValue v1, CValue v2) {
4472        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4473            return CValue.UNKNOWN;
4474        }
4475        return new CValueBoolean(almostGtZero(v1.realValue() - v2.realValue()));
4476    }
4477
4478    eq FStringType.geq(CValue v1, CValue v2) {
4479        if (!v1.hasStringValue() || !v2.hasStringValue()) {
4480            return CValue.UNKNOWN;
4481        } 
4482        return new CValueBoolean(v1.stringValue().compareTo(v2.stringValue()) >= 0);
4483    }
4484
4485    eq CValueUnknown.geq(CValue v1, CValue v2) = CValue.UNKNOWN;
4486
4487    /**
4488     * Greater than comparison for constant values.
4489     *
4490     * @param v1 Constant value of left operand.
4491     * @param v2 Constant value of right operand.
4492     * @return Resulting constant value.
4493     */
4494    syn CValue FType.gt(CValue v1, CValue v2) {
4495        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4496            return CValue.UNKNOWN;
4497        }
4498        return new CValueBoolean(v1.intValue() > v2.intValue());
4499    }
4500
4501    eq FRealType.gt(CValue v1, CValue v2) {
4502        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4503            return CValue.UNKNOWN;
4504        }
4505        return new CValueBoolean(v1.realValue() > v2.realValue());
4506    }
4507
4508    eq FStringType.gt(CValue v1, CValue v2) {
4509        if (!v1.hasStringValue() || !v2.hasStringValue()) {
4510            return CValue.UNKNOWN;
4511        }
4512        return new CValueBoolean(v1.stringValue().compareTo(v2.stringValue()) > 0);
4513    }
4514
4515    eq CValueUnknown.gt(CValue v1, CValue v2) = CValue.UNKNOWN;
4516
4517    /**
4518     * Less or equal than comparison for constant values.
4519     *
4520     * @param v1 Constant value of left operand.
4521     * @param v2 Constant value of right operand.
4522     * @return Resulting constant value.
4523     */
4524    syn CValue FType.leq(CValue v1, CValue v2) {
4525        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4526            return CValue.UNKNOWN;
4527        }
4528        return new CValueBoolean(v1.intValue() <= v2.intValue());
4529    }
4530
4531    eq FRealType.leq(CValue v1, CValue v2) {
4532        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4533            return CValue.UNKNOWN;
4534        } 
4535        return new CValueBoolean(almostLtZero(v1.realValue() - v2.realValue()));
4536    }
4537
4538    eq FStringType.leq(CValue v1, CValue v2) {
4539        if (!v1.hasStringValue() || !v2.hasStringValue()) {
4540            return CValue.UNKNOWN;
4541        }
4542        return new CValueBoolean(v1.stringValue().compareTo(v2.stringValue()) <= 0);
4543    }
4544
4545    eq CValueUnknown.leq(CValue v1, CValue v2) = CValue.UNKNOWN;
4546
4547    /**
4548     * Less than comparison for constant values.
4549     *
4550     * @param v1 Constant value of left operand.
4551     * @param v2 Constant value of right operand.
4552     * @return Resulting constant value.
4553     */
4554    syn CValue FType.lt(CValue v1, CValue v2) {
4555        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4556            return CValue.UNKNOWN;
4557        }
4558        return new CValueBoolean(v1.intValue() < v2.intValue());
4559    }
4560
4561    eq FRealType.lt(CValue v1, CValue v2) {
4562        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4563            return CValue.UNKNOWN;
4564        }
4565        return new CValueBoolean(v1.realValue() < v2.realValue());
4566    }
4567
4568    eq FStringType.lt(CValue v1, CValue v2) {
4569        if (!v1.hasStringValue() || !v2.hasStringValue()) {
4570            return CValue.UNKNOWN;
4571        }
4572        return new CValueBoolean(v1.stringValue().compareTo(v2.stringValue()) < 0);
4573    }
4574
4575    eq CValueUnknown.lt(CValue v1, CValue v2) = CValue.UNKNOWN;
4576
4577}
4578
4579aspect ArrayConstantEvaluation {
4580       
4581        /**
4582         * Returns the set of array indices spanned by a component declared with this subscript.
4583         */
4584        syn int[] FSubscript.arrayIndices(VariableEvaluator evaluator) = new int[0];
4585        eq FExpSubscript.arrayIndices(VariableEvaluator evaluator) {
4586                int s = numIndices(evaluator);
4587                if (s < 0)
4588                        s = 0;
4589                int ind[] = new int[s];
4590                for (int i = 0; i < s; i++) 
4591                        ind[i] = i + 1;
4592                return ind;
4593        }
4594
4595       
4596        /**
4597         * Get the number of array indices spanned by a component declared with this subscript.
4598         */
4599        syn int FSubscript.numIndices(VariableEvaluator evaluator) = 0;
4600        eq FExpSubscript.numIndices(VariableEvaluator evaluator) = getFExp().ceval(evaluator).intValue();
4601
4602}
4603
4604aspect LiteralExpressions {
4605
4606    syn boolean FExp.hasOnlyLiterals() {
4607        for (FExp e : childFExps())
4608            if (!e.hasOnlyLiterals())
4609                return false;
4610        return true;
4611    }
4612
4613    eq CommonAccessExp.hasOnlyLiterals()= false;
4614    eq FFunctionCall.hasOnlyLiterals()  = false;
4615    eq FTimeExp.hasOnlyLiterals()       = false;
4616    eq FEndExp.hasOnlyLiterals()        = !inFunction();
4617
4618}
4619
4620aspect CircularExpressions {
4621
4622    /**
4623     * Check if expression is circular.
4624     *
4625     * Default implementation returns <code>true</code> if any direct FExp child
4626     * is circular.
4627     */
4628    syn boolean FExp.isCircular() = false;
4629    syn lazy boolean FAbstractExp.isCircular() {
4630        if (inIsCircular)
4631            return true;
4632        inIsCircular = true;
4633        boolean res = isCircularCalc();
4634        inIsCircular = false;
4635        return res;
4636    }
4637
4638        syn boolean FExp.isCircularCalc() = false;
4639        eq FAbstractExp.isCircularCalc() {
4640                for (FExp e : childFExps())
4641                        if (e.isCircular())
4642                                return true;
4643                return false;
4644        }
4645       
4646        private boolean FAbstractExp.inIsCircular = false; 
4647       
4648    eq CommonAccessExp.isCircularCalc() = getAccess().isCircular(-1);
4649   
4650    syn boolean CommonAccess.isCircular(int dim);
4651    eq FAccess.isCircular(int dim)     = myFV().isCircular();
4652    eq InstAccess.isCircular(int dim) = myInstComponentDecl().isCircular(dim);
4653
4654        syn lazy boolean FForIndex.isCircular() circular [true] = getFExp().isCircular(); // TODO: test without when it works
4655
4656        eq FSizeExp.isCircularCalc() { 
4657                Size s = getFExp().size();
4658                return hasDim() ? s.isCircular(dimension()) : s.isCircular();
4659        }
4660    eq FUnknownSizeExp.isCircularCalc() = getDim().isCircular() || getFExp().asCommonAccess().isCircular(dimension());
4661   
4662    eq FIfExp.isCircularCalc() {
4663        if (getIfExp().variability().evalOrLess()) {
4664            try {
4665                CValue testVal = getIfExp().ceval();
4666                if (testVal.hasBooleanValue()) {
4667                    if (testVal.booleanValue())
4668                        return getThenExp().isCircular();
4669                    else
4670                        return getElseExp().isCircular();
4671                }
4672            } catch (ConstantEvaluationException e) {}
4673        }
4674        return super.isCircularCalc();
4675    }
4676
4677        syn boolean FExp.isUnknownSizeVarUse()  = false;
4678        eq CommonAccessExp.isUnknownSizeVarUse()= getAccess().isUnknownSizeVarUse();
4679       
4680        syn boolean CommonAccess.isUnknownSizeVarUse();
4681        eq FAccess.isUnknownSizeVarUse()     = myFV().isUnknownSizeVar();
4682        eq InstAccess.isUnknownSizeVarUse() = myInstComponentDecl().isUnknownSizeVar();
4683       
4684        syn boolean FAbstractVariable.isUnknownSizeVar() = false;
4685    eq FFunctionVariable.isUnknownSizeVar()          = getType().size().isUnknown();
4686        syn boolean InstComponentDecl.isUnknownSizeVar() = type().size().isUnknown();
4687       
4688        public boolean Size.isCircular() {
4689                for (int d = 0; d < size.length; d++)
4690                        if (isCircular(d))
4691                                return true;
4692                return false;
4693        }
4694       
4695        public boolean Size.isCircular(int d) {
4696                return false;
4697        }
4698       
4699        public boolean MutableSize.isCircular(int d) {
4700                try {
4701                        return size[d] == UNKNOWN && exps[d] != null && exps[d].isCircular();
4702                } catch (ArrayIndexOutOfBoundsException e) {
4703                        return false;
4704                }
4705        }
4706
4707    eq FIterExp.isCircularCalc() {
4708        if (getFExp().isCircular()) 
4709            return true;
4710        for (CommonForIndex i : getForIndexList()) 
4711            if (i.isCircular()) 
4712                return true;
4713        return false;
4714    }
4715
4716    syn boolean CommonForIndex.isCircular() = getFExp().isCircular();
4717    eq InstForIndexNoExp.isCircular()       = hasFExp() && getFExp().isCircular();
4718
4719        eq InstFunctionCall.isCircularCalc() {
4720                for (InstFunctionArgument a : getArgs())
4721                        if (a.isCircular())
4722                                return true;
4723                return false;
4724        }
4725
4726    syn boolean InstFunctionArgument.isCircular() = false;
4727    eq InstGivenArgument.isCircular()      = getFExp().isCircular();
4728    eq InstDefaultArgument.isCircular()    = getFExp().isCircular();
4729
4730
4731        syn lazy boolean FAbstractVariable.isCircular() circular [true] = false;
4732        eq FVariable.isCircular() = getFAccess().isCircular() || (hasBindingExp() && getBindingExp().isCircular());
4733       
4734        syn boolean FAccess.isCircular() = false;
4735        eq FAccessFull.isCircular() {
4736                for (FAccessPart part : getFAccessParts())
4737                        if (part.isCircular())
4738                                return true;
4739                return false;
4740        }
4741       
4742        syn boolean FAccessPart.isCircular() = false;
4743        eq FAccessPartArray.isCircular()     = getFArraySubscripts().isCircular();
4744
4745    syn lazy boolean InstComponentDecl.isCircular(int dim) circular [true] = false;
4746    eq InstAssignable.isCircular(int dim) {
4747        if (hasFArraySubscripts()) {
4748            if (dim == -1) {
4749                if (getFArraySubscripts().isCircular()) {
4750                    return true;
4751                }
4752            } else {
4753                if (getFArraySubscripts().subscript(dim).isCircular()) {
4754                    return true;
4755                }
4756            }
4757        }
4758        return (hasBindingFExp() && getBindingFExp().isCircular());
4759    }
4760    eq InstRecord.isCircular(int dim) = false;
4761
4762        syn boolean FArraySubscripts.isCircular() = false;
4763        eq FArrayExpSubscripts.isCircular() {
4764                for (FSubscript fs : getFSubscripts())
4765                        if (fs.isCircular())
4766                                return true;
4767                return false;
4768        }
4769       
4770        syn boolean FSubscript.isCircular() = false;
4771        eq FExpSubscript.isCircular() = getFExp().isCircular();
4772        public boolean IntegerSubscript.isCircular() { return false; }
4773
4774}
4775
4776aspect AritmeticTransformations {
4777
4778    /**
4779     * Create a negated copy of this expression.
4780     */
4781    syn FExp FExp.createNegated()     = new FNegExp(fullCopy());
4782    eq FNegExp.createNegated()        = getFExp().fullCopy();
4783    eq FDotSubExp.createNegated()     = createNodeBinary(getRight().fullCopy(), getLeft().fullCopy());
4784    eq FDotAddExp.createNegated()     = new FDotSubExp(new FNegExp(getLeft().fullCopy()), getRight().fullCopy());
4785    eq FAddExp.createNegated()        = new FSubExp(new FNegExp(getLeft().fullCopy()), getRight().fullCopy());
4786    eq FIntegerLitExp.createNegated() = new FIntegerLitExp(- getValue());
4787    eq FRealLitExp.createNegated()    = new FRealLitExp(- getValue());
4788
4789    /**
4790     * Return this expression negated.
4791     *
4792     * Does not copy expression.
4793     */
4794    syn FExp FExp.makeNegated()     = new FNegExp(this);
4795    eq FNegExp.makeNegated()        = getFExp();
4796    eq FDotAddExp.makeNegated()     = new FDotSubExp(new FNegExp(getLeft()), getRight());
4797    eq FAddExp.makeNegated()        = new FSubExp(new FNegExp(getLeft()), getRight());
4798    eq FDotSubExp.makeNegated() {
4799        FExp tmp = getLeft();
4800        setLeft(getRight());
4801        setRight(tmp);
4802        return this;
4803    }
4804    eq FIntegerLitExp.makeNegated() {
4805        setValue(- getValue());
4806        return this;
4807    }
4808    eq FRealLitExp.makeNegated() {
4809        setValue(- getValue());
4810        return this;
4811    }
4812
4813    /**
4814     * Can {@link #makeNegated()} and {@link #createNegated()} do something better
4815     * than just wrapping the expression in a FNegExp?
4816     */
4817    syn boolean FExp.hasSimpleNegation()  = false;
4818    eq FNegExp.hasSimpleNegation()        = true;
4819    eq FDotSubExp.hasSimpleNegation()     = true;
4820    eq FDotAddExp.hasSimpleNegation()     = true;
4821    eq FIntegerLitExp.hasSimpleNegation() = true;
4822    eq FRealLitExp.hasSimpleNegation()    = true;
4823
4824}
4825
4826aspect SourceCeval {
4827    /**
4828     * Source Constant evaluations only implemented for the most basic expressions.
4829     */ 
4830    syn CValue SrcExp.ceval()        = CValue.UNKNOWN;
4831    eq SrcStringLitExp.ceval()       = new CValueString(unEscape());
4832    eq SrcAccessExp.ceval()          = new CValueUnknownAccess(getSrcAccess().name());
4833    eq SrcBooleanLitExpTrue.ceval()  = CValueBoolean.TRUE;
4834    eq SrcBooleanLitExpFalse.ceval() = CValueBoolean.FALSE;
4835    eq SrcIntegerLitExp.ceval()      = new CValueInteger(Integer.parseInt(getUNSIGNED_INTEGER()));
4836    eq SrcRealLitExp.ceval()         = new CValueReal(Double.parseDouble(getUNSIGNED_NUMBER()));
4837    eq SrcArrayConstructor.ceval()   = cevalArray();
4838    eq SrcMatrix.ceval()             = cevalArray();
4839    eq SrcNegExp.ceval() {
4840        CValue value = getSrcExp().ceval();
4841        if (value.isInteger())
4842            return new CValueInteger(-value.intValue());
4843        else if (value.isReal())
4844            return new CValueReal(-value.realValue());
4845        else
4846            return CValue.UNKNOWN;
4847    }
4848   
4849    syn CValue SrcExp.cevalArray() = fillArrayCValue(new CValueArray(sizeCeval()));
4850   
4851    public CValue SrcExp.fillArrayCValue(CValueArray arrayValue) {
4852        List<? extends SrcExp> exps = arrayChildrenForCeval();
4853        if (exps == null) {
4854            arrayValue.addCell(ceval());
4855        } else {
4856            for (SrcExp exp : exps) {
4857                exp.fillArrayCValue(arrayValue);
4858            }
4859        }
4860        return arrayValue;
4861    }
4862   
4863    /**
4864     * It is currently not possible to use an VariableEvaluator for source node
4865     * expressions. This implementation simply delegates to ceval() without
4866     * arguments.
4867     */
4868    syn CValue SrcExp.ceval(VariableEvaluator evaluator) = ceval();
4869   
4870    syn int SrcExp.ndimsCeval() {
4871        List<? extends SrcExp> exps = arrayChildrenForCeval();
4872        if (exps == null) {
4873            return 0;
4874        } else if (exps.getNumChild() == 0) {
4875            return 1;
4876        } else {
4877            return 1 + exps.getChild(0).ndimsCeval();
4878        }
4879    }
4880
4881    syn Size SrcExp.sizeCeval() {
4882        int n = ndimsCeval();
4883        if (n == 0) {
4884            return Size.SCALAR;
4885        } else {
4886            int[] dims = new int[n];
4887            fillSizeCeval(dims, 0);
4888            return new Size(dims);
4889        }
4890    }
4891
4892    public void SrcExp.fillSizeCeval(int[] dims, int i) {
4893        List<? extends SrcExp> exps = arrayChildrenForCeval();
4894        dims[i] = exps.getNumChild();
4895        if (i + 1 < dims.length && dims[i] > 0) {
4896            exps.getChild(0).fillSizeCeval(dims, i + 1);
4897        }
4898    }
4899
4900    syn List<? extends SrcExp> SrcExp.arrayChildrenForCeval()   = null;
4901    eq SrcArrayConstructor.arrayChildrenForCeval() = getSrcFunctionArguments().getSrcExps();
4902    eq SrcMatrix.arrayChildrenForCeval()           = getRows();
4903    eq SrcMatrixRow.arrayChildrenForCeval()        = getSrcExps();
4904}
4905
4906aspect ConstantEvaluable {
4907    SrcExp implements Evaluable;
4908    FExp implements Evaluable;
4909   
4910    public ConstValue SrcExp.evaluateValue() {
4911        try {
4912            return ceval();
4913        } catch (ConstantEvaluationException e) {
4914            return CValue.UNKNOWN;
4915        }
4916    }
4917    public ConstValue FExp.evaluateValue() {
4918        try {
4919            return ceval();
4920        } catch (ConstantEvaluationException e) {
4921            return CValue.UNKNOWN;
4922        }
4923    }
4924}
4925
4926aspect VariableEvaluator {
4927    public static VariableEvaluator ASTNode.defaultVariableEvaluator() {
4928        return VariableEvaluator.instance;
4929    }
4930   
4931    public class VariableEvaluator {
4932        public static final VariableEvaluator instance = new VariableEvaluator(true);
4933        private boolean externalEvaluationEnabled;
4934       
4935        public VariableEvaluator(boolean externalEvaluationEnabled) {
4936            this.externalEvaluationEnabled = externalEvaluationEnabled;
4937        }
4938       
4939        public CValue ceval(CommonVariableDecl variable) {
4940            return variable.ceval(this);
4941        }
4942       
4943        /**
4944         * Works only for supporting evaluators.
4945         */
4946        public CValue ceval(String name) {
4947            throw new ConstantEvaluationException(null, "This evaluator doesn't support this type of value lookup");
4948        }
4949       
4950        public CValue ceval(CommonVariableDecl variable, Index i) {
4951            return variable.ceval(this, i);
4952        }
4953       
4954        public CValue cevalUse(CommonAccessExp access) {
4955            return access.cevalUse(this);
4956        }
4957       
4958        public AlgorithmEvaluator createAlgorithmEvaluator(OptionRegistry options, Map<CommonVariableDecl, CValue> values) {
4959            return new AlgorithmEvaluator(externalEvaluationEnabled, options, values);
4960        }
4961       
4962        public AlgorithmEvaluator createEmptyAlgorithmEvaluator(OptionRegistry options) {
4963            return new AlgorithmEvaluator(true, options, Collections.<CommonVariableDecl, CValue>emptyMap());
4964        }
4965       
4966        public boolean hasEvaluationValue(CommonVariableDecl variable) {
4967            return variable.getLocalCachedEvaluationValue() != null;
4968        }
4969       
4970        public void setEvaluationValue(CommonVariableDecl variable, CValue val) {
4971            variable.setLocalCachedEvaluationValue(val);
4972        }
4973       
4974        public CValue evaluationValue(CommonVariableDecl variable) {
4975            CValue val = variable.getLocalCachedEvaluationValue();
4976            return val == null ? CValue.UNKNOWN : val;
4977        }
4978       
4979        public void clearEvaluationValue(CommonVariableDecl variable) {
4980            variable.clearLocalCachedEvaluationValue();
4981        }
4982       
4983        public CValue timeValue() {
4984            return CValue.UNKNOWN;
4985        }
4986       
4987        public CValue inStreamEpsilon() {
4988            return CValue.UNKNOWN;
4989        }
4990       
4991        public boolean externalEvaluationEnabled() {
4992            return externalEvaluationEnabled;
4993        }
4994       
4995        public CValue evalBinOp(FBinExp exp, CValue left, CValue right) {
4996            return exp.cevalEval(left, right);
4997        }
4998       
4999        public CValue evalUnOp(FUnaryExp exp, CValue val) {
5000            return exp.cevalEval(val);
5001        }
5002    }
5003   
5004    public class PartialVariableEvaluator extends VariableEvaluator {
5005       
5006        public PartialVariableEvaluator(boolean externalEvaluationEnabled) {
5007            super(externalEvaluationEnabled);
5008        }
5009       
5010        @Override
5011        public CValue cevalUse(CommonAccessExp access) {
5012            if (access.variability().knownParameterOrLess()) {
5013                return super.cevalUse(access);
5014            } else {
5015                return createUnknownCValue(access);
5016            }
5017        }
5018       
5019        protected CValue createUnknownCValue(CommonAccessExp access) {
5020            return access.type().unknownCValue();
5021        }
5022       
5023        protected CValue createUnknownCValue(FExp exp) {
5024            return exp.type().unknownCValue();
5025        }
5026       
5027        @Override
5028        public AlgorithmEvaluator createAlgorithmEvaluator(OptionRegistry options, Map<CommonVariableDecl, CValue> values) {
5029            return new PartialAlgorithmEvaluator(externalEvaluationEnabled(), options, values, this);
5030        }
5031       
5032        @Override
5033        public CValue evalBinOp(FBinExp exp, CValue left, CValue right) {
5034            if (left.isUnknown() || right.isUnknown()) {
5035                return left.merge(right);
5036            }
5037            return exp.cevalEval(left, right);
5038        }
5039       
5040        @Override
5041        public CValue evalUnOp(FUnaryExp exp, CValue val) {
5042            if (val.isUnknown()) {
5043                return val;
5044            }
5045            return exp.cevalEval(val);
5046        }
5047       
5048        public boolean isDependencyEvaluator() {
5049            return false;
5050        }
5051       
5052    }
5053   
5054    public class DependencyVariableEvaluator extends PartialVariableEvaluator {
5055        Map<CommonVariableDecl,CValue> values;
5056       
5057        public DependencyVariableEvaluator() {
5058            super(false);
5059        }
5060       
5061        @Override
5062        public AlgorithmEvaluator createAlgorithmEvaluator(OptionRegistry options, Map<CommonVariableDecl, CValue> values) {
5063            if (this.values == null) {
5064                this.values = values;
5065            }
5066            return new PartialAlgorithmEvaluator(externalEvaluationEnabled(), options, values, this);
5067        }
5068       
5069        @Override
5070        protected CValue createUnknownCValue(CommonAccessExp use) {
5071            if (use.getAccess().isFAccess()) {
5072                return new CValueUnknownUse(use.asFAccessExp());
5073            } else {
5074                return new CValueUnknownUse();
5075            }
5076        }
5077       
5078        @Override
5079        protected CValue createUnknownCValue(FExp exp) {
5080            CValue val = new CValueUnknownUse();
5081            for (FAccessExp use : exp.findFAccessExpsInTree()) {
5082                val = val.merge(use.cevalUse(this));
5083            }
5084            return val;
5085        }
5086       
5087        @Override
5088        public CValue timeValue() {
5089            return new CValueUnknownUse();
5090        }
5091       
5092        public Map<FAccessExp, Set<FAccessExp>> resolveDependencies(FFunctionCallEquation equation) {
5093            Map<FAccessExp, Set<FAccessExp>> res = new HashMap<>();
5094            for (int i = 0; i < equation.getNumLeft(); i++) {
5095                if (equation.getLeft(i).hasFExp()) {
5096                    FExp e = equation.getLeft(i).getFExp();
5097                    CommonVariableDecl cvd = equation.getCall().myCallOutputs().get(i);
5098                    e.mapComponents(res, values.get(cvd));
5099                }
5100            }
5101            return res;
5102        }
5103       
5104        @Override
5105        public boolean isDependencyEvaluator() {
5106            return true;
5107        }
5108    }
5109   
5110    public void FExp.mapComponents(Map<FAccessExp, Set<FAccessExp>> res, CValue val) {
5111        throw new UnsupportedOperationException("Unsupported FExp in LHS");
5112    }
5113   
5114    public void FArray.mapComponents(Map<FAccessExp, Set<FAccessExp>> res, CValue val) {
5115        Enumerator e = new Enumerator();
5116        mapComponentsArray(res, val.array(), e);
5117    }
5118   
5119    public void FExp.mapComponentsArray(Map<FAccessExp, Set<FAccessExp>> res, CValueArray val, Enumerator e) {
5120        mapComponents(res, val.getCell(e.next()));
5121    }
5122   
5123    public void FArray.mapComponentsArray(Map<FAccessExp, Set<FAccessExp>> res, CValueArray val, Enumerator e) {
5124        for (FExp exp : getFExps()) {
5125            exp.mapComponentsArray(res, val, e);
5126        }
5127    }
5128   
5129    public void FRecordConstructor.mapComponents(Map<FAccessExp, Set<FAccessExp>> res, CValue val) {
5130        CValueRecord rec = val.record();
5131        for (int i = 0; i < getNumArg(); i++) {
5132            getArg(i).mapComponents(res, rec.getMember(i));
5133        }
5134    }
5135   
5136    public void FAccessExp.mapComponents(Map<FAccessExp, Set<FAccessExp>> res, CValue val) {
5137        Set<FAccessExp> s = new HashSet<>();
5138        s.addAll(val.getDependencies());
5139        res.put(this, s);
5140    }
5141   
5142    public Set<FAccessExp> CValue.getDependencies() {
5143        return new HashSet<>();
5144    }
5145   
5146    public Set<FAccessExp> CValueUnknown.getDependencies() {
5147        return unknownUse().getDependencies();
5148    }
5149   
5150    public void FNoExp.mapComponents(Map<FAccessExp, Set<FAccessExp>> res, CValue val) {
5151       
5152    }
5153   
5154    public class AlgorithmEvaluator extends VariableEvaluator {
5155       
5156        protected Map<CommonVariableDecl, CValue> values;
5157        private OptionRegistry options;
5158       
5159        public AlgorithmEvaluator(boolean evaluateExternalEnabled, OptionRegistry options, Map<CommonVariableDecl, CValue> values) {
5160            super(evaluateExternalEnabled);
5161            this.values  = values;
5162            this.options = options;
5163        }
5164       
5165        public int externalEvaluation() {
5166            return externalEvaluationEnabled() ? options.getIntegerOption("external_constant_evaluation") : 0;
5167        }
5168       
5169        @Override
5170        public String toString() {
5171            StringBuilder sb = new StringBuilder();
5172            sb.append(super.toString());
5173            sb.append("\n");
5174            for (CommonVariableDecl cvd : values.keySet()) {
5175                sb.append(cvd.toString());
5176                sb.append(" = ");
5177                sb.append(values.get(cvd).toString());
5178                sb.append("\n");
5179            }
5180            return sb.toString();
5181        }
5182       
5183        public CValue ceval(FExp exp) {
5184            return exp.ceval(this);
5185        }
5186       
5187        @Override
5188        public void setEvaluationValue(CommonVariableDecl variable, CValue val) {
5189            super.setEvaluationValue(variable, val);
5190            values.put(variable, val);
5191        }
5192       
5193        public void clear() {
5194            values.clear();
5195        }
5196       
5197        public Map<CommonVariableDecl, CValue> getValues() {
5198            return values;
5199        }
5200       
5201        public void failed(CommonCallable cc, ConstantEvaluationException e) {
5202            throw new FunctionEvaluationException(cc.qualifiedName(), e);
5203        }
5204       
5205        public boolean recursive(CommonCallable cc) {
5206            return true;
5207        }
5208       
5209        /**
5210         * Called when an if statement evaluation is started.
5211         */
5212        public void startIf() {}
5213       
5214        /**
5215         * Called when an if statement evaluation is finished.
5216         */
5217        public void endIf() {}
5218       
5219        /**
5220         * Called when an if branch evaluation is finished.
5221         */
5222        public void branchIf(int res) {}
5223       
5224    }
5225   
5226    public class PartialAlgorithmEvaluator extends AlgorithmEvaluator {
5227        protected PartialVariableEvaluator variableEvaluator;
5228        protected ArrayList<IfEvaluation> ifStack;
5229       
5230        public PartialAlgorithmEvaluator(boolean evaluateExternalEnabled, OptionRegistry options,
5231                Map<CommonVariableDecl, CValue> values, PartialVariableEvaluator variableEvaluator) {
5232            super(evaluateExternalEnabled, options, values);
5233            this.variableEvaluator = variableEvaluator;
5234            ifStack = new ArrayList<IfEvaluation>();
5235        }
5236       
5237        @Override
5238        public CValue ceval(FExp exp) {
5239            try {
5240                return exp.ceval(this);
5241            } catch (ConstantEvaluationException e) {
5242                return variableEvaluator.createUnknownCValue(exp);
5243            }
5244        }
5245       
5246        @Override
5247        public AlgorithmEvaluator createAlgorithmEvaluator(OptionRegistry options, Map<CommonVariableDecl, CValue> values) {
5248            return variableEvaluator.createAlgorithmEvaluator(options, values);
5249        }
5250       
5251        @Override
5252        public CValue evalBinOp(FBinExp exp, CValue left, CValue right) {
5253            return variableEvaluator.evalBinOp(exp, left, right);
5254        }
5255       
5256        @Override
5257        public CValue evalUnOp(FUnaryExp exp, CValue val) {
5258            return variableEvaluator.evalUnOp(exp, val);
5259        }
5260       
5261        @Override
5262        public void failed(CommonCallable cc, ConstantEvaluationException e) {
5263            values.clear();
5264            for (CommonVariableDecl cvd : cc.myOutputs()) {
5265                values.put(cvd, CValue.UNKNOWN);
5266            }
5267        }
5268       
5269        @Override
5270        public boolean recursive(CommonCallable cc) {
5271            if (variableEvaluator.isDependencyEvaluator()) {
5272                CValueUnknownUse val = new CValueUnknownUse();
5273                for (CommonVariableDecl cvd : cc.myInputs()) {
5274                    val.merge(values.get(cvd));
5275                }
5276                for (CommonVariableDecl cvd : cc.myOutputs()) {
5277                    values.put(cvd, val);
5278                }
5279                return false;
5280            } else {
5281                throw new ConstantEvaluationException(null, "Partial evaluation of recursive functions not supported.");
5282            }
5283        }
5284       
5285        @Override
5286        public void startIf() {
5287            if (variableEvaluator.isDependencyEvaluator()) {
5288                throw new ConstantEvaluationException(null, "Dependency evaluation of if statements not supported.");
5289            }
5290            ifStack.add(new IfEvaluation());
5291        }
5292       
5293        @Override
5294        public void endIf() {
5295            ifStack.remove(ifStack.size()-1).merge();
5296        }
5297       
5298        @Override
5299        public void branchIf(int res) {
5300            ifStack.get(ifStack.size()-1).restore(res);
5301        }
5302       
5303        /**
5304         * Stores several sets of values evaluated from different if-branches
5305         */
5306        private class IfEvaluation {
5307            protected Map<CommonVariableDecl, CValue> valuesBefore;
5308            protected ArrayList<IfBranchEvaluated> branches;
5309           
5310            public IfEvaluation() {
5311                valuesBefore = new HashMap<CommonVariableDecl, CValue>();
5312                for (CommonVariableDecl cvd : values.keySet()) {
5313                    valuesBefore.put(cvd, values.get(cvd).clone());
5314                }
5315                branches = new ArrayList<IfBranchEvaluated>();
5316            }
5317           
5318            /**
5319             * Called when if branch has been evaluated. Will store the evaluators current
5320             * value set and restore that set as it was before this if-clause was entered.
5321             */
5322            public void restore(int res) {
5323                IfBranchEvaluated lastBranch = new IfBranchEvaluated(res);
5324                branches.add(lastBranch);
5325               
5326                for (CommonVariableDecl cvd : values.keySet()) {
5327                    cvd.setEvaluationValue(PartialAlgorithmEvaluator.this, CValue.UNKNOWN);
5328                }
5329                for (CommonVariableDecl cvd : valuesBefore.keySet()) {
5330                    cvd.setEvaluationValue(PartialAlgorithmEvaluator.this, valuesBefore.get(cvd));
5331                }
5332            }
5333           
5334            /**
5335             * Merge all evaluated branches and write result to evaluators current value set.
5336             */
5337            public void merge() {
5338                IfBranchEvaluated res = branches.get(0);
5339                for (int i = 1 ; i < branches.size(); i++) {
5340                    res.merge(branches.get(i));
5341                }
5342                res.restore();
5343            }
5344           
5345            /**
5346             * Stores values evaluated from an if-branch.
5347             */
5348            private class IfBranchEvaluated {
5349                Map<CommonVariableDecl, CValue> values;
5350                int res;
5351               
5352                public IfBranchEvaluated(int res) {
5353                    this.res = res;
5354                    values = new HashMap<CommonVariableDecl, CValue>();
5355                    for (CommonVariableDecl cvd : PartialAlgorithmEvaluator.this.values.keySet()) {
5356                        values.put(cvd, PartialAlgorithmEvaluator.this.values.get(cvd).clone());
5357                    }
5358                }
5359               
5360                /**
5361                 * Merge values from other branch into this. Differing values results in unknown values.
5362                 */
5363                public void merge(IfBranchEvaluated other) {
5364                    if (res != other.res) {
5365                        throw new ConstantEvaluationException(null, "Partial constant evaluation of if statements with "
5366                                + "differing return statuses is not possible");
5367                    }
5368                    for (CommonVariableDecl cvd : other.values.keySet()) {
5369                        if (values.get(cvd) == null) {
5370                            values.put(cvd, cvd.type().unknownCValue());
5371                        } else {
5372                            values.put(cvd, values.get(cvd).merge(other.values.get(cvd)));
5373                        }
5374                    }
5375                }
5376               
5377                /**
5378                 * Write this branch into the value set used by the evaluator.
5379                 */
5380                public void restore() {
5381                    for (CommonVariableDecl cvd : values.keySet()) {
5382                        cvd.setEvaluationValue(PartialAlgorithmEvaluator.this, values.get(cvd));
5383                    }
5384                }
5385            }
5386        }
5387    }
5388}
Note: See TracBrowser for help on using the repository browser.