source: branches/dev-5819/Compiler/ModelicaFlatTree/src/jastadd/ConstantEvaluation/ConstantEvaluation.jrag @ 13651

Last change on this file since 13651 was 13651, checked in by randersson, 2 months ago

#5819 Merged trunk into branch

File size: 188.2 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 Arrays.asList(values).iterator();
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 objectValue() {
1672            return value;
1673        }
1674
1675        @Override
1676        public String toString() {
1677            return type.getName() + "." + value;
1678        }
1679
1680        @Override
1681        public boolean isEnum() {
1682            return true;
1683        }
1684
1685        @Override
1686        public boolean hasIntValue() {
1687            return true;
1688        }
1689
1690        @Override
1691        public boolean hasRealValue() {
1692            return true;
1693        }
1694
1695        @Override
1696        public boolean hasStringValue() {
1697            return true;
1698        }
1699
1700        /**
1701         * Create a literal AST node from constant.
1702         *
1703         * Always creates node for the flat tree.
1704         * 
1705         *  @return an CommonAccessExp pointing to the literal in the FEnumDecl.
1706         */
1707        public FExp buildLiteral() {
1708            return type.createLiteral(index);
1709        }
1710
1711        @Override
1712        public FExp buildInstLiteral() {
1713            return new FEnumLitExp(type, index);
1714        }
1715
1716        @Override
1717        public boolean hasBuildLiteral() {
1718            return true;
1719        }
1720
1721        public CValue constrainWithin(CValue min, CValue max) {
1722            if (!min.isUnknown() && min.intValue() > index)
1723                return min;
1724            if (!max.isUnknown() && max.intValue() < index)
1725                return max;
1726            return this;
1727        }
1728
1729    }
1730
1731
1732    /**
1733     * Create a CValue with the zero value for this type, if applicable.
1734     */
1735    public CValue FType.zeroCValue() {
1736        if (isArray() && !zeroCValueScalar().isUnknown()) {
1737            CValueArray res = new CValueArray(size());
1738            while (!res.isFilled())
1739                res.addCell(zeroCValueScalar());
1740            return res; 
1741        } else {
1742            return zeroCValueScalar();
1743        }
1744    }
1745
1746    public CValue FType.zeroCValueScalar()        { return CValue.UNKNOWN; }
1747    public CValue FArrayType.zeroCValueScalar()   { return getFPrimitiveType().zeroCValueScalar(); }
1748    public CValue FRealType.zeroCValueScalar()    { return new CValueReal(0.0); }
1749    public CValue FIntegerType.zeroCValueScalar() { return new CValueInteger(0); }
1750    public CValue FEnumType.zeroCValueScalar()    { return new CValueEnum(this, 1); }
1751    public CValue FStringType.zeroCValueScalar()  { return new CValueString(""); }
1752    public CValue FBooleanType.zeroCValueScalar() { return new CValueBoolean(false); }
1753   
1754    public CValue FType.createCValue(int v) {
1755        if (isArray()) {
1756            CValueArray res = new CValueArray(size());
1757            while (!res.isFilled())
1758                res.addCell(createCValueScalar(v));
1759            return res;
1760        } else {
1761            return createCValueScalar(v);
1762        }
1763    }
1764   
1765    public CValue FType.createCValueScalar(int v)     { return new CValueInteger(v); }
1766    public CValue FRealType.createCValueScalar(int v) { return new CValueReal(v); }
1767
1768    public CValue FType.convert(CValue v)        { return v; }
1769    public CValue FRealType.convert(CValue v)    { return v.convertReal(); }
1770    public CValue FIntegerType.convert(CValue v) { return v.convertInteger(); }
1771    public CValue FStringType.convert(CValue v)  { return v.convertString(); }
1772    public CValue FBooleanType.convert(CValue v) { return v.convertBoolean(); }
1773
1774    public CValue FType.limitCValueScalar(boolean high)        { return CValue.UNSUPPORTED; }
1775    public CValue FRealType.limitCValueScalar(boolean high)    { return new CValueReal(      high ? Double.MAX_VALUE  : -Double.MAX_VALUE); }
1776    public CValue FIntegerType.limitCValueScalar(boolean high) { return new CValueInteger(   high ? Integer.MAX_VALUE : Integer.MIN_VALUE); }
1777    public CValue FBooleanType.limitCValueScalar(boolean high) { return new CValueBoolean(   high ? true : false); }
1778    public CValue FEnumType.limitCValueScalar(boolean high)    { return new CValueEnum(this, high ? getNumFEnumLiteralType() : 1); }
1779
1780    public boolean CValue.isZero()        { return false; }
1781    public boolean CValueReal.isZero()    { return value == 0; }
1782    public boolean CValueInteger.isZero() { return value == 0; }
1783   
1784   
1785    private boolean CValueArray.cached = false;
1786    private boolean CValueRecord.cached = false;
1787    public CValueArray CValueArray.markAsCached() { this.cached = true; return this; }
1788    public CValueRecord CValueRecord.markAsCached() { this.cached = true; return this; }
1789   
1790    public CValue CValue.cached()       { return this; }
1791    public CValue CValueArray.cached()  {
1792        CValueArray res = this;
1793        if (cached) {
1794            res = (CValueArray) res.clone();
1795        } else {
1796            for (int i = 0; i < values.length; i++) {
1797                values[i] = values[i].cached();
1798            }
1799        }
1800        return res.markAsCached();
1801    }
1802    public CValue CValueRecord.cached()  {
1803        CValueRecord res = this;
1804        if (cached) {
1805            res = res.clone();
1806        } else {
1807            for (int i = 0; i < values.length; i++) {
1808                values[i] = values[i].cached();
1809            }
1810        }
1811        return res.markAsCached();
1812    }
1813   
1814   
1815    public CValue FType.unknownCValue() {
1816        if (isArray()) {
1817            CValueArray arr = new CValueArray(size());
1818            for (Index i : indices()) {
1819                arr.setCell(i, CValue.UNKNOWN);
1820            }
1821            return arr;
1822        } else {
1823            return CValue.UNKNOWN;
1824        }
1825    }
1826   
1827   
1828    public boolean CValue.equals(CValue other) {
1829        return super.equals(other);
1830    }
1831   
1832    public boolean CValueUnknown.equals(CValue other) {
1833        if (other instanceof CValueUnknown) {
1834            return true;
1835        }
1836        return super.equals(other);
1837    }
1838   
1839    public boolean CValueReal.equals(CValue other) {
1840        if (other instanceof CValueReal || 
1841                other instanceof CValueInteger) {
1842            return realValue() == other.realValue();
1843        }
1844        return super.equals(other);
1845    }
1846   
1847    public boolean CValueInteger.equals(CValue other) {
1848        if (other instanceof CValueReal || 
1849                other instanceof CValueInteger) {
1850            return realValue() == other.realValue();
1851        }
1852        return super.equals(other);
1853    }
1854   
1855    public boolean CValueBoolean.equals(CValue other) {
1856        if (other instanceof CValueBoolean) {
1857            return booleanValue() == other.booleanValue();
1858        }
1859        return super.equals(other);
1860    }
1861   
1862    public boolean CValueEnum.equals(CValue other) {
1863        if (other instanceof CValueEnum) {
1864            return intValue() == other.intValue();
1865        }
1866        return super.equals(other);
1867    }
1868   
1869    public boolean CValueString.equals(CValue other) {
1870        if (other instanceof CValueString) {
1871            return stringValue() == other.stringValue();
1872        }
1873        return super.equals(other);
1874    }
1875   
1876    public boolean CValueRecord.equals(CValue other) {
1877        if (other instanceof CValueRecord) {
1878            CValueRecord o = (CValueRecord) other;
1879            for (int i = 0; i < values.length; i++) {
1880                if (!values[i].equals(o.values[i])) {
1881                    return false;
1882                }
1883            }
1884            return true;
1885        }
1886        return super.equals(other);
1887    }
1888   
1889    public boolean CValueArray.equals(CValue other) {
1890        if (other instanceof CValueArray) {
1891            CValueArray o = (CValueArray) other;
1892            if (values.length != o.values.length)
1893                return false;
1894            for (int i = 0; i < values.length; i++) {
1895                if (!values[i].equals(o.values[i])) {
1896                    return false;
1897                }
1898            }
1899            return true;
1900        }
1901        return super.equals(other);
1902    }
1903   
1904    public abstract boolean CValue.typeMatches(CValue other);
1905   
1906    public boolean CValueUnknown.typeMatches(CValue other) {
1907        return other.isUnknown();
1908    }
1909   
1910    public boolean CValueReal.typeMatches(CValue other) {
1911        return other.isReal() || other.isInteger();
1912    }
1913   
1914    public boolean CValueInteger.typeMatches(CValue other) {
1915        return other.isReal() || other.isInteger();
1916    }
1917   
1918    public boolean CValueBoolean.typeMatches(CValue other) {
1919        return other.isBoolean();
1920    }
1921   
1922    public boolean CValueEnum.typeMatches(CValue other) {
1923        return other.isEnum();
1924    }
1925   
1926    public boolean CValueString.typeMatches(CValue other) {
1927        return other.isString();
1928    }
1929   
1930    public boolean CValueRecord.typeMatches(CValue other) {
1931        if (other instanceof CValueRecord) {
1932            CValueRecord o = (CValueRecord) other;
1933            if (values.length != o.values.length)
1934                return false;
1935            for (int i = 0; i < values.length; i++) {
1936                if (!values[i].typeMatches(o.values[i])) {
1937                    return false;
1938                }
1939            }
1940            return true;
1941        }
1942        return false;
1943    }
1944   
1945    public boolean CValueArray.typeMatches(CValue other) {
1946        if (other instanceof CValueArray) {
1947            CValueArray o = (CValueArray) other;
1948            if (values.length != o.values.length)
1949                return false;
1950            for (int i = 0; i < values.length; i++) {
1951                if (!values[i].typeMatches(o.values[i])) {
1952                    return false;
1953                }
1954            }
1955            return true;
1956        }
1957        return false;
1958    }
1959   
1960   
1961    public boolean CValueExternalObject.typeMatches(CValue other) {
1962        throw new UnsupportedOperationException("typeMatches() not implemented for "+getClass().getSimpleName());
1963    }
1964    public boolean CValuePartialFunction.typeMatches(CValue other) {
1965        throw new UnsupportedOperationException("typeMatches() not implemented for "+getClass().getSimpleName());
1966    }
1967
1968    /**
1969     * Modifies <code>this</code> CValue so that components that do not match to
1970     * <code>other</code> are replaced with <code>CValue.UNKNOWN</code>.
1971     * @param other CValue to merge from
1972     * @return Possibly modified <code>this</code> if composite or equals
1973     *         <code>other</code>, else <code>CValue.UNKNOWN</code>
1974     */
1975    public CValue CValue.merge(CValue other) {
1976        if (equals(other)) {
1977            return this;
1978        }
1979        if (isUnknown() && !other.isUnknown()) {
1980            return this;
1981        } else if (!isUnknown() && other.isUnknown()) {
1982            return other;
1983        }
1984        return CValue.UNKNOWN;
1985    }
1986   
1987    @Override
1988    public CValue CValueArray.merge(CValue other) {
1989        if (other instanceof CValueArray) {
1990            CValueArray o = (CValueArray) other;
1991            if (values.length != o.values.length)
1992                return CValue.UNKNOWN;
1993            for (int i = 0; i < values.length; i++) {
1994                values[i] = values[i].merge(o.values[i]);
1995            }
1996            return this;
1997        }
1998        return CValue.UNKNOWN;
1999    }
2000   
2001    @Override
2002    public CValue CValueRecord.merge(CValue other) {
2003        if (other instanceof CValueRecord) {
2004            CValueRecord o = (CValueRecord) other;
2005            if (values.length != o.values.length)
2006                return CValue.UNKNOWN;
2007            for (int i = 0; i < values.length; i++) {
2008                values[i] = values[i].merge(o.values[i]);
2009            }
2010            return this;
2011        }
2012        return CValue.UNKNOWN;
2013    }
2014   
2015    @Override
2016    public CValue CValueUnknown.merge(CValue other) {
2017        return this;
2018    }
2019   
2020    @Override
2021    public CValue CValueUnknownUse.merge(CValue other) {
2022        if (other instanceof CValueUnknownUse) {
2023            CValueUnknownUse o = other.unknownUse();
2024            CValueUnknownUse res = new CValueUnknownUse();
2025            res.deps.addAll(deps);
2026            res.deps.addAll(o.deps);
2027            return res;
2028        }
2029        return super.merge(other);
2030    }
2031   
2032   
2033    /**
2034     * \build Creates an FExp with literals from this Array.
2035     *
2036     * Creates a (possibly nested) FArray containing FLitExp nodes.
2037     *
2038     * @param toReal  if <code>true</code>, convert all values to real.
2039     */
2040    public FExp FExp.buildLiteral(boolean toReal) {
2041        return toReal ? ceval().convertReal().buildLiteral() : ceval().buildLiteral();
2042    }
2043
2044    /**
2045     * Convenience function for savely checking if an expression as a particular value.
2046     *
2047     */ 
2048    syn boolean FExp.equalsRealValue(double val) {
2049        try {
2050                return variability().lessOrEqual(Variability.CONSTANT) && ceval().realValue()==val;
2051        } catch(Exception e) {
2052                return false;
2053        }
2054    } 
2055
2056
2057    /**
2058     * Returns the constant value of a flat expression.
2059     *
2060     * If the expression is not constant, or if it contains type errors,
2061     * <code>CValue.UNKNOWN</code> is returned.
2062     *
2063     * The actual evaluation of concrete FExp nodes is performed by dispatching
2064     * with respect to the primitive type of the expression. For example, when an
2065     * FAddExp node is evaluated, the computation proceeds in the following steps:
2066     *
2067     *  - The primitive type of the expression is retrieved using the type()
2068     *    attribute.
2069     *  - The method add() defined for FType is invoked.
2070     *  - The resulting CValue is returned.
2071     * 
2072     *  Using this strategy, a particular FExp node does not need to know the details of
2073     *  how to evaluate itself in the case of operands of different types. Rather,
2074     *  these computations are delegated to the respective types. In particular,
2075     *  this design simplifies the task of extending the evaluation framework
2076     *  to composite types such as arrays and complex numbers. In addition,
2077     *  the type dispatch makes implementation of support for operator overloading
2078     *  simpler.
2079     * 
2080     *  Note that function evaluation depends on nothing being cached in constant
2081     *  evaluation. If caching is needed later on, an argument to avoid caching must be
2082     *  added to cevalCalc() and an alternate ceval() created. Also, the form taking
2083     *  an Index should then probably be removed.
2084     * 
2085     *  The VariableEvaluator argument is designed to only work reliably after
2086     *  scalarization. This is due to that the fact that size, type, array and
2087     *  some other functions use ceval() without propagation of the evaluator.
2088     *
2089     * @return The constant value of the expression.
2090     */
2091    syn CValue FExp.ceval() = ceval(defaultVariableEvaluator());
2092
2093    syn CValue FExp.ceval(VariableEvaluator evaluator) {
2094        if (isCircular()) 
2095            return CValue.UNKNOWN;
2096        if (isArray()) {
2097            if (size().evaluated().isUnknown())
2098                return CValue.UNKNOWN;
2099            return cevalArray(evaluator, Index.NULL);
2100        }
2101        CValue resOver = cevalOverloaded(evaluator);
2102        return (resOver != null) ? resOver : cevalCalc(evaluator);
2103    }
2104   
2105    /**
2106     * Like {@link #ceval()}, but in the case of an array, only calculate
2107     *        the given cell, if possible.
2108     */
2109    syn CValue FExp.ceval(VariableEvaluator evaluator, Index i) {
2110        if (isCircular()) 
2111            return CValue.UNKNOWN;
2112        if (isArray())
2113            return cevalArray(evaluator, i);
2114        CValue resOver = cevalOverloaded(evaluator);
2115        return (resOver != null) ? resOver : cevalCalc(evaluator);
2116    }
2117
2118
2119    syn Set<String> FExp.collectAccessNames() {
2120        final Set<String> names = new HashSet<>();
2121        collectAccessNames(names);
2122        return names;
2123    }
2124
2125    public void FExp.collectAccessNames(Set<String> collectedNames) {
2126        for (FExp child : childFExps()) {
2127            child.collectAccessNames(collectedNames);
2128        }
2129    }
2130
2131    @Override
2132    public void FTimeExp.collectAccessNames(Set<String> collectedNames) {
2133        collectedNames.add("time");
2134    }
2135
2136    @Override
2137    public void InstAccessExp.collectAccessNames(Set<String> collectedNames) {
2138        if (isArray()) {
2139            for (FExp fexp: getArray().iterable()) {
2140                fexp.collectAccessNames(collectedNames);
2141            }
2142        } else {
2143            final InstAccess access = getInstAccess();
2144            if (!access.isPackageConstantAccess() && !access.isEnumLiteralAccess()) {
2145                access.collectAccessNames(collectedNames);
2146                access.collectAccessNamesInArraySubscripts(collectedNames);
2147            }
2148        }
2149    }
2150
2151    @Override
2152    public void InstFunctionCall.collectAccessNames(Set<String> collectedNames) {
2153      for (InstFunctionArgument arg : getArgList()) {
2154          arg.getFExp().collectAccessNames(collectedNames);
2155      }
2156    }
2157
2158    public boolean InstAccess.isPackageConstantAccess() { return myInstComponentDecl().isPackageConstant(); }
2159    public boolean InstAccess.isEnumLiteralAccess()     { return myInstComponentDecl().isEnumLiteral(); }
2160
2161    public abstract void InstAccess.collectAccessNames(Set<String> collectedNames);
2162
2163    @Override
2164    public void InstDot.collectAccessNames(Set<String> collectedNames) {
2165        final String qualifiedName = qualifiedName();
2166
2167        final ArrayList<String> prefixes = new ArrayList<>();
2168        for (InstAccess instAccess : getInstAccesss()) {
2169            if (instAccess.isClassAccess()) {
2170                prefixes.add(instAccess.name());
2171            }
2172        }
2173        final String prefix = StringUtil.join(".", prefixes);
2174
2175        final Set<String> names = new HashSet<>();
2176        getLastInstAccess().collectAccessNames(names);
2177        for (String name : names) {
2178            collectedNames.add(prefix.isEmpty() ? name : prefix +"." + name);
2179        }
2180    }
2181
2182    @Override
2183    public void InstGlobalAccess.collectAccessNames(Set<String> collectedNames) {
2184        getInstAccess().collectAccessNames(collectedNames);
2185    }
2186
2187    @Override
2188    public void InstArrayAccess.collectAccessNames(Set<String> collectedNames) {
2189        myInstComponentElement().collectScalarPrimitives(collectedNames);
2190    }
2191
2192    @Override
2193    public void InstClassAccess.collectAccessNames(Set<String> collectedNames) {
2194    }
2195
2196    @Override
2197    public void InstScalarAccess.collectAccessNames(Set<String> collectedNames) {
2198        myInstComponentDecl().collectScalarPrimitives(collectedNames);
2199    }
2200
2201    public void InstComponentDecl.collectScalarPrimitives(Set<String> collectedNames) {
2202        for (InstComponentDecl instComponentDecl : getInstComponentDecls()) {
2203            instComponentDecl.collectScalarPrimitives(collectedNames);
2204        }
2205    }
2206
2207    @Override
2208    public void InstPrimitive.collectScalarPrimitives(Set<String> collectedNames) {
2209        final String qualifiedName = qualifiedName();
2210
2211        if (isArray()) {
2212            for (Index index : Indices.create(size())) {
2213                collectedNames.add(qualifiedName + index);
2214            }
2215        } else if (!isForIndex()) {
2216            collectedNames.add(qualifiedName);
2217        }
2218    }
2219
2220    public void FArraySubscripts.collectAccessNames(Set<String> collectedNames) {
2221    }
2222
2223    @Override
2224    public void FArrayExpSubscripts.collectAccessNames(Set<String> collectedNames) {
2225        for (FSubscript sub : getFSubscripts()) {
2226            sub.collectAccessNames(collectedNames);
2227        }
2228    }
2229
2230
2231    public void FSubscript.collectAccessNames(Set<String> collectedNames) {
2232    }
2233
2234    @Override
2235    public void FExpSubscript.collectAccessNames(Set<String> collectedNames) {
2236        getFExp().collectAccessNames(collectedNames);
2237    }
2238
2239    @Override
2240    public void FIterExp.collectAccessNames(Set<String> collectedNames) {
2241        for (CommonForIndex cfi : getForIndexs()) {
2242            cfi.collectAccessNames(collectedNames);
2243        }
2244       
2245        getFExp().collectAccessNames(collectedNames);
2246    }
2247
2248    public abstract void CommonForIndex.collectAccessNames(Set<String> collectedNames);
2249
2250    @Override
2251    public void FForIndex.collectAccessNames(Set<String> collectedNames) {
2252        throw new UnsupportedOperationException();
2253    }
2254
2255    @Override
2256    public void InstForIndexWithExp.collectAccessNames(Set<String> collectedNames) {
2257        getFExp().collectAccessNames(collectedNames);
2258    }
2259
2260    @Override
2261    public void InstForIndexNoExp.collectAccessNames(Set<String> collectedNames) {
2262    }
2263
2264    public void InstAccess.collectAccessNamesInArraySubscripts(Set<String> collectedNames) {
2265    }
2266
2267    @Override
2268    public void InstDot.collectAccessNamesInArraySubscripts(Set<String> collectedNames) {
2269        for (InstAccess access : getInstAccesss()) {
2270            access.collectAccessNamesInArraySubscripts(collectedNames);
2271        }
2272    }
2273
2274    @Override
2275    public void InstGlobalAccess.collectAccessNamesInArraySubscripts(Set<String> collectedNames) {
2276        getInstAccess().collectAccessNamesInArraySubscripts(collectedNames);
2277    }
2278
2279    @Override
2280    public void InstArrayAccess.collectAccessNamesInArraySubscripts(Set<String> collectedNames) {
2281        if (myInstComponentDecl().isPrimitive()) {
2282            getFArraySubscripts().collectAccessNames(collectedNames);
2283        }
2284    }
2285
2286
2287    /**
2288     * If this is an overloaded operator expression, evaluate it as such, otherwise return null.
2289     */
2290    syn CValue FExp.cevalOverloaded(VariableEvaluator evaluator) {
2291        if (!shouldUseOverloadedOperator() || operatorName() == null)
2292            return null;
2293        InstClassDecl func = overloadedOperator();
2294        return (func == null) ? CValue.UNKNOWN : func.evaluateFirst(evaluator, childFExps());
2295    }
2296
2297    /**
2298     * Check if this expression can be constant evaluated.
2299     *
2300     * Calls ceval and checks that no exception is thrown, and that the result isn't unknown.
2301     * Use only for error checking, since it does not guarantee that the expression can be
2302     * evaluated at the moment - only after calculating overconstrained connection graph.
2303     */
2304    syn boolean FExp.canCeval() = canCeval(defaultVariableEvaluator());
2305   
2306    syn boolean FExp.canCeval(VariableEvaluator evaluator) {
2307          try {
2308              return !ceval(evaluator).isUnknown();
2309        } catch (ConstantEvaluationNotReadyException e) {
2310          // Will be evaluatable later, ignore for now
2311          return true;
2312          } catch (Exception e) {
2313              return false;
2314          }
2315    }
2316   
2317    /**
2318     * Constant evaluation for arrays.
2319     *
2320     * @param i  the index of the cell to calculate,
2321     *           where Index.NULL means to calculate all cells
2322     * @see #ceval()
2323     */
2324    syn CValue FExp.cevalArray(Index i) = cevalArray(defaultVariableEvaluator(), i);
2325    syn CValue FExp.cevalArray(VariableEvaluator evaluator, Index i) {
2326        CValueArray res = new CValueArray(size());
2327        if (size().evaluated().isUnknown())
2328            return CValue.UNKNOWN;
2329        Array arr = getArray();
2330        if (i == Index.NULL)
2331          for (Index j : arr.indices())
2332              res.setCell(j, arr.get(j).ceval(evaluator));
2333        else if (size().isOKIndex(i))
2334          res.setCell(i, arr.get(i).ceval(evaluator));
2335        else
2336          throw new ConstantEvaluationException();
2337        return res;
2338    }
2339   
2340    eq FDeferExp.cevalArray(VariableEvaluator evaluator, Index i) = getFExp().cevalArray(evaluator, i);
2341   
2342    // Bypass for nodes with inherent support for constant evaluation of arrays.
2343    eq FFunctionCall.cevalArray(VariableEvaluator evaluator, Index i)    = cevalCalc(evaluator);
2344    eq InstFunctionCall.cevalArray(VariableEvaluator evaluator, Index i) = cevalCalc(evaluator);
2345    eq CommonAccessExp.cevalArray(VariableEvaluator evaluator, Index i)  = isSlice() ? super.cevalArray(evaluator, i) : cevalCalc(evaluator);
2346    eq FIfExp.cevalArray(VariableEvaluator evaluator, Index i)           = cevalSelectExp(evaluator).cevalArray(evaluator, i);
2347
2348    /**
2349     * Delegate attribute for ceval().
2350     *
2351     * This needs to be overridden for subclasses of FExp.
2352     */
2353    syn CValue FExp.cevalCalc(VariableEvaluator evaluator);
2354    eq FUnsupportedExp.cevalCalc(VariableEvaluator evaluator) = CValue.UNSUPPORTED;
2355    eq FAbstractArrayExp.cevalCalc(VariableEvaluator evaluator) { throw new ConstantEvaluationException(null, "Can not evaluate scalar array expression ");}
2356    eq InstPreExp.cevalCalc(VariableEvaluator evaluator) = CValue.UNSUPPORTED;
2357    eq FNoExp.cevalCalc(VariableEvaluator evaluator) = CValue.UNSUPPORTED;
2358
2359    eq FTimeExp.cevalCalc(VariableEvaluator evaluator) = evaluator.timeValue();
2360   
2361    eq FInStreamEpsExp.cevalCalc(VariableEvaluator evaluator) = evaluator.inStreamEpsilon();
2362
2363    eq FDeferExp.cevalCalc(VariableEvaluator evaluator) = getFExp().ceval(evaluator);
2364   
2365    eq FBinExp.cevalCalc(VariableEvaluator evaluator) = evaluator.evalBinOp(this, getLeft().ceval(evaluator), getRight().ceval(evaluator));
2366    eq FDotMulExp.cevalCalc(VariableEvaluator evaluator) {
2367        CValue left = getLeft().ceval(evaluator);
2368        CValue right = getRight().ceval(evaluator);
2369        if (left.isZero() || right.isZero()) {
2370            return type().zeroCValue();
2371        }
2372        return evaluator.evalBinOp(this, left, right);
2373    }
2374    eq FDotDivExp.cevalCalc(VariableEvaluator evaluator) {
2375        CValue left = getLeft().ceval(evaluator);
2376        CValue right = getRight().ceval(evaluator);
2377        if (left.isZero()) {
2378            return type().zeroCValue();
2379        }
2380        return evaluator.evalBinOp(this, left, right);
2381    }
2382   
2383
2384    eq FMulExp.cevalCalc(VariableEvaluator evaluator) {
2385        if (isElementWise() || isArray())
2386          return super.cevalCalc(evaluator);
2387       
2388        FType t = type();
2389        CValue sum = new CValueInteger(0);
2390        CValueArray l = getLeft().ceval(evaluator).array();
2391        CValueArray r = getRight().ceval(evaluator).array();
2392        for (Index i : l.indices())
2393          sum = t.add(sum, t.mul(l.getCell(i), r.getCell(i)));
2394        return sum;
2395    }
2396
2397    syn CValue FBinExp.cevalEval(CValue left, CValue right);
2398    eq FDotAddExp.cevalEval(CValue left, CValue right) = type().add(left, right);
2399    eq FDotSubExp.cevalEval(CValue left, CValue right) = type().sub(left, right);
2400    eq FDotMulExp.cevalEval(CValue left, CValue right) = type().mul(left, right);
2401    eq FDotDivExp.cevalEval(CValue left, CValue right) = type().div(left, right);
2402    eq FDotPowExp.cevalEval(CValue left, CValue right) = type().pow(left, right);
2403   
2404    eq FAndExp.cevalEval(CValue left, CValue right) = type().and(left, right);
2405    eq FOrExp.cevalEval(CValue left, CValue right)  = type().or(left, right);
2406   
2407    syn FType FRelExp.cevalType() = getLeft().type().typePromotion(getRight().type());
2408   
2409    eq FEqExp.cevalEval(CValue left, CValue right)  = cevalType().equ(left, right);
2410    eq FNeqExp.cevalEval(CValue left, CValue right) = cevalType().neq(left, right);
2411    eq FGtExp.cevalEval(CValue left, CValue right)  = cevalType().gt(left, right);
2412    eq FGeqExp.cevalEval(CValue left, CValue right) = cevalType().geq(left, right);
2413    eq FLtExp.cevalEval(CValue left, CValue right)  = cevalType().lt(left, right);
2414    eq FLeqExp.cevalEval(CValue left, CValue right) = cevalType().leq(left, right);
2415   
2416    eq FUnaryExp.cevalCalc(VariableEvaluator evaluator) = evaluator.evalUnOp(this, getFExp().ceval(evaluator));
2417   
2418    syn CValue FUnaryExp.cevalEval(CValue val);
2419    eq InstDerExp.cevalEval(CValue val) { 
2420        throw new ConstantEvaluationException(null, 
2421                 "Doesn't support evaluation of derivatives." + System.lineSeparator() +
2422                 "Replace expression with a variable and provide the value."); 
2423    }
2424   
2425    /**
2426     * Doesn't support evaluation of derivatives due to potential problems with
2427     * use of the Differentiation framework in the instance tree before the transformation steps.
2428     */
2429    eq InstDerExp.cevalCalc(VariableEvaluator evaluator) {
2430        throw new ConstantEvaluationException(null, 
2431                 "Doesn't support evaluation of derivatives." + System.lineSeparator() +
2432                 "Replace expression with a variable and provide the value.");
2433    }
2434   
2435
2436    eq FNegExp.cevalEval(CValue val) = type().neg(val);
2437    eq FNotExp.cevalEval(CValue val) = type().not(val);
2438
2439
2440    eq FIfExp.cevalCalc(VariableEvaluator evaluator) = cevalSelectExp(evaluator).ceval(evaluator);
2441    eq FHomotopyExp.cevalCalc(VariableEvaluator evaluator)   = getActual().ceval(evaluator);
2442    eq FSemiLinearExp.cevalCalc(VariableEvaluator evaluator) = type().mul(getX().ceval(evaluator),cevalSelectExp(evaluator).ceval(evaluator));
2443
2444    syn FExp FIfExp.cevalSelectExp() = cevalSelectExp(defaultVariableEvaluator());
2445    syn FExp FIfExp.cevalSelectExp(VariableEvaluator evaluator) =
2446        getIfExp().ceval(evaluator).booleanValue() ? getThenExp() : getElseExp();
2447    syn FExp FSemiLinearExp.cevalSelectExp(VariableEvaluator evaluator) = type().geq(getX().ceval(evaluator), type().zeroCValue()).booleanValue() ? getPosSlope() : getNegSlope();
2448
2449    eq FRecordConstructor.cevalCalc(VariableEvaluator evaluator) {
2450        CValueRecord res = new CValueRecord((FRecordType) type());
2451        int i = 0;
2452        for (FExp arg : getArgs())
2453          res.setMember(i++, arg.ceval(evaluator));
2454        return res;
2455    }
2456
2457    eq InstRecordConstructor.cevalCalc(VariableEvaluator evaluator) {
2458        CValueRecord res = new CValueRecord((FRecordType) type());
2459        int i = 0;
2460        for (InstComponentDecl icd : getRecord().myInstClassDecl().allInstComponentDecls()) {
2461            CValue val;
2462            if (icd.isModifiable()) {
2463                val = getArg(i).getFExp().ceval(evaluator);
2464            } else {
2465                val = icd.ceval(evaluator);
2466            }
2467            res.setMember(i++, val);
2468        }
2469        return res;
2470    }
2471   
2472    eq FComponentExp.cevalCalc(VariableEvaluator evaluator) = getFExp().ceval().component(getName());
2473   
2474    public CValue CValue.component(String name) {
2475        return CValue.UNKNOWN;
2476    }
2477   
2478    public CValue CValueRecord.component(String name) {
2479        return getMember(name);
2480    }
2481   
2482    eq FEndExp.cevalCalc(VariableEvaluator evaluator) = mySize().ceval(evaluator, 0);
2483    eq FNdimsExp.cevalCalc(VariableEvaluator evaluator) = new CValueInteger(getFExp().ndims());
2484   
2485    eq FSubscriptedExp.cevalCalc(VariableEvaluator evaluator) {
2486        Index i = getFArraySubscripts().createIndex(evaluator);
2487        return getFExp().ceval(evaluator, i).getCell(i);
2488    }
2489
2490    eq FCardinality.cevalCalc(VariableEvaluator evaluator) {
2491        final int v = getFExp().cardinalityValue();
2492        return (v <= 0) ? CValue.UNKNOWN : new CValueInteger(v);
2493    }
2494
2495    eq FDecouple.cevalCalc(VariableEvaluator evaluator) = getFExp().ceval(evaluator);
2496
2497    eq FConnectionsOp.cevalCalc(VariableEvaluator evaluator) {
2498        throw new ConstantEvaluationException();
2499    }
2500    eq FConnBoolOp.cevalCalc(VariableEvaluator evaluator) {
2501        if (connectionGraph != null && connectionGraph.builtTreesDone()) 
2502          return new CValueBoolean(cevalFromGraph());
2503        else
2504          throw new ConstantEvaluationNotReadyException();
2505    }
2506
2507    syn boolean FConnBoolOp.cevalFromGraph();
2508    eq FConnIsRoot.cevalFromGraph() = connectionGraph.ops(getA()).isRoot;
2509    eq FConnRooted.cevalFromGraph() = connectionGraph.ops(getA()).rooted;
2510
2511    eq FTerminate.cevalCalc(VariableEvaluator evaluator) {
2512        throw new ConstantEvaluationException();
2513    }
2514    eq FReinit.cevalCalc(VariableEvaluator evaluator) {
2515        throw new ConstantEvaluationException();
2516    }
2517    eq FAssert.cevalCalc(VariableEvaluator evaluator) {
2518        throw new ConstantEvaluationException();
2519    }
2520
2521    eq FDelayExp.cevalCalc(VariableEvaluator evaluator) = getFExp().ceval(evaluator);
2522    eq FSpatialDistExp.cevalCalc(VariableEvaluator evaluator) = evaluate(evaluator)[0];
2523   
2524    public CValue[] FSpatialDistExp.evaluate(VariableEvaluator evaluator) {
2525        CValue[] res = new CValue[2];
2526        CValueArray vals = getInitialValues().ceval(evaluator).array();
2527        if (getPositiveVelocity().ceval(evaluator).booleanValue()) {
2528            res[1] = vals.getCell(vals.values.length-1);
2529            res[0] = vals.getCell(0);
2530        } else {
2531            res[0] = vals.getCell(vals.values.length-1);
2532            res[1] = vals.getCell(0);
2533        }
2534        return res;
2535    }
2536   
2537    /**
2538     * The connections graph to use when constat evaluating a Connections.x() operator with boolean result.
2539     */
2540    protected OverconstrainedConnectionGraph FConnBoolOp.connectionGraph = null;
2541
2542    eq FSizeExp.cevalCalc(VariableEvaluator evaluator) =
2543            getFExp().size().ceval(evaluator, dimension());
2544    eq FUnknownSizeExp.cevalCalc(VariableEvaluator evaluator) =
2545            inFunction() ? getFExp().cevalCalc(evaluator).size().ceval(evaluator, dimension()) : CValue.UNKNOWN;
2546   
2547    public CValue Size.ceval(VariableEvaluator evaluator, int d) {
2548        int s = get(d);
2549        return (s == Size.UNKNOWN) ? CValue.UNKNOWN : new CValueInteger(s);
2550    }
2551
2552    eq FMinMaxExp.cevalCalc(VariableEvaluator evaluator) {
2553        if (hasY()) {
2554          CValue x = getX().ceval(evaluator);
2555          CValue y = getY().ceval(evaluator);
2556          boolean selectX = type().lt(x, y).booleanValue() ^ !selectLesser();
2557          return selectX ? x : y;
2558        } else {
2559            if (getX().size().evaluated().isUnknown())
2560                return CValue.UNKNOWN;
2561          Iterator<FExp> it = getX().getArray().iteratorFExp();
2562          boolean less = selectLesser();
2563          CValue sel = it.next().ceval(evaluator);
2564          while (it.hasNext()) {
2565              CValue val = it.next().ceval(evaluator);
2566              if (type().lt(val, sel).booleanValue() ^ !less)
2567                  sel = val;
2568          }
2569          return sel;
2570        }
2571    }
2572
2573    eq FReductionExp.cevalCalc(VariableEvaluator evaluator) {
2574        if (getFExp().size().evaluated().isUnknown())
2575            return CValue.UNKNOWN;
2576        Iterator<FExp> it = getFExp().getArray().iteratorFExp();
2577        CValue value = reduceStartValue();
2578        while (it.hasNext())
2579          value = reduceOperation(value, it.next().ceval(evaluator));
2580        return value;
2581    }
2582
2583    syn CValue FReductionExp.reduceStartValue();
2584    eq FSumExp.reduceStartValue()     = type().createCValue(0);
2585    eq FProductExp.reduceStartValue() = type().createCValue(1);
2586
2587    syn CValue FBuiltInFunctionCall.scalarReduceStartValue() = CValue.UNKNOWN;
2588    eq FSumExp.scalarReduceStartValue()     = type().createCValueScalar(0);
2589    eq FProductExp.scalarReduceStartValue() = type().createCValueScalar(1);
2590    eq FMaxExp.scalarReduceStartValue()     = type().limitCValueScalar(false);
2591    eq FMinExp.scalarReduceStartValue()     = type().limitCValueScalar(true);
2592
2593    syn CValue FReductionExp.reduceOperation(CValue leftValue, CValue rightValue);
2594    eq FSumExp.reduceOperation(CValue leftValue, CValue rightValue)     = type().add(leftValue, rightValue);
2595    eq FProductExp.reduceOperation(CValue leftValue, CValue rightValue) = type().mul(leftValue, rightValue);
2596
2597
2598    eq FNoEventExp.cevalCalc(VariableEvaluator evaluator) = getFExp().ceval(evaluator);
2599    eq FSmoothExp.cevalCalc(VariableEvaluator evaluator)  = getFExp().ceval(evaluator);
2600    eq FLoadResource.cevalCalc(VariableEvaluator evaluator) {
2601        String arg = getFExp().ceval(evaluator).stringValue();
2602        if (!new File(arg).isAbsolute())
2603            arg = URIResolver.DEFAULT.resolve(this, arg).replace("\\", "\\\\");
2604        return new CValueString(arg);
2605    }
2606
2607    eq FEdgeExp.cevalCalc(VariableEvaluator evaluator)    = variability().constantVariability() ? CValueBoolean.FALSE : CValue.UNKNOWN;
2608    eq FChangeExp.cevalCalc(VariableEvaluator evaluator)  = variability().constantVariability() ? CValueBoolean.FALSE : CValue.UNKNOWN;
2609    eq FSampleExp.cevalCalc(VariableEvaluator evaluator)  = CValue.UNKNOWN;
2610
2611    /** Decides what initial() is currently evaluated to. */
2612    private static CValue FInitialExp.evaluationValue = CValueBoolean.FALSE;
2613
2614    /** Set the value for initial() to evaluate to. */
2615    public static void FInitialExp.setIsInitial(boolean value) {
2616          evaluationValue = new CValueBoolean(value);
2617    }
2618
2619    /** Set if constant evaluation should consider simulation to be during initialization or not. */
2620    public void FClass.setIsInitial(boolean initial) {
2621          FInitialExp.setIsInitial(initial);
2622    }
2623
2624    eq FInitialExp.cevalCalc(VariableEvaluator evaluator)  = evaluationValue;
2625    eq FTerminalExp.cevalCalc(VariableEvaluator evaluator) = CValueBoolean.FALSE;
2626
2627    syn boolean FMinMaxExp.selectLesser();
2628    eq FMinExp.selectLesser() = true;
2629    eq FMaxExp.selectLesser() = false;
2630
2631    eq FRealLitExp.cevalCalc(VariableEvaluator evaluator)         = new CValueReal(getValue());
2632    eq FIntegerLitExp.cevalCalc(VariableEvaluator evaluator)      = new CValueInteger(getValue());
2633    eq FBooleanLitExpTrue.cevalCalc(VariableEvaluator evaluator)  = new CValueBoolean(true);
2634    eq FBooleanLitExpFalse.cevalCalc(VariableEvaluator evaluator) = new CValueBoolean(false);
2635    eq FStringLitExp.cevalCalc(VariableEvaluator evaluator)       = new CValueString(unEscape());
2636    eq FEnumLitExp.cevalCalc(VariableEvaluator evaluator)         = new CValueEnum(type(), getValue());
2637
2638    syn CValue CommonAccess.unknownCValue() = new CValueUnknownAccess(name());
2639
2640    syn CValue CommonAccess.ceval(VariableEvaluator evaluator);
2641    eq FAccess.ceval(VariableEvaluator evaluator) {
2642        boolean func = inFunction();
2643        FAbstractVariable var = myFV();
2644        if (var != null && !var.isUnknown()) {
2645            Index i = Index.NULL;
2646            if (var.ndims() > 0 && hasFArraySubscripts()) {
2647                i = getFArraySubscripts().createIndex(evaluator);
2648            }
2649            if (i != Index.NULL) {
2650                if(var.inRecord()) {
2651                    CValue cevalRecordMember = cevalRecordMember(evaluator, this);
2652                    if (cevalRecordMember.isUnknown()) {
2653                        return CValue.UNKNOWN; 
2654                    } else {
2655                        return cevalRecordMember.getCell(i);
2656                    }
2657                } else {
2658                    return evaluator.ceval(var, i);
2659                }
2660            } else {
2661                return var.inRecord() ? cevalRecordMember(evaluator, this) : evaluator.ceval(var);
2662            }
2663        } else {
2664            return unknownCValue();
2665        }
2666    }
2667
2668    /**
2669     * Perform constant evaluation of an access to a record member.
2670     */
2671    syn CValue FAccess.cevalRecordMember(VariableEvaluator evaluator, FAccess name) {
2672        if (name.numDots() < 1)
2673          return CValue.UNKNOWN;
2674        String last = name.lastActualPartName();
2675        FAccess prefix = name.copyPrefix();
2676        prefix.parent = this;
2677        FAbstractVariable var = prefix.myFV();
2678        CValue res = var.inRecord() ? cevalRecordMember(evaluator, prefix) : evaluator.ceval(var);
2679        if (res.isUnknown()) return CValue.UNKNOWN;
2680        if (prefix.hasFArraySubscripts())
2681          res = res.getCell(prefix.getFArraySubscripts().createIndex(evaluator));
2682        if (res.isUnknown()) return CValue.UNKNOWN;
2683        return res.record().getMember(last);
2684    }
2685
2686    eq CommonAccessExp.cevalCalc(VariableEvaluator evaluator) = evaluator.cevalUse(this);
2687   
2688    syn CValue CommonAccessExp.cevalUse(VariableEvaluator evaluator) = getAccess().ceval(evaluator);
2689    eq FAbstractDerExp.cevalUse(VariableEvaluator evaluator) {
2690        if (getFAccess().variability().discreteOrLess())
2691            return new CValueInteger(0);
2692        FAbstractVariable decl = myFV();
2693        return decl == null ? CValue.UNKNOWN : evaluator.ceval(decl);
2694    }
2695    eq FPreExp.cevalUse(VariableEvaluator evaluator) {
2696        if (variability().constantVariability())
2697            return super.cevalUse(evaluator);
2698        FAbstractVariable decl = myFV();
2699        return decl == null ? CValue.UNKNOWN : evaluator.ceval(decl);
2700    }
2701   
2702   
2703    syn CValue InstAccess.ceval(VariableEvaluator evaluator)          = ceval(evaluator, Index.NULL);
2704    syn CValue InstAccess.ceval(VariableEvaluator evaluator, Index i) = unknownCValue();
2705    eq InstDot.ceval(VariableEvaluator evaluator, Index i)            = getLastInstAccess().ceval(evaluator, i);
2706    eq InstGlobalAccess.ceval(VariableEvaluator evaluator, Index i)   = getInstAccess().ceval(evaluator, i);
2707    eq InstNamedAccess.ceval(VariableEvaluator evaluator, Index i) {
2708        CValue res = unknownCValue();
2709        if (myInstComponentDecl().isAssignable()) {
2710          Index iHere = Index.NULL;
2711          InstComponentDecl var = myInstComponentDecl();
2712         
2713          if (isSlice()) {
2714              FArraySubscripts fas = getFArraySubscripts();
2715              iHere = fas.createIndex(evaluator);
2716              i = iHere.expand(i);
2717          }
2718         
2719          if (shouldCevalThroughParent(var)) {
2720              res = cevalRecordMember(evaluator, this);
2721              if (i != Index.NULL)
2722                  res = res.getCell(i);
2723              return res;
2724          } else {
2725              res = evaluator.ceval(var, i);
2726          }
2727          if (iHere != Index.NULL)
2728              res = res.getCell(iHere);
2729        } else if (myInstClassDecl().isEnum()) {
2730            res = new CValueInteger(myInstClassDecl().enumLiterals().size());
2731        } else if (myInstClassDecl().isBoolean()) {
2732            res = new CValueInteger(2);
2733        }
2734        return res;
2735    }
2736
2737    /**
2738     * Check if constant evaluation should go through surrounding record.
2739     */
2740    protected boolean InstNamedAccess.shouldCevalThroughParent(InstComponentDecl var) {
2741        if (!var.inRecord())
2742            return false;
2743        if (!var.inFunction()) 
2744            return !var.hasBindingFExp() && var.hasParentRecordWithBindingExp();
2745        if (containingInstComponent() == var.containingInstComponent())
2746            return false;
2747        InstAccess first = getTopInstAccess().getFirstInstAccess();
2748        return !first.myInstComponentDecl().evaluationValue(defaultVariableEvaluator()).isUnknown();
2749    }
2750
2751    /**
2752     * Check if there is a parent record that has a binding expression.
2753     */
2754    inh boolean InstComponentDecl.hasParentRecordWithBindingExp();
2755    eq Root.getChild().hasParentRecordWithBindingExp()           = false;
2756    eq InstBaseNode.getChild().hasParentRecordWithBindingExp()   = false;
2757    eq InstAssignable.getChild().hasParentRecordWithBindingExp() = 
2758        isRecord() && (hasBindingFExp() || hasParentRecordWithBindingExp());
2759
2760    /**
2761     * Perform constant evaluation of an access to a record member.
2762     */
2763    inh CValue InstAccess.cevalRecordMember(VariableEvaluator evaluator, InstNamedAccess access);
2764    eq BaseNode.getChild().cevalRecordMember(VariableEvaluator evaluator, InstNamedAccess access)          = 
2765        access.myInstComponentDecl().cevalParentRecord(evaluator).record().getMember(access.getID());
2766    eq InstDot.getInstAccess(int i).cevalRecordMember(VariableEvaluator evaluator, InstNamedAccess access) = 
2767        (i == 0) ? cevalRecordMember(evaluator, access) : getInstAccess(i - 1).ceval(evaluator).record().getMember(access.getID());
2768
2769    /**
2770     * Perform constant evaluation of a record member.
2771     */
2772    inh CValue InstComponentDecl.cevalParentRecord(VariableEvaluator evaluator);
2773    eq Root.getChild().cevalParentRecord(VariableEvaluator evaluator)         = CValue.UNKNOWN;
2774    eq InstBaseNode.getChild().cevalParentRecord(VariableEvaluator evaluator) = CValue.UNKNOWN;
2775    eq InstRecord.getChild().cevalParentRecord(VariableEvaluator evaluator)   = 
2776        hasParentRecordWithBindingExp() ? cevalParentRecord(evaluator).record().getMember(name()) : ceval(evaluator);
2777    eq InstArrayComponentDecl.getChild().cevalParentRecord(VariableEvaluator evaluator) {
2778        CValue v = cevalParentRecord(evaluator);
2779        return isArray() ? v : v.getCell(myIndex());
2780    }
2781
2782    // TODO: if caching, use cevalFunction() instead
2783    eq FFunctionCall.cevalCalc(VariableEvaluator evaluator)    = evaluate(evaluator)[0];
2784    eq InstFunctionCall.cevalCalc(VariableEvaluator evaluator) = hasOutputs() ? evaluate(evaluator)[0] : CValue.UNKNOWN;
2785
2786    eq FAbsExp.cevalCalc(VariableEvaluator evaluator)  = type().abs(getFExp().ceval(evaluator));
2787    eq FSignExp.cevalCalc(VariableEvaluator evaluator) = type().sign(getFExp().ceval(evaluator));
2788    eq FSqrtExp.cevalCalc(VariableEvaluator evaluator)  = new CValueReal(StrictMath.sqrt(getFExp().ceval(evaluator).realValue()));
2789    eq FEnumIntegerExp.cevalCalc(VariableEvaluator evaluator) = getFExp().ceval(evaluator).convertInteger();
2790    eq FStringExp.cevalCalc(VariableEvaluator evaluator) {
2791        if (getValue().isArray() || !getValue().type().isPrimitive()) {
2792            return CValue.UNKNOWN;
2793        }
2794       
2795        CValue cval = getValue().ceval(evaluator);
2796        boolean isReal = getValue().type().isReal();
2797        if (isReal) {
2798            cval = cval.convertReal();
2799        }
2800        Object value = cval.objectValue();
2801        final String format = formatString(evaluator);
2802        char formatChar = format.charAt(format.length() - 1);
2803       
2804        // Modelica allows Integer to Real conversion for formatting but not the other direction
2805        boolean mustBeInteger = formatChar == 'd' || formatChar == 'i' || formatChar == 'o' || 
2806            formatChar == 'x' || formatChar == 'X' || formatChar == 'u' || formatChar == 'c';
2807        if (mustBeInteger && isReal) {
2808            throw new ConstantEvaluationException(cval, "format the resulting value. The format '"+ format + "' requires value of Integer type but Real value is provided. ");
2809        }
2810
2811        if (getValue().type().isInteger()) {
2812            // Java formatter do not convert types
2813            final boolean convertToFloat = formatChar == 'e' || formatChar == 'E' || 
2814                    formatChar == 'f' || formatChar == 'g' || formatChar == 'G';
2815            if (convertToFloat) {
2816                return new CValueString(String.format((Locale) null, format, cval.realValue()));
2817            }
2818            if (formatChar == 'u') {
2819                String formatCorrect = format.substring(0, format.length()-1) + "s";
2820                long unsigned = ((long) cval.intValue()) & 0xffffffffL; // Java 8 Integer.toUnsignedLong
2821                return new CValueString(String.format((Locale) null, formatCorrect, unsigned));
2822            }
2823
2824            if (formatChar == 'i') {
2825                String formatCorrect = format.substring(0, format.length()-1) + "d";
2826                return new CValueString(String.format((Locale) null, formatCorrect, cval.intValue()));
2827            }
2828        }
2829       
2830        try {
2831            return new CValueString(String.format((Locale) null, format, value));
2832        } catch (java.util.IllegalFormatException e) {
2833            throw new ConstantEvaluationException(cval, 
2834                    "format the resulting value. " + format + " is not a supported valid format string");
2835        }
2836    }
2837    eq FGetInstanceName.cevalCalc(VariableEvaluator evaluator) = new CValueString(calcInstanceName());
2838
2839    /**
2840     * Calculate the value of a getInstanceName() call.
2841     */
2842    inh String FGetInstanceName.calcInstanceName();
2843    eq FClass.getChild().calcInstanceName() {
2844        throw new UnsupportedOperationException("The getInstanceName() operator is not allowed in the flat tree.");
2845    }
2846
2847    syn String FStringExp.formatString(VariableEvaluator evaluator) {
2848        StringBuilder buf = new StringBuilder("%");
2849        if (hasFormat()) {
2850            buf.append(getFormat().ceval(evaluator).stringValue());
2851        } else {
2852            int minLength = minimumLength(evaluator);
2853            if (minLength > 0) {
2854                if (leftJustified(evaluator)) {
2855                    buf.append('-');
2856                }
2857                buf.append(minLength);
2858            }
2859            if (getValue().type().isReal()) {
2860                buf.append('.');
2861                buf.append(significantDigits(evaluator));
2862            }
2863            buf.append(getValue().type().formatSpecifier());
2864        }
2865        return buf.toString();
2866    }
2867
2868    syn int FStringExp.minimumLength(VariableEvaluator evaluator)     = 
2869        hasMinimumLength() ? getMinimumLength().ceval(evaluator).intValue() : 0;
2870    syn boolean FStringExp.leftJustified(VariableEvaluator evaluator) = 
2871        hasLeftJustified() ? getLeftJustified().ceval(evaluator).booleanValue() : true;
2872    syn int FStringExp.significantDigits(VariableEvaluator evaluator) = 
2873        hasSignificantDigits() ? getSignificantDigits().ceval(evaluator).intValue() : DEFAULT_PRECISION;
2874    syn String FType.formatSpecifier() {
2875        throw new UnsupportedOperationException();
2876    }
2877    eq FRealType.formatSpecifier()    = "g";
2878    eq FIntegerType.formatSpecifier() = "d";
2879    eq FBooleanType.formatSpecifier() = "s";
2880    eq FEnumType.formatSpecifier()    = "s";
2881    eq FStringType.formatSpecifier()  = "s";
2882    public static final int FStringExp.DEFAULT_PRECISION = 6;
2883
2884    eq FDivFuncExp.cevalCalc(VariableEvaluator evaluator)         = type().truncToZero(type().div(getX().ceval(evaluator), getY().ceval(evaluator)));
2885    eq FModFuncExp.cevalCalc(VariableEvaluator evaluator)         = type().sub(getX().ceval(evaluator), type().mul(type().div(getX().ceval(evaluator), getY().ceval(evaluator)).convertInteger(),    getY().ceval(evaluator)));
2886    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)));
2887    eq FCeilFuncExp.cevalCalc(VariableEvaluator evaluator)        = type().ceil(getX().ceval(evaluator));
2888    eq FFloorFuncExp.cevalCalc(VariableEvaluator evaluator)       = getX().ceval(evaluator).convertInteger().convertReal();
2889    eq FIntegerFuncExp.cevalCalc(VariableEvaluator evaluator)     = getX().ceval(evaluator).convertInteger();
2890
2891    eq FSinExp.cevalCalc(VariableEvaluator evaluator)   = new CValueReal(StrictMath.sin(getFExp().ceval(evaluator).realValue()));
2892    eq FCosExp.cevalCalc(VariableEvaluator evaluator)   = new CValueReal(StrictMath.cos(getFExp().ceval(evaluator).realValue()));
2893    eq FTanExp.cevalCalc(VariableEvaluator evaluator)   = new CValueReal(StrictMath.tan(getFExp().ceval(evaluator).realValue()));
2894    eq FAsinExp.cevalCalc(VariableEvaluator evaluator)  = new CValueReal(StrictMath.asin(getFExp().ceval(evaluator).realValue()));
2895    eq FAcosExp.cevalCalc(VariableEvaluator evaluator)  = new CValueReal(StrictMath.acos(getFExp().ceval(evaluator).realValue()));
2896    eq FAtanExp.cevalCalc(VariableEvaluator evaluator)  = new CValueReal(StrictMath.atan(getFExp().ceval(evaluator).realValue()));
2897    eq FAtan2Exp.cevalCalc(VariableEvaluator evaluator) = new CValueReal(StrictMath.atan2(getFExp().ceval(evaluator).realValue(),
2898                                                               getY().ceval(evaluator).realValue()));
2899    eq FSinhExp.cevalCalc(VariableEvaluator evaluator)  = new CValueReal(StrictMath.sinh(getFExp().ceval(evaluator).realValue()));
2900    eq FCoshExp.cevalCalc(VariableEvaluator evaluator)  = new CValueReal(StrictMath.cosh(getFExp().ceval(evaluator).realValue()));
2901    eq FTanhExp.cevalCalc(VariableEvaluator evaluator)  = new CValueReal(StrictMath.tanh(getFExp().ceval(evaluator).realValue()));
2902    eq FExpExp.cevalCalc(VariableEvaluator evaluator)   = new CValueReal(StrictMath.exp(getFExp().ceval(evaluator).realValue()));
2903    eq FLogExp.cevalCalc(VariableEvaluator evaluator)   = new CValueReal(StrictMath.log(getFExp().ceval(evaluator).realValue()));
2904    eq FLog10Exp.cevalCalc(VariableEvaluator evaluator) = new CValueReal(StrictMath.log10(getFExp().ceval(evaluator).realValue()));
2905
2906    eq FExInStream.cevalCalc(VariableEvaluator evaluator) {
2907        int n = 0;
2908        for (InStreamPart cont : contributors()) {
2909            n++;
2910            break;
2911        }
2912        if (n == 0) {
2913            return getDefault().ceval(evaluator);
2914        } else if (n == 1) {
2915            return contributors().iterator().next().stream.ceval(evaluator);
2916        } else {
2917            double eps = -1.0;
2918            double val = 0.0;
2919            double sum = 0.0;
2920            double div = 0.0;
2921            for (InStreamPart cont : contributors()) {
2922                double flow = cont.flow.ceval(evaluator).realValue();
2923                if (!cont.outside) {
2924                    flow = -flow;
2925                }
2926                if (eps < 0.0) {
2927                    eps = getEps().ceval(evaluator).realValue();
2928                }
2929                flow = Math.max(flow, eps);
2930                sum += flow * cont.stream.ceval(evaluator).realValue();
2931                div += flow;
2932            }
2933            return new CValueReal(sum / div);
2934        }
2935    }
2936
2937    eq FScalarExp.cevalCalc(VariableEvaluator evaluator) = getFExp().ceval(evaluator).array().getCell(0);
2938
2939    syn CValue FSubscript.ceval() = ceval(defaultVariableEvaluator());
2940        syn CValue FSubscript.ceval(VariableEvaluator evaluator) = CValue.UNSUPPORTED;
2941        eq FExpSubscript.ceval(VariableEvaluator evaluator)      = getFExp().ceval(evaluator);
2942        eq FIntegerSubscript.ceval(VariableEvaluator evaluator)  = new CValueInteger(getValue());
2943       
2944        syn int FSubscript.value()   = ceval(defaultVariableEvaluator()).intValue();
2945        eq FIntegerSubscript.value() = getValue();
2946       
2947    public int Subscript.value(VariableEvaluator evaluator);
2948    public int FSubscript.value(VariableEvaluator evaluator) { return ceval(evaluator).intValue();}
2949    public int IntegerSubscript.value(VariableEvaluator evaluator) { return value();}
2950
2951    syn CValue InstComponentDecl.ceval() = ceval(defaultVariableEvaluator());
2952        syn CValue InstComponentDecl.ceval(VariableEvaluator evaluator) = 
2953                (evaluationValue == null) ? CValue.UNKNOWN : evaluationValue;
2954    syn CValue InstComponentDecl.ceval(VariableEvaluator evaluator, Index i) = CValue.UNKNOWN;
2955
2956        /**
2957         * Evaluation of a assignable instance node located in the instance
2958         * AST.
2959         *
2960         * In some situations, expressions are evaluated in the instance AST.
2961         * Such expressions are then instantiated, but not yet flattened. As a
2962         * consequence, identifiers in expressions refers to InstAssignable nodes,
2963         * and accordingly, it it necessary to compute the constant value
2964         * corresponding to an InstAssignable node. If the assignable is a
2965         * constant or a parameter, and if it has a binding expression, then
2966         * a corresponding CValue object is returned, otherwise, CValueUnknown
2967         * is returned.
2968         *
2969         * @return The constant value.
2970         */
2971        eq InstAssignable.ceval(VariableEvaluator evaluator) = ceval(evaluator, Index.NULL);
2972       
2973
2974    /**
2975     * Evaluation of a assignable instance node located in the instance
2976     * AST. Evaluates a specific cell if this assignable is an array.
2977     *
2978     * If assignable is not an array, <code>i</code> should be Index.NULL.
2979     * 
2980     * In some situations, expressions are evaluated in the instance AST.
2981     * Such expressions are then instantiated, but not yet flattened. As a
2982     * consequence, identifiers in expressions refers to InstAssignable nodes,
2983     * and accordingly, it it necessary to compute the constant value
2984     * corresponding to an InstAssignable node. If the assignable is a
2985     * constant or a parameter, and if it has a binding expression, then
2986     * a corresponding CValue object is returned, otherwise, CValueUnknown
2987     * is returned. If the variable has <code>evaluationValue</code> set,
2988     * then that value is always returned.
2989     *
2990     * Outside of functions, the calculated value is cached.
2991     *
2992     * @return The constant value.
2993     */
2994    eq InstAssignable.ceval(VariableEvaluator evaluator, Index i) {
2995        CValue val = CValue.UNKNOWN;
2996        if (hasEvaluationValue(evaluator)) {
2997            val = evaluationValue(evaluator);
2998        } else if ((variability().fixedParameterOrLess() || (inFunction() && !isInput())) && !isForIndex()) {
2999            boolean func = inFunction();
3000            i = func ? i : Index.NULL;
3001            if (hasBindingFExp()) {
3002                FExp bexp = getBindingFExp();
3003                if (!bexp.type().isUnknown())
3004                    val = bexp.ceval(evaluator, i);
3005            } else if ((!func && !inRecordDecl()) || isRecord()) {
3006                val = cevalNoBExp(evaluator, i);
3007            }
3008            if (!func) {
3009                setEvaluationValue(evaluator, val);
3010            }
3011        }
3012        return val;
3013    }
3014   
3015    eq InstExternalObject.ceval(VariableEvaluator evaluator, Index i) {
3016        CValue val = super.ceval(evaluator, i);
3017        val.markExternalObject(qualifiedName());
3018        return val;
3019    }
3020   
3021    syn CValue InstAssignable.cevalNoBExp(VariableEvaluator evaluator, Index i) {
3022        CValue val = startAttributeCValue(evaluator);
3023        if (i != Index.NULL) 
3024            val = val.getCell(i);
3025        if ((isInteger() || isReal() || isEnum()) && !val.isUnknown()) {
3026            try {
3027                CValue min = minAttributeCValue(evaluator);
3028                if (i != Index.NULL) 
3029                    min = min.getCell(i);
3030                CValue max = maxAttributeCValue(evaluator);
3031                if (i != Index.NULL) 
3032                    max = max.getCell(i);
3033                val =  val.constrainWithin(min, max);
3034            } catch (ConstantEvaluationException e) {}
3035        }
3036        return val;
3037    }
3038   
3039    eq InstRecord.cevalNoBExp(VariableEvaluator evaluator, Index i) {
3040        if (isArray()) {
3041            if (size().isUnknown()) {
3042                return CValue.UNKNOWN;
3043            }
3044            CValueArray val = new CValueArray(size());
3045            if (size().numElements() > 0) {
3046                cevalNoBExpArray(evaluator, this, val, ndims());
3047            }
3048            return i == Index.NULL ? val : val.getCell(i);
3049        } else {
3050            return cevalNoBExpCell(evaluator, allInstComponentDecls());
3051        }
3052    }
3053
3054    eq InstExternalObject.cevalNoBExp(VariableEvaluator evaluator, Index i) = CValue.UNKNOWN;
3055
3056    public void InstComponentDecl.cevalNoBExpArray(VariableEvaluator evaluator, InstRecord top, CValueArray a, int ndims) {
3057        if (ndims > 0) {
3058            for (InstComponentDecl icd : allInstComponentDecls()) {
3059                icd.cevalNoBExpArray(evaluator, top, a, ndims-1);
3060            }
3061        } else {
3062            a.addCell(top.cevalNoBExpCell(evaluator, allInstComponentDecls()));
3063        }
3064    }
3065   
3066    syn CValue InstRecord.cevalNoBExpCell(VariableEvaluator evaluator, Iterable<InstComponentDecl> icds) {
3067        CValueRecord rec = new CValueRecord(myInstClass().recordType());
3068        for (InstComponentDecl icd : icds) {
3069            rec.setMember(icd.name(), icd.ceval(evaluator));
3070        }
3071        return rec;
3072    }
3073
3074    // Can never be an array - assume i == Index.NULL
3075    eq InstEnumLiteral.ceval(VariableEvaluator evaluator, Index i) = new CValueEnum(type(), myIndex());
3076
3077
3078    /**
3079     * Find and evaluate the "start" attribute. If it is not found, use default value.
3080     */
3081    syn CValue InstComponentDecl.startAttributeCValue(VariableEvaluator evaluator)  = CValue.UNKNOWN;
3082    syn lazy CValue InstPrimitive.startAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.START);
3083
3084    /**
3085     * Find and evaluate the "fixed" attribute. If it is not found, use default value.
3086     */
3087    syn CValue InstComponentDecl.fixedAttributeCValue() = fixedAttributeCValue(defaultVariableEvaluator());
3088    syn CValue InstComponentDecl.fixedAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.FIXED);
3089
3090    /**
3091     * Find and evaluate the "quantity" attribute. If it is not found, use default value.
3092     */
3093    syn CValue InstComponentDecl.quantityAttributeCValue() = quantityAttributeCValue(defaultVariableEvaluator());
3094    syn CValue InstComponentDecl.quantityAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.QUANTITY);
3095
3096    /**
3097     * Find and evaluate the "unit" attribute. If it is not found, use default value.
3098     */
3099    syn CValue InstComponentDecl.unitAttributeCValue() = unitAttributeCValue(defaultVariableEvaluator());
3100    syn CValue InstComponentDecl.unitAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.UNIT);
3101
3102    /**
3103     * Find and evaluate the "displayUnit" attribute. If it is not found, use default value.
3104     */
3105    syn CValue InstComponentDecl.displayUnitAttributeCValue() = displayUnitAttributeCValue(defaultVariableEvaluator());
3106    syn CValue InstComponentDecl.displayUnitAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.DISPLAY_UNIT);
3107
3108    /**
3109     * Find and evaluate the "min" attribute. If it is not found, use default value.
3110     */
3111    syn CValue InstComponentDecl.minAttributeCValue() = minAttributeCValue(defaultVariableEvaluator());
3112    syn CValue InstComponentDecl.minAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.MIN);
3113
3114    /**
3115     * Find and evaluate the "max" attribute. If it is not found, use default value.
3116     */
3117    syn CValue InstComponentDecl.maxAttributeCValue() = maxAttributeCValue(defaultVariableEvaluator());
3118    syn CValue InstComponentDecl.maxAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.MAX);
3119
3120    /**
3121     * Find and evaluate the "nominal" attribute. If it is not found, use default value.
3122     */
3123    syn CValue InstComponentDecl.nominalAttributeCValue() = nominalAttributeCValue(defaultVariableEvaluator());
3124    syn CValue InstComponentDecl.nominalAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.NOMINAL);
3125
3126    /**
3127     * Find and evaluate the "stateSelect" attribute. If it is not found, use default value.
3128     */
3129    syn CValue InstComponentDecl.stateSelectAttributeCValue() = stateSelectAttributeCValue(defaultVariableEvaluator());
3130    syn CValue InstComponentDecl.stateSelectAttributeCValue(VariableEvaluator evaluator) = attributeCValueGeneric(evaluator, FAttribute.STATE_SELECT);
3131
3132    /**
3133     * Find and evaluate the attribute <code>name</code>. If it is not found, use default value.
3134     */
3135    syn CValue InstComponentDecl.attributeCValueGeneric(VariableEvaluator evaluator, String name) = CValue.UNKNOWN;
3136    eq InstAssignable.attributeCValueGeneric(VariableEvaluator evaluator, String name) {
3137       
3138        CValue val = attributeCValueSet(evaluator, name);
3139        if (val != null) {
3140            return val;
3141        }
3142       
3143        CValue res = attributeCValueDefault(name);
3144        if (isArray()) {
3145            res = arrayCValue(res);
3146        }
3147        return res;
3148    }
3149   
3150    syn CValue InstAssignable.attributeCValueSet(VariableEvaluator evaluator, String name) {
3151        for (InstModification im : totalMergedEnvironment()) {
3152            FExp exp = im.findAttribute(name);
3153            if (exp != null) {
3154                CValue val = exp.ceval(evaluator);
3155                if (im.hasEach()) {
3156                    val = arrayCValue(val);
3157                }
3158                return val;
3159            }
3160        }
3161        return null;
3162    }
3163   
3164    syn CValueArray InstAssignable.arrayCValue(CValue val) {
3165        CValueArray array = new CValueArray(size());
3166        for (Index i : indices()) {
3167            array.setCell(i, val);
3168        }
3169        return array;
3170    }
3171   
3172
3173    /**
3174     * Get the default value for attribute <code>name</code> for a given type.
3175     */
3176    syn CValue InstComponentDecl.attributeCValueDefault(String name) = CValue.UNKNOWN;
3177    eq InstPrimitive.attributeCValueDefault(String name) {
3178        if (name.equals(FAttribute.FIXED))
3179            return new CValueBoolean(isConstant() || isParameter() || isString());
3180        CValue res = attributeCValueDefaultMap().get(name);
3181        return (res == null) ? CValue.UNKNOWN : res;
3182    }
3183    eq InstEnum.attributeCValueDefault(String name) {
3184        if (name.equals(FAttribute.START) || name.equals(FAttribute.MIN))
3185            return new CValueEnum(type(), 1);
3186        else if (name.equals(FAttribute.MAX))
3187            return new CValueEnum(type(), -1);
3188        else
3189            return super.attributeCValueDefault(name);
3190    }
3191
3192    private static Map<String,CValue> InstPrimitive.REAL_DEFAULT_ATTRIBUTES = null;
3193    private static Map<String,CValue> InstPrimitive.INTEGER_DEFAULT_ATTRIBUTES = null;
3194    private static Map<String,CValue> InstPrimitive.BOOLEAN_DEFAULT_ATTRIBUTES = null;
3195    private static Map<String,CValue> InstPrimitive.STRING_DEFAULT_ATTRIBUTES = null;
3196    private static Map<String,CValue> InstPrimitive.ENUM_DEFAULT_ATTRIBUTES = null;
3197
3198    protected Map<String,CValue> InstPrimitive.attributeCValueDefaultMap() {
3199        if (REAL_DEFAULT_ATTRIBUTES == null) {
3200            CValue emptyStr = new CValueString("");
3201            Map<String,CValue> real = new HashMap<String,CValue>();
3202            real.put(FAttribute.QUANTITY, emptyStr);
3203            real.put(FAttribute.UNIT, emptyStr);
3204            real.put(FAttribute.DISPLAY_UNIT, emptyStr);
3205            real.put(FAttribute.START, new CValueReal(0.0));
3206            // TODO: add stateSelect, but how to get type?
3207            REAL_DEFAULT_ATTRIBUTES = real;
3208            Map<String,CValue> integer = new HashMap<String,CValue>();
3209            integer.put(FAttribute.QUANTITY, emptyStr);
3210            integer.put(FAttribute.START, new CValueInteger(0));
3211            INTEGER_DEFAULT_ATTRIBUTES = integer;
3212            Map<String,CValue> bool = new HashMap<String,CValue>();
3213            bool.put(FAttribute.QUANTITY, emptyStr);
3214            bool.put(FAttribute.START, CValueBoolean.FALSE);
3215            BOOLEAN_DEFAULT_ATTRIBUTES = bool;
3216            Map<String,CValue> string = new HashMap<String,CValue>();
3217            string.put(FAttribute.QUANTITY, emptyStr);
3218            string.put(FAttribute.START, emptyStr);
3219            STRING_DEFAULT_ATTRIBUTES = string;
3220            Map<String,CValue> enumeration = new HashMap<String,CValue>();
3221            enumeration.put(FAttribute.QUANTITY, emptyStr);
3222            ENUM_DEFAULT_ATTRIBUTES = enumeration;
3223        }
3224        if (isReal())
3225            return REAL_DEFAULT_ATTRIBUTES;
3226        else if (isInteger())
3227            return INTEGER_DEFAULT_ATTRIBUTES;
3228        else if (isBoolean())
3229            return BOOLEAN_DEFAULT_ATTRIBUTES;
3230        else if (isString())
3231            return STRING_DEFAULT_ATTRIBUTES;
3232        else if (isEnum())
3233            return ENUM_DEFAULT_ATTRIBUTES;
3234        throw new UnsupportedOperationException("No default CValue map for " + type());
3235    }
3236
3237    /**
3238     * Find the expression for the attribute <code>name</code>.
3239     */
3240    public FExp InstModification.findAttribute(String name) { 
3241        return null;
3242    }
3243
3244    public FExp InstComponentModification.findAttribute(String name) {
3245        if (getName().name().equals(name) && getInstModification().hasInstValueMod())
3246            return getInstModification().getInstValueMod().instValueMod();
3247        return null;
3248    }
3249
3250
3251        /**
3252         * Constant evaluation of FVariable binding expressions.
3253         *
3254         * If an expression is evaluated in an FClass, then identifiers are
3255         * referencing FVariables. The constant value of an FVariable is computed
3256         * by evaluating the binding expression of the variable, if any. If the
3257         * FVariable is not a constant or a parameter, or if it has no binding
3258         * expressions, then a CValueUnknown object is returned.
3259         *
3260         *  @return The constant value.
3261         */
3262    syn CValue FAbstractVariable.ceval() = ceval(defaultVariableEvaluator());
3263   
3264        syn CValue FAbstractVariable.ceval(VariableEvaluator evaluator) = CValue.UNKNOWN;
3265        eq FFunctionVariable.ceval(VariableEvaluator evaluator)         = evaluationValue(evaluator);
3266        eq FVariable.ceval(VariableEvaluator evaluator)                 = ceval(evaluator, isParameter());
3267        syn CValue FVariable.ceval(VariableEvaluator evaluator, boolean inParameterRecord) {
3268                CValue val;
3269                if (isForIndex())
3270                        val = evaluationValue(evaluator);
3271                else if (hasParameterEquation())
3272                        val = parameterEquation().cevalParameter(evaluator, this);
3273                else if (hasBindingExp())
3274                        val = getBindingExp().ceval(evaluator);
3275                else
3276                        val = defaultCValue(evaluator, inParameterRecord);
3277        if (isReal() && !val.isUnknown()) {
3278            val = val.convertReal();
3279        }
3280                return val;
3281        }
3282   
3283    eq FExternalObjectVariable.ceval(VariableEvaluator evaluator, boolean inParameterRecord) {
3284        CValue val = super.ceval(evaluator, inParameterRecord);
3285        val.markExternalObject(name());
3286        return val;
3287    }
3288   
3289       
3290        /**
3291         * Constant evaluation of FVariable binding expressions.
3292         *
3293         * If an expression is evaluated in an FClass, then identifiers are
3294         * referencing FVariables. The constant value of an FVariable is computed
3295         * by evaluating the binding expression of the variable, if any. If the
3296         * FVariable is not a constant or a parameter, or if it has no binding
3297         * expressions, then a CValueUnknown object is returned.
3298         *
3299         * This version only evaluates a specific cell in an array, and returns
3300         * the value for that specific cell.
3301         *
3302         *  @return The constant value.
3303         */
3304        syn CValue FAbstractVariable.ceval(VariableEvaluator evaluator, Index i) = CValue.UNKNOWN;
3305        eq FFunctionVariable.ceval(VariableEvaluator evaluator, Index i)         = evaluationValue(evaluator).getCell(i);
3306        eq FVariable.ceval(VariableEvaluator evaluator, Index i) {
3307        CValue val;
3308        if (isForIndex())
3309            val = evaluationValue(evaluator);
3310        else if (hasParameterEquation())
3311            val = parameterEquation().cevalParameter(evaluator, this, i);
3312        else if (hasBindingExp())
3313            val = getBindingExp().ceval(evaluator, i);
3314        else
3315            val = startAttributeCValue();
3316        val = val.getCell(i);
3317        if (isReal())
3318            val = val.convertReal();
3319        return val;
3320    }
3321   
3322    eq FExternalObjectVariable.ceval(VariableEvaluator evaluator, Index i) {
3323        CValue val = super.ceval(evaluator, i);
3324        val.markExternalObject(name());
3325        return val;
3326    }
3327
3328  /**
3329   * Constant evaluation of binding equation for dependent parameter.
3330   */
3331  syn CValue FAbstractEquation.cevalParameter(VariableEvaluator evaluator, FVariable fv) = CValue.UNKNOWN;
3332  eq FEquation.cevalParameter(VariableEvaluator evaluator, FVariable fv)                 = getRight().ceval(evaluator);
3333  eq FFunctionCallEquation.cevalParameter(VariableEvaluator evaluator, FVariable fv) {
3334          CValue[] vals = getCall().cevalFunction(evaluator);
3335          for (int i = 0; i < getNumLeft(); i++) {
3336                  CValue res = getLeft(i).extractCValue(vals[i], fv);
3337                  if (res != null)
3338                          return res;
3339          }
3340          return CValue.UNKNOWN;
3341  }
3342 
3343  /**
3344   * Constant evaluation of binding equation for dependent parameter.
3345   */
3346  syn CValue FAbstractEquation.cevalParameter(VariableEvaluator evaluator, FVariable fv, Index i) = CValue.UNKNOWN;
3347  eq FEquation.cevalParameter(VariableEvaluator evaluator, FVariable fv, Index i)                 = getRight().ceval(evaluator, i);
3348 
3349  /**
3350   * Given that <code>val</code> is the value of this use expression,
3351   *        extract the part of it referring to <code>fv</code>,
3352   *        or <code>null</code> if none match.
3353   */
3354  syn CValue FFunctionCallLeft.extractCValue(CValue val, FVariable fv) =
3355          hasFExp() ? getFExp().extractCValue(val, fv) : null;
3356 
3357  /**
3358   * Given that <code>val</code> is the value of this use expression,
3359   *        extract the part of it referring to <code>fv</code>,
3360   *        or <code>null</code> if none match.
3361   */
3362  syn CValue FExp.extractCValue(CValue val, FVariable fv) = null;
3363  eq FAccessExp.extractCValue(CValue val, FVariable fv)    = getFAccess().myFV() == fv ? val : null;
3364  eq FArray.extractCValue(CValue val, FVariable fv) {
3365          CValueArray arr = val.array();
3366          for (Index i : indices()) {
3367                  CValue res = getArray().get(i).extractCValue(arr.getCell(i), fv);
3368                  if (res != null)
3369                          return res;
3370          }
3371          return null;
3372  }
3373  eq FRecordConstructor.extractCValue(CValue val, FVariable fv) {
3374          CValueRecord rec = val.record();
3375          int n = getNumArg();
3376          for (int i = 0; i < n; i++) {
3377                  CValue res = getArg(i).extractCValue(rec.getMember(i), fv);
3378                  if (res != null)
3379                          return res;
3380          }
3381          return null;
3382  }
3383 
3384  /**
3385   * Constant eval for variables without any binding expression, or binding equation.
3386   * Uses the start value for non-records.
3387   */
3388  syn CValue FVariable.defaultCValue(VariableEvaluator evaluator, boolean inParameterRecord) = startAttributeCValue();
3389  eq FRecordVariable.defaultCValue(VariableEvaluator evaluator, boolean inParameterRecord) {
3390          if (isArray()) {
3391                  CValueArray res = new CValueArray(size());
3392                  for (Index i : indices())
3393                          res.setCell(i, defaultCValueCell(evaluator, i, inParameterRecord));
3394                  return res;
3395          } else {
3396                  return defaultCValueCell(evaluator, Index.NULL, inParameterRecord);
3397          }
3398  }
3399 
3400  /**
3401   * Constant eval for variables without any binding expression, or binding equation.
3402   * Uses the start value for non-records.
3403   */
3404  syn CValue FVariable.defaultCValueCell(VariableEvaluator evaluator, Index i, boolean inParameterRecord) = startAttributeCValue();
3405   
3406    private boolean FRecordVariable.circular = false;
3407    eq FRecordVariable.defaultCValueCell(VariableEvaluator evaluator, Index i, boolean inParameterRecord) {
3408        if (circular) {
3409            throw new ConstantEvaluationException(null, "Circular evaluation in record component");
3410        }
3411        circular = true;
3412        try {
3413            CValueRecord res = new CValueRecord((FRecordType) type().scalarType());
3414            FRecordDecl rec = myFRecordDecl();
3415            for (int j = 0, n = rec.getNumFVariable(); j < n; j++) {
3416                FVariable fv = rec.getFVariable(j);
3417                if (inParameterRecord || fv.isParameter() || fv.isRecord())
3418                    res.setMember(j, fv.ceval(evaluator, inParameterRecord));
3419                else
3420                    res.setMember(j, CValue.UNKNOWN);
3421            }
3422            for (FAttribute a : getFAttributes())
3423                a.applyToCValue(evaluator, res, i);
3424            return res;
3425        } finally {
3426            circular = false;
3427        }
3428    }
3429 
3430  /**
3431   * Apply any binding expressions for record members to a record CValue.
3432   */
3433  public void FAttribute.applyToCValue(VariableEvaluator evaluator, CValueRecord rec, Index i) {
3434          if (rec.members().containsKey(name())) {
3435                  int j = rec.members().get(name());
3436                  if (hasValue()) {
3437                          CValue val = getValue().ceval(evaluator);
3438                          if (i != Index.NULL && rec.getMember(j).size().ndims() + i.ndims() == val.size().ndims())
3439                                  val = val.array().getPart(i);
3440                          if (!rec.getMember(j).isUnknown())
3441                                  rec.setMember(j, val);
3442                  } else {
3443                          if (!rec.getMember(j).isUnknown())
3444                                  rec.getMember(j).applyAttributes(getFAttributes(), i);
3445                  }
3446          }
3447  }
3448 
3449  /**
3450   * Apply attributes in attrs to any records in this value.
3451   */
3452  public void CValue.applyAttributes(List<FAttribute> attrs, Index i) {}
3453 
3454  public void CValueArray.applyAttributes(List<FAttribute> attrs, Index i) {
3455          if (values.length > 0 && values[0].isRecord()) 
3456                  for (Index j : indices) 
3457                          getCell(j).applyAttributes(attrs, i.expand(j));
3458  }
3459 
3460  public void CValueRecord.applyAttributes(List<FAttribute> attrs, Index i) {
3461          for (FAttribute a : attrs)
3462                  a.applyToCValue(ASTNode.defaultVariableEvaluator(), this, i);
3463  }
3464 
3465 
3466  /**
3467   * Constant evaluate all dimensions described by expressions.
3468   */
3469  public Size Size.ceval() {
3470      return ceval(ASTNode.defaultVariableEvaluator());
3471  }
3472 
3473  public Size Size.ceval(VariableEvaluator evaluator) {
3474          return this;
3475  }
3476 
3477  public Size MutableSize.ceval(VariableEvaluator evaluator) {
3478          int[] ns = size.clone();
3479          for (int i = 0; i < size.length; i++) 
3480                  if (size[i] == UNKNOWN && exps[i] != null) 
3481                          ns[i] = exps[i].ceval(evaluator).intValue();
3482          return new Size(ns);
3483  }
3484 
3485 
3486  /**
3487   * Check if this node is in a function that is being evaluated.
3488   */
3489  inh boolean FExp.duringFunctionEval();
3490  inh boolean InstNamedAccess.duringFunctionEval();
3491  eq FFunctionDecl.getChild().duringFunctionEval()     = currentEvaluationValues != null;
3492  eq InstBaseClassDecl.getChild().duringFunctionEval() = currentEvaluationValues != null;
3493  eq FClass.getChild().duringFunctionEval()            = false;
3494  eq Root.getChild().duringFunctionEval()              = false;
3495 
3496  /**
3497   * Perform constant evaluation of functions, with caching.
3498   *
3499   * Delegates to {@link #evaluate()};
3500   *
3501   * @return  constant values for the outputs
3502   */
3503  syn CValue[] FAbstractFunctionCall.cevalFunction(VariableEvaluator evaluator) = new CValue[] { ceval(evaluator) };
3504  syn lazy CValue[] FFunctionCall.cevalFunction(VariableEvaluator evaluator)    = evaluate(evaluator);
3505  syn lazy CValue[] InstFunctionCall.cevalFunction(VariableEvaluator evaluator) = evaluate(evaluator);
3506
3507    /**
3508     * Interface for variable declarations in flat and instance trees.
3509     */
3510    public interface CommonVariableDecl {
3511        public void readEvaluationValue(Map<CommonVariableDecl, CValue> map);
3512        public void setEvaluationValue(VariableEvaluator evaluator, CValue val);
3513        public void clearEvaluationValue(VariableEvaluator evaluator);
3514        public void setLocalCachedEvaluationValue(CValue val);
3515        public CValue getLocalCachedEvaluationValue();
3516        public void clearLocalCachedEvaluationValue();
3517        public void resetAfterCeval();
3518        public CValue evaluationValue(VariableEvaluator evaluator);
3519        public CValue ceval();
3520        public CValue ceval(VariableEvaluator evaluator);
3521        public CValue ceval(VariableEvaluator evaluator, Index i);
3522        public String name();
3523        public String qualifiedName();
3524        public Size size();
3525        public boolean isConstant();
3526        public boolean isPackageConstant();
3527        public boolean inSameInstClass(InstNode instNode);
3528        public TypePrefixVariability variability();
3529
3530        // Added for codegeneration when evaluating external functions
3531        public FType   type();
3532        public String  name_C();
3533        public boolean isInput();
3534        public boolean isOutput();
3535       
3536        // Added for type checking
3537        public boolean shouldBeDifferentiated();
3538        public boolean isUnknown();
3539     
3540        public FAbstractVariable asFAbstractVariable();
3541    }
3542   
3543    public boolean FAbstractVariable.isInstClassConstant() { return false;}
3544
3545    public boolean FAbstractVariable.isPackageConstant() { return false;}
3546    public boolean InstComponentDecl.isPackageConstant() { return isConstant() && containingInstClass().isPackage();}
3547   
3548    public boolean FAbstractVariable.inSameInstClass(InstNode instNode) { return false;}
3549    public boolean InstComponentDecl.inSameInstClass(InstNode instNode) {
3550        InstNode classDecl = instNode;
3551        if (!classDecl.isClassDecl()) {
3552                classDecl = classDecl.containingInstClass();
3553        }
3554        InstNode node = containingEntity();
3555        if (node.equals(classDecl)) {
3556                return true;
3557        }
3558        return false;
3559    }
3560   
3561   
3562   
3563    FAbstractVariable implements CommonVariableDecl;
3564    InstComponentDecl implements CommonVariableDecl;
3565   
3566    syn FAbstractVariable FAbstractVariable.asFAbstractVariable() = this;
3567    syn FAbstractVariable InstComponentDecl.asFAbstractVariable() = null;
3568 
3569  syn FExp FAbstractFunctionCall.argument(int i) {
3570          for (FExp e : childFExps())
3571                  if (i-- == 0)
3572                          return e;
3573          return null;
3574  }
3575  eq FFunctionCall.argument(int i)    = getArg(i);
3576  eq InstFunctionCall.argument(int i) = getArg(i).getFExp();
3577
3578  /**
3579   * Perform constant evaluation of functions.
3580   *
3581   * @return  constant values for the outputs
3582   */
3583  public CValue[] FAbstractFunctionCall.evaluate(VariableEvaluator evaluator) {
3584          Map<CommonVariableDecl, CValue> values = new HashMap<CommonVariableDecl, CValue>();
3585          int i = 0;
3586          for (CommonVariableDecl var : myCallInputs()) {
3587                  FExp arg = argument(i++);
3588            if (arg != null) {
3589                values.put(var, arg.ceval(evaluator));
3590            } else {
3591                throw new ConstantEvaluationException();
3592            }
3593          }
3594         
3595          evaluate(evaluator, values);
3596         
3597          CValue[] res = new CValue[myCallOutputs().size()];
3598          i = 0;
3599          for (CommonVariableDecl var : myCallOutputs()) {
3600                  CValue val = values.get(var);
3601                  res[i] = (val == null) ? CValue.UNKNOWN : val;
3602                  i++;
3603          }
3604          return res;
3605  }
3606   
3607   
3608    public void FAbstractFunctionCall.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3609        evaluateCell(evaluator, values);
3610    }
3611   
3612    @Override
3613    public void FVectorFunctionCall.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3614        evaluateVector(evaluator, values);
3615    }
3616   
3617    @Override
3618    public void InstVectorFunctionCall.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3619        evaluateVector(evaluator, values);
3620    }
3621   
3622   
3623    public void FAbstractFunctionCall.evaluateCell(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3624        values.clear();
3625    }
3626   
3627    @Override
3628    public void FAssert.evaluateCell(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3629        boolean val = getTest().ceval().booleanValue();
3630        if (!val && (!hasLevel() || getLevel().ceval().stringValue().equals(LEVEL_ERROR))) {
3631            String msg = "Assertion failed: " + getMsg().ceval().stringValue();
3632            throw new ConstantEvaluationException(null , msg);
3633        }
3634    }
3635   
3636   
3637    @Override
3638    public void FFunctionCall.evaluateCell(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3639        myCommonCallable().evaluate(evaluator, values);
3640    }
3641   
3642    @Override
3643    public void InstFunctionCall.evaluateCell(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3644        myCommonCallable().evaluate(evaluator, values);
3645    }
3646   
3647    @Override
3648    public void FPartialFunctionCall.evaluateCell(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3649        evaluatePartial(values);
3650    }
3651   
3652    @Override
3653    public void InstPartialFunctionCall.evaluateCell(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3654        evaluatePartial(values);
3655    }
3656   
3657   
3658    public void FAbstractFunctionCall.evaluateVector(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3659        Size vectorizedSize = sizeOfOutput(0);
3660        CommonVariableDecl output = myCallOutputs().get(0);
3661        Map<CommonVariableDecl, CValue> input  = new HashMap<CommonVariableDecl, CValue>(values.size());
3662        input.putAll(values);
3663        values.put(output, new CValueArray(vectorizedSize));
3664       
3665        Map<CommonVariableDecl, Boolean> isVectorized = new HashMap<CommonVariableDecl, Boolean>(input.size());
3666        for (CommonVariableDecl cvd : input.keySet()) {
3667            isVectorized.put(cvd, cvd.size().expand(vectorizedSize).equivalent(input.get(cvd).size(), true));
3668        }
3669       
3670        for (Index i : Indices.create(vectorizedSize)) {
3671            Map<CommonVariableDecl, CValue> valuesCell = new HashMap<CommonVariableDecl, CValue>();
3672            for (CommonVariableDecl cvd : input.keySet()) {
3673                if (isVectorized.get(cvd)) {
3674                    valuesCell.put(cvd, input.get(cvd).array().getPart(i));
3675                } else {
3676                    valuesCell.put(cvd, input.get(cvd));
3677                }
3678            }
3679            evaluateCell(evaluator, valuesCell);
3680            CValue val = valuesCell.get(output);
3681            if (val == null) {
3682                val = CValue.UNKNOWN;
3683            }
3684            values.get(output).array().setCell(i, val);
3685        }
3686    }
3687   
3688    public void FAbstractFunctionCall.evaluatePartial(Map<CommonVariableDecl, CValue> values) {
3689        values.put(myCallOutputs().get(0), myCommonCallable().evaluatePartial(values));
3690    }
3691   
3692    public interface CommonCallable {
3693        public void evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values);
3694        public CValue evaluatePartial(Map<CommonVariableDecl, CValue> values);
3695    }
3696   
3697    syn CValue InstClassDecl.evaluatePartial(Map<CommonVariableDecl, CValue> values) = 
3698        CValuePartialFunction.create(this, values);
3699    syn CValue FFunctionDecl.evaluatePartial(Map<CommonVariableDecl, CValue> values) = 
3700        CValuePartialFunction.create(this, values);
3701    syn CValue InstPartialFunction.evaluatePartial(Map<CommonVariableDecl, CValue> values) =
3702        evaluationValue.evaluatePartialFunction(this, values);
3703    syn CValue FFunctionVariable.evaluatePartial(Map<CommonVariableDecl, CValue> values) =
3704        evaluationValue.evaluatePartialFunction(this, values);
3705   
3706    public static Map<CommonVariableDecl, CValue> FFunctionDecl.resetAfterCeval(CommonCallable cc, ASTNode n, Map<CommonVariableDecl, CValue> values) {
3707        Map<CommonVariableDecl, CValue> oldVal = cc.getCurrentEvaluationValues();
3708        cc.setCurrentEvaluationValues(values);
3709        for (CommonVariableDecl cvd : cc.myInputs()) {
3710            cvd.resetAfterCeval();
3711        }
3712        for (CommonVariableDecl cvd : cc.myNonInputs()) {
3713            cvd.resetAfterCeval();
3714        }
3715        n.resetAfterCeval();
3716        if (values != null) {
3717            for (CommonVariableDecl cvd : values.keySet()) {
3718                cvd.setLocalCachedEvaluationValue(values.get(cvd));
3719            }
3720        }
3721        return oldVal;
3722    }
3723   
3724    public void ASTNode.resetAfterCeval() {
3725        for (ASTNode n : this) {
3726            n.resetAfterCeval();
3727        }
3728    }
3729   
3730    public void FFunctionVariable.resetAfterCeval() {
3731        super.resetAfterCeval();
3732        clearLocalCachedEvaluationValue();
3733        size().resetAfterCeval();
3734    }
3735   
3736    public void InstAssignable.resetAfterCeval() {
3737        super.resetAfterCeval();
3738        clearLocalCachedEvaluationValue();
3739        if (hasBindingFExp()) {
3740            myBindingInstExp().resetAfterCeval();
3741        }
3742        size().resetAfterCeval();
3743    }
3744   
3745    public void Size.resetAfterCeval() {
3746       
3747    }
3748   
3749    public void MutableSize.resetAfterCeval() {
3750        for (int i = 0; i < exps.length; i++) {
3751            if (exps[i] != null) {
3752                exps[i].resetAfterCeval();
3753                evaluated[i] = false;
3754                size[i] = Size.UNKNOWN;
3755            }
3756        }
3757    }
3758   
3759   
3760    public void FExp.resetAfterCeval() {
3761        flushAllRecursive();
3762    }
3763
3764    @Override
3765    public void FInitArrayStmt.resetAfterCeval() {
3766        flushAllRecursive();
3767    }
3768
3769    // TODO: reduce code duplication
3770
3771    /**
3772     * Perform constant evaluation of functions.
3773     *
3774     * @param values  constant values for the variables.
3775     *                Should be filled with the values of the inputs.
3776     */
3777    public void FFunctionDecl.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3778        FFunctionDecl.evaluate(evaluator, values, this, getFAlgorithm());
3779    }
3780   
3781    public static void FFunctionDecl.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values, CommonCallable cc, FAlgorithm fab) {
3782        AlgorithmEvaluator algoEvaluator = evaluator.createAlgorithmEvaluator(fab.myOptions(), values);
3783        Map<CommonVariableDecl, CValue> oldVal = FFunctionDecl.resetAfterCeval(cc, fab, values);
3784        try {
3785            for (CommonVariableDecl cvd : cc.myInputs()) {
3786                // Only here because operator record functions does not evaluate default values of inputs
3787                cvd.readEvaluationValue(values);
3788            }
3789            for (CommonVariableDecl cvd : cc.myNonInputs()) {
3790                // Only here because scalar primitives does not have init statements.
3791                cvd.readEvaluationValue(values);
3792            }
3793            if (oldVal == null || algoEvaluator.recursive(cc)) {
3794                fab.getFStatements().evaluateList(algoEvaluator);
3795            }
3796        } catch (ConstantEvaluationException e) {
3797            algoEvaluator.failed(cc, e);
3798        } finally {
3799            FFunctionDecl.resetAfterCeval(cc, fab, oldVal);
3800        }
3801    }
3802   
3803    public void FFunctionVariable.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3804        evaluationValue.evaluateFunction(evaluator, myFCallable(), values);
3805    }
3806   
3807    interface CommonCallable {
3808        public Map<CommonVariableDecl, CValue> getCurrentEvaluationValues();
3809        public void setCurrentEvaluationValues(Map<CommonVariableDecl, CValue> values);
3810    }
3811   
3812    private Map<CommonVariableDecl, CValue> FFunctionDecl.currentEvaluationValues = null;
3813    public Map<CommonVariableDecl, CValue> FFunctionDecl.getCurrentEvaluationValues() { return currentEvaluationValues; }
3814    public void FFunctionDecl.setCurrentEvaluationValues(Map<CommonVariableDecl, CValue> values) { currentEvaluationValues = values; }
3815   
3816    private Map<CommonVariableDecl, CValue> InstBaseClassDecl.currentEvaluationValues = null;
3817    public Map<CommonVariableDecl, CValue> InstBaseClassDecl.getCurrentEvaluationValues() { return currentEvaluationValues; }
3818    public void InstBaseClassDecl.setCurrentEvaluationValues(Map<CommonVariableDecl, CValue> values) { currentEvaluationValues = values; }
3819   
3820    public Map<CommonVariableDecl, CValue> InstNode.getCurrentEvaluationValues() { return null; }
3821    public void InstNode.setCurrentEvaluationValues(Map<CommonVariableDecl, CValue> values) {}
3822   
3823    public Map<CommonVariableDecl, CValue> FFunctionVariable.getCurrentEvaluationValues() { return null; }
3824    public void FFunctionVariable.setCurrentEvaluationValues(Map<CommonVariableDecl, CValue> values) {}
3825   
3826    /**
3827     * Constant-evaluate function with given set of arguments and return value for first output.
3828     *
3829     * @param args  arguments of the function call
3830     */
3831    public CValue InstClassDecl.evaluateFirst(VariableEvaluator evaluator, Iterable<FExp> args) {
3832        Map<CommonVariableDecl, CValue> values = new HashMap<CommonVariableDecl, CValue>();
3833        int i = 0;
3834        for (FExp arg : args) {
3835            if (i < myInputs().size()) {
3836                CommonVariableDecl cvd = myInputs().get(i);
3837                if (cvd.type().typeCompatible(arg.type(), true)) {
3838                    values.put(cvd, arg.ceval(evaluator));
3839                } else {
3840                    InstClassDecl constructor = cvd.type().matchOverloadedConstructor(arg.type());
3841                    ArrayList<FExp> l = new ArrayList<FExp>();
3842                    l.add(arg);
3843                    CValue v = constructor.evaluateFirst(evaluator, l);
3844                    values.put(cvd, v);
3845                }
3846            } else {
3847                throw new ConstantEvaluationException();
3848            }
3849            i++;
3850        }
3851       
3852        evaluate(evaluator, values);
3853       
3854        CValue res = myOutputs().isEmpty() ? null : values.get(myOutputs().get(0));
3855        return (res == null) ? CValue.UNKNOWN : res;
3856    }
3857
3858    /**
3859     * Perform constant evaluation of functions.
3860     *
3861     * @param values  constant values for the variables.
3862     *                Should be filled with the values of the inputs.
3863     */
3864    public void InstClassDecl.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3865        values.clear(); // Make sure evaluation returns CValue.UNKNOWN
3866    }
3867
3868    public void InstSimpleShortClassDecl.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3869       actualInstClass().evaluate(evaluator, values);
3870    }
3871
3872    public void InstLibNode.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3873       actualInstClass().evaluate(evaluator, values);
3874    }
3875
3876    public void InstBaseClassDecl.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3877        // We assume that this class is a function
3878       
3879        FAlgorithm fab = findFunctionAlgorithm();
3880        if (fab == null) {
3881            InstExternal ie = findFunctionExternal();
3882            if (ie == null) {
3883                values.clear();
3884                return;
3885            }
3886            fab = ie.getFAlgorithm();
3887        }
3888       
3889        FFunctionDecl.evaluate(evaluator, values, this, fab);
3890    }
3891   
3892    public void InstPartialFunction.evaluate(VariableEvaluator evaluator, Map<CommonVariableDecl, CValue> values) {
3893        evaluationValue.evaluateFunction(evaluator, myInstClass(), values);
3894    }
3895   
3896   
3897   
3898    /**
3899     * Read current function evaluation value from map.
3900     *
3901     * If this variable isn't in the map, set to value of binding expression.
3902     */
3903    public void FAbstractVariable.readEvaluationValue(Map<CommonVariableDecl, CValue> map) {
3904        CValue val = map.get(this);
3905        if (val == null) {
3906            val = cevalFunctionBindingExp(ASTNode.defaultVariableEvaluator());
3907        }
3908        if (!isInput()) {
3909            val = val.cached();
3910        }
3911        map.put(this, val);
3912        setLocalCachedEvaluationValue(val);
3913    }
3914
3915    /**
3916     * Read current function evaluation value from map.
3917     *
3918     * If this variable isn't in the map, set to value of binding expression.
3919     */
3920    public void InstComponentDecl.readEvaluationValue(Map<CommonVariableDecl, CValue> map) {
3921        CValue val = map.get(this);
3922        if (val == null) {
3923            val = cevalFunctionBindingExp(ASTNode.defaultVariableEvaluator());
3924        }
3925        if (!isInput()) {
3926            val = val.cached();
3927        }
3928        map.put(this, val);
3929        setLocalCachedEvaluationValue(val);
3930    }
3931   
3932   
3933    protected CValue FAbstractVariable.cevalFunctionBindingExp(VariableEvaluator evaluator) {
3934        return CValue.UNKNOWN;
3935    }
3936
3937    protected CValue FFunctionVariable.cevalFunctionBindingExp(VariableEvaluator evaluator) {
3938        if (hasBindingExp()) {
3939            return getBindingExp().ceval(evaluator);
3940        } else if (isArray()) {
3941            return CValue.UNKNOWN;
3942        } else {
3943            return type().zeroCValue();
3944        }
3945    }
3946
3947    protected CValue InstComponentDecl.cevalFunctionBindingExp(VariableEvaluator evaluator) {
3948        return CValue.UNKNOWN;
3949    }
3950
3951    protected CValue InstAssignable.cevalFunctionBindingExp(VariableEvaluator evaluator) {
3952        return hasBindingFExp() ? myBindingInstExp().ceval(evaluator) : type().zeroCValue();
3953    }
3954
3955    protected CValue InstRecord.cevalFunctionBindingExp(VariableEvaluator evaluator) {
3956        if (hasBindingFExp())
3957            return myBindingInstExp().ceval(evaluator);
3958        FRecordType type = (FRecordType) type().scalarType();
3959        if (isArray()) {
3960            CValueArray res = new CValueArray(size());
3961            int ndims = ndims();
3962            for (InstComponentDecl ch : allInstComponentDecls())
3963                ch.cevalBindingExpForRecordArray(evaluator, type, res, ndims);
3964            return res;
3965        } else {
3966            return cevalBindingExpForRecord(evaluator, type);
3967        }
3968    }
3969
3970    protected void InstComponentDecl.cevalBindingExpForRecordArray(VariableEvaluator evaluator, FRecordType type, CValueArray arr, int ndims) {
3971        throw new UnsupportedOperationException("Only valid for InstArrayComponentDecls.");
3972    }
3973
3974    protected void InstArrayComponentDecl.cevalBindingExpForRecordArray(VariableEvaluator evaluator, FRecordType type, CValueArray arr, int ndims) {
3975        ndims--;
3976        if (ndims > 0) {
3977            for (InstComponentDecl ch : allInstComponentDecls())
3978                ch.cevalBindingExpForRecordArray(evaluator, type, arr, ndims);
3979        } else {
3980            arr.addCell(cevalBindingExpForRecord(evaluator, type));
3981        }
3982    }
3983
3984    protected CValue InstComponentDecl.cevalBindingExpForRecord(VariableEvaluator evaluator, FRecordType type) {
3985        CValueRecord res = new CValueRecord(type);
3986        evaluationValue = res;
3987        for (InstComponentDecl ch : allInstComponentDecls())
3988            res.setMember(ch.name(), ch.cevalFunctionBindingExp(evaluator));
3989        return res;
3990    }
3991
3992    /**
3993     * Set the current evaluation value.
3994     */
3995    public void CommonForIndex.setEvaluationValue(CValue val) {
3996        setEvaluationValue(ASTNode.defaultVariableEvaluator(), val);
3997    }
3998   
3999    /**
4000     * Get the current evaluation value.
4001     */
4002    public CValue CommonForIndex.evaluationValue() {
4003        return evaluationValue(ASTNode.defaultVariableEvaluator());
4004    }
4005   
4006    syn CommonVariableDecl CommonForIndex.myCVD();
4007    eq FForIndex.myCVD() = getFVariable();
4008    eq InstForIndex.myCVD() = getInstPrimitive();
4009   
4010    public void CommonForIndex.setEvaluationValue(VariableEvaluator evaluator, CValue val) {
4011        if (val == null) {
4012            clearEvaluationValue(ASTNode.defaultVariableEvaluator());
4013        } else {
4014            myCVD().setEvaluationValue(evaluator, val);
4015        }
4016    }
4017   
4018    public CValue CommonForIndex.evaluationValue(VariableEvaluator evaluator) {
4019        return myCVD().evaluationValue(evaluator);
4020    }
4021   
4022    public void CommonForIndex.clearEvaluationValue() {
4023        clearEvaluationValue(defaultVariableEvaluator());
4024    }
4025   
4026    public void CommonForIndex.clearEvaluationValue(VariableEvaluator evaluator) {
4027        myCVD().clearEvaluationValue(evaluator);
4028    }
4029   
4030  /**
4031   * Set the current function evaluation value.
4032   *
4033   * Also updates value map.
4034   */
4035    public void FAbstractVariable.setEvaluationValue(VariableEvaluator evaluator, CValue val) {
4036        evaluator.setEvaluationValue(this, val.cached());
4037    }
4038 
4039  /**
4040   * Set the current function evaluation value.
4041   *
4042   * Also updates value map.
4043   */
4044    public void InstComponentDecl.setEvaluationValue(VariableEvaluator evaluator, CValue val) {
4045        evaluator.setEvaluationValue(this, val.cached());
4046    }
4047 
4048  /**
4049   * Check if this variable has a current function evaluation value.
4050   */
4051  public boolean FAbstractVariable.hasEvaluationValue(VariableEvaluator evaluator) {
4052          return evaluator.hasEvaluationValue(this);
4053  }
4054 
4055  /**
4056   * Check if this variable has a current function evaluation value.
4057   */
4058  public boolean InstComponentDecl.hasEvaluationValue(VariableEvaluator evaluator) {
4059          return evaluator.hasEvaluationValue(this);
4060  }
4061 
4062  /**
4063   * Get the current evaluation value.
4064   */
4065  public CValue FAbstractVariable.evaluationValue(VariableEvaluator evaluator) {
4066          return evaluator.evaluationValue(this);
4067  }
4068 
4069  /**
4070   * Get the current evaluation value.
4071   */
4072  public CValue InstComponentDecl.evaluationValue(VariableEvaluator evaluator) {
4073          return evaluator.evaluationValue(this);
4074  }
4075 
4076    /**
4077     * Remove the current evaluation value
4078     */
4079    public void FAbstractVariable.clearEvaluationValue(VariableEvaluator evaluator) {
4080        evaluator.clearEvaluationValue(this);
4081    }
4082   
4083    /**
4084     * Remove the current evaluation value
4085     */
4086    public void InstComponentDecl.clearEvaluationValue(VariableEvaluator evaluator) {
4087        evaluator.clearEvaluationValue(this);
4088    }
4089   
4090  protected CValue FAbstractVariable.evaluationValue = null;
4091  protected CValue InstComponentDecl.evaluationValue = null;
4092 
4093    public CValue FAbstractVariable.getLocalCachedEvaluationValue() {
4094        return evaluationValue;
4095    }
4096   
4097    public CValue InstComponentDecl.getLocalCachedEvaluationValue() {
4098        return evaluationValue;
4099    }
4100 
4101    public void FAbstractVariable.setLocalCachedEvaluationValue(CValue value) {
4102        evaluationValue = value;
4103    }
4104   
4105    public void InstComponentDecl.setLocalCachedEvaluationValue(CValue value) {
4106        evaluationValue = value;
4107    }
4108   
4109    public void FAbstractVariable.clearLocalCachedEvaluationValue() {
4110        evaluationValue = null;
4111    }
4112   
4113    public void InstComponentDecl.clearLocalCachedEvaluationValue() {
4114        evaluationValue = null;
4115    }
4116   
4117    /**
4118     * Kept for legacy reasons.
4119     * @deprecated Use {@link #setLocalCachedEvaluationValue} instead.
4120     */
4121    public void FAbstractVariable.setEvaluationValue(CValue value) {
4122        setLocalCachedEvaluationValue(value);
4123    }
4124   
4125    /**
4126     * Kept for legacy reasons.
4127     * @deprecated Use {@link #setLocalCachedEvaluationValue} instead.
4128     */
4129    public void InstComponentDecl.setEvaluationValue(CValue value) {
4130        setLocalCachedEvaluationValue(value);
4131    }
4132 
4133
4134    public class EvaluationValueCache {
4135
4136        private Map<CommonVariableDecl,CValue> values;
4137        private Map<CommonVariableDecl,CValue> old;
4138
4139        public EvaluationValueCache(ASTNode source) {
4140            values = source.collectEvaluationValues(null);
4141        }
4142       
4143        public void apply() {
4144            if (values != null) {
4145                old = new HashMap<CommonVariableDecl,CValue>();
4146                for (CommonVariableDecl var : values.keySet()) {
4147                    CValue prev = var.evaluationValue(ASTNode.defaultVariableEvaluator());
4148                    if (!prev.isUnknown())
4149                        old.put(var, prev);
4150                    if (values.get(var) != null)
4151                        var.setEvaluationValue(ASTNode.defaultVariableEvaluator(), values.get(var));
4152                }
4153            }
4154        }
4155       
4156        public void reset() {
4157            if (values != null)
4158                for (CommonVariableDecl var : values.keySet())
4159                    if (old.get(var) != null)
4160                        var.setEvaluationValue(ASTNode.defaultVariableEvaluator(), old.get(var));
4161            old = null;
4162        }
4163
4164    }
4165
4166    public Map<CommonVariableDecl,CValue> ASTNode.collectEvaluationValues(Map<CommonVariableDecl,CValue> map) {
4167        for (ASTNode n : this)
4168            map = n.collectEvaluationValues(map);
4169        return map;
4170    }
4171
4172    public Map<CommonVariableDecl,CValue> InstComponentAccess.collectEvaluationValues(Map<CommonVariableDecl,CValue> map) {
4173        return super.collectEvaluationValues(myInstComponentDecl().collectMyEvaluationValue(map));
4174    }
4175
4176    public Map<CommonVariableDecl,CValue> InstComponentDecl.collectEvaluationValues(Map<CommonVariableDecl,CValue> map) {
4177        return super.collectEvaluationValues(collectMyEvaluationValue(map));
4178    }
4179
4180    public Map<CommonVariableDecl,CValue> CommonAccess.collectEvaluationValues(Map<CommonVariableDecl,CValue> map) {
4181        return super.collectEvaluationValues(collectMyEvaluationValue(map));
4182    }
4183
4184    public Map<CommonVariableDecl,CValue> FAbstractVariable.collectEvaluationValues(Map<CommonVariableDecl,CValue> map) {
4185        return super.collectEvaluationValues(collectMyEvaluationValue(map));
4186    }
4187   
4188    public Map<CommonVariableDecl,CValue> FAttribute.collectEvaluationValues(Map<CommonVariableDecl,CValue> map) {
4189        return map;
4190    }
4191   
4192    public abstract Map<CommonVariableDecl,CValue> CommonAccess.collectMyEvaluationValue(Map<CommonVariableDecl,CValue> map);
4193   
4194    public Map<CommonVariableDecl,CValue> FAccess.collectMyEvaluationValue(Map<CommonVariableDecl,CValue> map) {
4195        return myFV().collectMyEvaluationValue(map);
4196    }
4197   
4198    public Map<CommonVariableDecl,CValue> InstAccess.collectMyEvaluationValue(Map<CommonVariableDecl,CValue> map) {
4199        return map;
4200    }
4201
4202    public Map<CommonVariableDecl,CValue> InstComponentDecl.collectMyEvaluationValue(Map<CommonVariableDecl,CValue> map) {
4203        if (evaluationValue != null) {
4204            if (map == null)
4205                map = new HashMap<CommonVariableDecl,CValue>();
4206            map.put(this, evaluationValue);
4207        }
4208        return map;
4209    }
4210
4211    public Map<CommonVariableDecl,CValue> FAbstractVariable.collectMyEvaluationValue(Map<CommonVariableDecl,CValue> map) {
4212        if (evaluationValue != null) {
4213            if (map == null)
4214                map = new HashMap<CommonVariableDecl,CValue>();
4215            map.put(this, evaluationValue);
4216        }
4217        return map;
4218    }
4219
4220    /**
4221     * Addition of constant values.
4222     *
4223     * @param v1 Constant value of left operand.
4224     * @param v2 Constant value of right operand.
4225     * @return Resulting constant value.
4226     */
4227    syn CValue FType.add(CValue v1, CValue v2) = CValue.UNKNOWN;
4228
4229    eq FRealType.add(CValue v1, CValue v2) {
4230        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4231            return CValue.UNKNOWN;
4232        }
4233        return new CValueReal(v1.realValue() + v2.realValue());
4234    }
4235
4236    eq FIntegerType.add(CValue v1, CValue v2) {
4237        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4238            return CValue.UNKNOWN;
4239        }
4240        return new CValueInteger(v1.intValue() + v2.intValue());
4241    }
4242
4243    eq FStringType.add(CValue v1, CValue v2) {
4244        if (!v1.isString() || !v2.isString()) {
4245            return CValue.UNKNOWN;
4246        }
4247        return new CValueString(v1.stringValue() + v2.stringValue());
4248    }
4249
4250    /**
4251     * Subtraction of constant values.
4252     *
4253     * @param v1 Constant value of left operand.
4254     * @param v2 Constant value of right operand.
4255     * @return Resulting constant value.
4256     */
4257    syn CValue FType.sub(CValue v1, CValue v2) = CValue.UNKNOWN;
4258
4259    eq FRealType.sub(CValue v1, CValue v2) {
4260        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4261            return CValue.UNKNOWN;
4262        }
4263        return new CValueReal(v1.realValue() - v2.realValue());
4264    }
4265
4266    eq FIntegerType.sub(CValue v1, CValue v2) {
4267        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4268            return CValue.UNKNOWN;
4269        }
4270        return new CValueInteger(v1.intValue() - v2.intValue());
4271    }
4272
4273    /**
4274     * Multiplication of constant values.
4275     *
4276     * @param v1 Constant value of left operand.
4277     * @param v2 Constant value of right operand.
4278     * @return Resulting constant value.
4279     */
4280    syn CValue FType.mul(CValue v1, CValue v2) = CValue.UNKNOWN;
4281
4282    eq FRealType.mul(CValue v1, CValue v2) {
4283        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4284            return CValue.UNKNOWN;
4285        }
4286        return new CValueReal(v1.realValue() * v2.realValue());
4287    }
4288
4289    eq FIntegerType.mul(CValue v1, CValue v2) {
4290        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4291            return CValue.UNKNOWN;
4292        }
4293        return new CValueInteger(v1.intValue() * v2.intValue());
4294    }
4295
4296    /**
4297     * Division of constant values.
4298     *
4299     * @param v1 Constant value of left operand.
4300     * @param v2 Constant value of right operand.
4301     * @return Resulting constant value.
4302     */
4303    syn CValue FType.div(CValue v1, CValue v2) = CValue.UNKNOWN;
4304
4305    eq FRealType.div(CValue v1, CValue v2) {
4306        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4307            return CValue.UNKNOWN;
4308        }
4309        return new CValueReal(v1.realValue() / v2.realValue());
4310    }
4311
4312    eq FIntegerType.div(CValue v1, CValue v2) {
4313        if (!v1.isReal() || !v2.isReal()) {
4314            return CValue.UNKNOWN;
4315        }
4316        return new CValueReal(v1.realValue() / v2.realValue());
4317    }
4318
4319    /**
4320     * Power expression for constant values.
4321     *
4322     * @param v1 Constant value of left operand.
4323     * @param v2 Constant value of right operand.
4324     * @return Resulting constant value.
4325     */
4326    syn CValue FType.pow(CValue v1, CValue v2) = CValue.UNKNOWN;
4327
4328    eq FRealType.pow(CValue v1, CValue v2) {
4329        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4330            return CValue.UNKNOWN;
4331        }
4332        return new CValueReal(java.lang.StrictMath.pow(v1.realValue(), v2.realValue()));
4333    }
4334
4335    /**
4336     * Negation of a constant value.
4337     *
4338     * @param v Constant value of operand.
4339     * @return Resulting constant value.
4340     */
4341    syn CValue FType.neg(CValue v) = CValue.UNKNOWN;
4342    eq FRealType.neg(CValue v) = v.hasRealValue() ? new CValueReal(-v.realValue()) : CValue.UNKNOWN;
4343    eq FIntegerType.neg(CValue v) = v.hasIntValue() ? new CValueInteger(-v.intValue()) : CValue.UNKNOWN;
4344
4345    /**
4346     * Abs expression for constant values.
4347     *
4348     * @param v Constant value of operand.
4349     * @return Resulting constant value.
4350     */
4351    syn CValue FType.abs(CValue v) = CValue.UNKNOWN;
4352    eq FRealType.abs(CValue v) = v.hasRealValue() ? new CValueReal(StrictMath.abs(v.realValue())) : CValue.UNKNOWN;
4353    eq FIntegerType.abs(CValue v) =
4354            v.hasIntValue() ? new CValueInteger(StrictMath.abs(v.intValue())) : CValue.UNKNOWN;
4355
4356    /**
4357     * Sign expression for constant values.
4358     *
4359     * @param v Constant value of operand.
4360     * @return Resulting constant value.
4361     */
4362    syn CValue FType.sign(CValue v) = CValue.UNKNOWN;
4363
4364    eq FIntegerType.sign(CValue v) =
4365            v.hasIntValue() ? new CValueInteger((int) StrictMath.signum(v.realValue())) : CValue.UNKNOWN;
4366
4367    /**
4368     * Ceil expression for constant values.
4369     *
4370     * @param v Constant value of operand.
4371     * @return Resulting constant value.
4372     */
4373    syn CValue FType.ceil(CValue v) = CValue.UNKNOWN;
4374
4375    eq FRealType.ceil(CValue v) = v.hasRealValue() ? new CValueReal(StrictMath.ceil(v.realValue())) : CValue.UNKNOWN;
4376
4377    eq FIntegerType.ceil(CValue v) =
4378            v.hasIntValue() ? new CValueInteger((int) StrictMath.ceil(v.realValue())) : CValue.UNKNOWN;
4379
4380    /**
4381     * Truncation to zero for constant values.
4382     *
4383     * @param v Constant value of operand.
4384     * @return Resulting constant value.
4385     */
4386    syn CValue FType.truncToZero(CValue v) = CValue.UNKNOWN;
4387
4388    eq FRealType.truncToZero(CValue v) {
4389        if (!v.hasRealValue()) {
4390            return CValue.UNKNOWN;
4391        }
4392        return v.realValue() < 0 ? ceil(v) : v.convertInteger().convertReal();
4393    }
4394
4395    eq FIntegerType.truncToZero(CValue v) {
4396        if (!v.hasIntValue()) {
4397            return CValue.UNKNOWN;
4398        }
4399        return v.realValue() < 0 ? ceil(v) : v.convertInteger();
4400    }
4401
4402    /**
4403     * And expression for constant values.
4404     *
4405     * @param v1 Constant value of left operand.
4406     * @param v2 Constant value of right operand.
4407     * @return Resulting constant value.
4408     */
4409    syn CValue FType.and(CValue v1, CValue v2) = CValue.UNKNOWN;
4410
4411    eq FBooleanType.and(CValue v1, CValue v2) {
4412        if (!v1.isBoolean() || !v2.isBoolean()) {
4413            return CValue.UNKNOWN;
4414        }
4415        return new CValueBoolean(v1.booleanValue() && v2.booleanValue());
4416    }
4417
4418    /**
4419     * Or expression for constant values.
4420     *
4421     * @param v1 Constant value of left operand.
4422     * @param v2 Constant value of right operand.
4423     * @return Resulting constant value.
4424     */
4425    syn CValue FType.or(CValue v1, CValue v2) = CValue.UNKNOWN;
4426
4427    eq FBooleanType.or(CValue v1, CValue v2) {
4428        if (!v1.isBoolean() || !v2.isBoolean()) {
4429            return CValue.UNKNOWN;
4430        } 
4431        return new CValueBoolean(v1.booleanValue() || v2.booleanValue());
4432    }
4433
4434    /**
4435     * Not expression for constant values.
4436     *
4437     * @param v Constant value of operand.
4438     * @return Resulting constant value.
4439     */
4440    syn CValue FType.not(CValue v) = CValue.UNKNOWN;
4441    eq FBooleanType.not(CValue v) = v.isBoolean() ? new CValueBoolean(!v.booleanValue()) : CValue.UNKNOWN;
4442
4443    /* Machine epsilon */
4444    public static double FRealType.MACHINE_EPSILON = 2.2204460492503131e-16;
4445
4446    /* Epsilon used for Real-type comparisons */
4447    public static double FRealType.ALMOST_EPSILON = MACHINE_EPSILON;
4448
4449    syn boolean FRealType.almostZero(double op)   = almostLtZero(op) && almostGtZero(op);
4450    syn boolean FRealType.almostLtZero(double op) = op <= ALMOST_EPSILON;
4451    syn boolean FRealType.almostGtZero(double op) = op >= -ALMOST_EPSILON;
4452    syn boolean FRealType.surelyLtZero(double op) = op < -ALMOST_EPSILON;
4453    syn boolean FRealType.surelyGtZero(double op) = op > ALMOST_EPSILON;
4454
4455    /**
4456     * Equals comparison for constant values.
4457     *
4458     * @param v1 Constant value of left operand.
4459     * @param v2 Constant value of right operand.
4460     * @return Resulting constant value.
4461     */
4462    syn CValue FType.equ(CValue v1, CValue v2) {
4463        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4464            return CValue.UNKNOWN;
4465        }
4466        return new CValueBoolean(v1.intValue() == v2.intValue());
4467    }
4468
4469    eq FRealType.equ(CValue v1, CValue v2) {
4470        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4471            return CValue.UNKNOWN;
4472        }
4473        return new CValueBoolean(almostZero(v1.realValue() - v2.realValue()));
4474    }
4475
4476    eq FStringType.equ(CValue v1, CValue v2) {
4477        if (!v1.hasStringValue() || !v2.hasStringValue()) {
4478            return CValue.UNKNOWN;
4479        }
4480        return new CValueBoolean(v1.stringValue().compareTo(v2.stringValue()) == 0);
4481    }
4482
4483    eq CValueUnknown.equ(CValue v1, CValue v2) = CValue.UNKNOWN;
4484
4485    /**
4486     * Not equal comparison for constant values.
4487     *
4488     * @param v1 Constant value of left operand.
4489     * @param v2 Constant value of right operand.
4490     * @return Resulting constant value.
4491     */
4492    syn CValue FType.neq(CValue v1, CValue v2) {
4493        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4494            return CValue.UNKNOWN;
4495        }
4496        return new CValueBoolean(v1.intValue() != v2.intValue());
4497    }
4498
4499    eq FRealType.neq(CValue v1, CValue v2) {
4500        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4501            return CValue.UNKNOWN;
4502        }
4503        return new CValueBoolean(v1.realValue() != v2.realValue());
4504    }
4505
4506    eq FStringType.neq(CValue v1, CValue v2) {
4507        if (!v1.hasStringValue() || !v2.hasStringValue()) {
4508            return CValue.UNKNOWN;
4509        }
4510        return new CValueBoolean(v1.stringValue().compareTo(v2.stringValue()) != 0);
4511    }
4512
4513    eq CValueUnknown.neq(CValue v1, CValue v2) = CValue.UNKNOWN;
4514
4515    /**
4516     * Greater or equal than comparison for constant values.
4517     *
4518     * @param v1 Constant value of left operand.
4519     * @param v2 Constant value of right operand.
4520     * @return Resulting constant value.
4521     */
4522    syn CValue FType.geq(CValue v1, CValue v2) {
4523        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4524            return CValue.UNKNOWN;
4525        }
4526        return new CValueBoolean(v1.intValue() >= v2.intValue());
4527    }
4528
4529    eq FRealType.geq(CValue v1, CValue v2) {
4530        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4531            return CValue.UNKNOWN;
4532        }
4533        return new CValueBoolean(almostGtZero(v1.realValue() - v2.realValue()));
4534    }
4535
4536    eq FStringType.geq(CValue v1, CValue v2) {
4537        if (!v1.hasStringValue() || !v2.hasStringValue()) {
4538            return CValue.UNKNOWN;
4539        } 
4540        return new CValueBoolean(v1.stringValue().compareTo(v2.stringValue()) >= 0);
4541    }
4542
4543    eq CValueUnknown.geq(CValue v1, CValue v2) = CValue.UNKNOWN;
4544
4545    /**
4546     * Greater than comparison for constant values.
4547     *
4548     * @param v1 Constant value of left operand.
4549     * @param v2 Constant value of right operand.
4550     * @return Resulting constant value.
4551     */
4552    syn CValue FType.gt(CValue v1, CValue v2) {
4553        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4554            return CValue.UNKNOWN;
4555        }
4556        return new CValueBoolean(v1.intValue() > v2.intValue());
4557    }
4558
4559    eq FRealType.gt(CValue v1, CValue v2) {
4560        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4561            return CValue.UNKNOWN;
4562        }
4563        return new CValueBoolean(v1.realValue() > v2.realValue());
4564    }
4565
4566    eq FStringType.gt(CValue v1, CValue v2) {
4567        if (!v1.hasStringValue() || !v2.hasStringValue()) {
4568            return CValue.UNKNOWN;
4569        }
4570        return new CValueBoolean(v1.stringValue().compareTo(v2.stringValue()) > 0);
4571    }
4572
4573    eq CValueUnknown.gt(CValue v1, CValue v2) = CValue.UNKNOWN;
4574
4575    /**
4576     * Less or equal than comparison for constant values.
4577     *
4578     * @param v1 Constant value of left operand.
4579     * @param v2 Constant value of right operand.
4580     * @return Resulting constant value.
4581     */
4582    syn CValue FType.leq(CValue v1, CValue v2) {
4583        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4584            return CValue.UNKNOWN;
4585        }
4586        return new CValueBoolean(v1.intValue() <= v2.intValue());
4587    }
4588
4589    eq FRealType.leq(CValue v1, CValue v2) {
4590        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4591            return CValue.UNKNOWN;
4592        } 
4593        return new CValueBoolean(almostLtZero(v1.realValue() - v2.realValue()));
4594    }
4595
4596    eq FStringType.leq(CValue v1, CValue v2) {
4597        if (!v1.hasStringValue() || !v2.hasStringValue()) {
4598            return CValue.UNKNOWN;
4599        }
4600        return new CValueBoolean(v1.stringValue().compareTo(v2.stringValue()) <= 0);
4601    }
4602
4603    eq CValueUnknown.leq(CValue v1, CValue v2) = CValue.UNKNOWN;
4604
4605    /**
4606     * Less than comparison for constant values.
4607     *
4608     * @param v1 Constant value of left operand.
4609     * @param v2 Constant value of right operand.
4610     * @return Resulting constant value.
4611     */
4612    syn CValue FType.lt(CValue v1, CValue v2) {
4613        if (!v1.hasIntValue() || !v2.hasIntValue()) {
4614            return CValue.UNKNOWN;
4615        }
4616        return new CValueBoolean(v1.intValue() < v2.intValue());
4617    }
4618
4619    eq FRealType.lt(CValue v1, CValue v2) {
4620        if (!v1.hasRealValue() || !v2.hasRealValue()) {
4621            return CValue.UNKNOWN;
4622        }
4623        return new CValueBoolean(v1.realValue() < v2.realValue());
4624    }
4625
4626    eq FStringType.lt(CValue v1, CValue v2) {
4627        if (!v1.hasStringValue() || !v2.hasStringValue()) {
4628            return CValue.UNKNOWN;
4629        }
4630        return new CValueBoolean(v1.stringValue().compareTo(v2.stringValue()) < 0);
4631    }
4632
4633    eq CValueUnknown.lt(CValue v1, CValue v2) = CValue.UNKNOWN;
4634
4635}
4636
4637aspect ArrayConstantEvaluation {
4638       
4639        /**
4640         * Returns the set of array indices spanned by a component declared with this subscript.
4641         */
4642        syn int[] FSubscript.arrayIndices(VariableEvaluator evaluator) = new int[0];
4643        eq FExpSubscript.arrayIndices(VariableEvaluator evaluator) {
4644                int s = numIndices(evaluator);
4645                if (s < 0)
4646                        s = 0;
4647                int ind[] = new int[s];
4648                for (int i = 0; i < s; i++) 
4649                        ind[i] = i + 1;
4650                return ind;
4651        }
4652
4653       
4654        /**
4655         * Get the number of array indices spanned by a component declared with this subscript.
4656         */
4657        syn int FSubscript.numIndices(VariableEvaluator evaluator) = 0;
4658        eq FExpSubscript.numIndices(VariableEvaluator evaluator) = getFExp().ceval(evaluator).intValue();
4659
4660}
4661
4662aspect LiteralExpressions {
4663
4664    syn boolean FExp.hasOnlyLiterals() {
4665        for (FExp e : childFExps())
4666            if (!e.hasOnlyLiterals())
4667                return false;
4668        return true;
4669    }
4670
4671    eq CommonAccessExp.hasOnlyLiterals()= false;
4672    eq FFunctionCall.hasOnlyLiterals()  = false;
4673    eq FTimeExp.hasOnlyLiterals()       = false;
4674    eq FEndExp.hasOnlyLiterals()        = !inFunction();
4675
4676}
4677
4678aspect CircularExpressions {
4679
4680    /**
4681     * Check if expression is circular.
4682     *
4683     * Default implementation returns <code>true</code> if any direct FExp child
4684     * is circular.
4685     */
4686    syn boolean FExp.isCircular() = false;
4687    syn lazy boolean FAbstractExp.isCircular() {
4688        if (inIsCircular)
4689            return true;
4690        inIsCircular = true;
4691        boolean res = isCircularCalc();
4692        inIsCircular = false;
4693        return res;
4694    }
4695
4696        syn boolean FExp.isCircularCalc() = false;
4697        eq FAbstractExp.isCircularCalc() {
4698                for (FExp e : childFExps())
4699                        if (e.isCircular())
4700                                return true;
4701                return false;
4702        }
4703       
4704        private boolean FAbstractExp.inIsCircular = false; 
4705       
4706    eq CommonAccessExp.isCircularCalc() = getAccess().isCircular(-1);
4707   
4708    syn boolean CommonAccess.isCircular(int dim);
4709    eq FAccess.isCircular(int dim)     = myFV().isCircular();
4710    eq InstAccess.isCircular(int dim) = myInstComponentDecl().isCircular(dim);
4711
4712        syn lazy boolean FForIndex.isCircular() circular [true] = getFExp().isCircular(); // TODO: test without when it works
4713
4714        eq FSizeExp.isCircularCalc() { 
4715                Size s = getFExp().size();
4716                return hasDim() ? s.isCircular(dimension()) : s.isCircular();
4717        }
4718    eq FUnknownSizeExp.isCircularCalc() = getDim().isCircular() || getFExp().asCommonAccess().isCircular(dimension());
4719   
4720    eq FIfExp.isCircularCalc() {
4721        if (getIfExp().variability().evalOrLess()) {
4722            try {
4723                CValue testVal = getIfExp().ceval();
4724                if (testVal.hasBooleanValue()) {
4725                    if (testVal.booleanValue())
4726                        return getThenExp().isCircular();
4727                    else
4728                        return getElseExp().isCircular();
4729                }
4730            } catch (ConstantEvaluationException e) {}
4731        }
4732        return super.isCircularCalc();
4733    }
4734
4735        syn boolean FExp.isUnknownSizeVarUse()  = false;
4736        eq CommonAccessExp.isUnknownSizeVarUse()= getAccess().isUnknownSizeVarUse();
4737       
4738        syn boolean CommonAccess.isUnknownSizeVarUse();
4739        eq FAccess.isUnknownSizeVarUse()     = myFV().isUnknownSizeVar();
4740        eq InstAccess.isUnknownSizeVarUse() = myInstComponentDecl().isUnknownSizeVar();
4741       
4742        syn boolean FAbstractVariable.isUnknownSizeVar() = false;
4743    eq FFunctionVariable.isUnknownSizeVar()          = getType().size().isUnknown();
4744        syn boolean InstComponentDecl.isUnknownSizeVar() = type().size().isUnknown();
4745       
4746        public boolean Size.isCircular() {
4747                for (int d = 0; d < size.length; d++)
4748                        if (isCircular(d))
4749                                return true;
4750                return false;
4751        }
4752       
4753        public boolean Size.isCircular(int d) {
4754                return false;
4755        }
4756       
4757        public boolean MutableSize.isCircular(int d) {
4758                try {
4759                        return size[d] == UNKNOWN && exps[d] != null && exps[d].isCircular();
4760                } catch (ArrayIndexOutOfBoundsException e) {
4761                        return false;
4762                }
4763        }
4764
4765    eq FIterExp.isCircularCalc() {
4766        if (getFExp().isCircular()) 
4767            return true;
4768        for (CommonForIndex i : getForIndexList()) 
4769            if (i.isCircular()) 
4770                return true;
4771        return false;
4772    }
4773
4774    syn boolean CommonForIndex.isCircular() = getFExp().isCircular();
4775    eq InstForIndexNoExp.isCircular()       = hasFExp() && getFExp().isCircular();
4776
4777        eq InstFunctionCall.isCircularCalc() {
4778                for (InstFunctionArgument a : getArgs())
4779                        if (a.isCircular())
4780                                return true;
4781                return false;
4782        }
4783
4784    syn boolean InstFunctionArgument.isCircular() = false;
4785    eq InstGivenArgument.isCircular()      = getFExp().isCircular();
4786    eq InstDefaultArgument.isCircular()    = getFExp().isCircular();
4787
4788
4789        syn lazy boolean FAbstractVariable.isCircular() circular [true] = false;
4790        eq FVariable.isCircular() = getFAccess().isCircular() || (hasBindingExp() && getBindingExp().isCircular());
4791       
4792        syn boolean FAccess.isCircular() = false;
4793        eq FAccessFull.isCircular() {
4794                for (FAccessPart part : getFAccessParts())
4795                        if (part.isCircular())
4796                                return true;
4797                return false;
4798        }
4799       
4800        syn boolean FAccessPart.isCircular() = false;
4801        eq FAccessPartArray.isCircular()     = getFArraySubscripts().isCircular();
4802
4803    syn lazy boolean InstComponentDecl.isCircular(int dim) circular [true] = false;
4804    eq InstAssignable.isCircular(int dim) {
4805        if (hasFArraySubscripts()) {
4806            if (dim == -1) {
4807                if (getFArraySubscripts().isCircular()) {
4808                    return true;
4809                }
4810            } else {
4811                if (getFArraySubscripts().subscript(dim).isCircular()) {
4812                    return true;
4813                }
4814            }
4815        }
4816        return (hasBindingFExp() && getBindingFExp().isCircular());
4817    }
4818    eq InstRecord.isCircular(int dim) = false;
4819
4820        syn boolean FArraySubscripts.isCircular() = false;
4821        eq FArrayExpSubscripts.isCircular() {
4822                for (FSubscript fs : getFSubscripts())
4823                        if (fs.isCircular())
4824                                return true;
4825                return false;
4826        }
4827       
4828        syn boolean FSubscript.isCircular() = false;
4829        eq FExpSubscript.isCircular() = getFExp().isCircular();
4830        public boolean IntegerSubscript.isCircular() { return false; }
4831
4832}
4833
4834aspect AritmeticTransformations {
4835
4836    /**
4837     * Create a negated copy of this expression.
4838     */
4839    syn FExp FExp.createNegated()     = new FNegExp(fullCopy());
4840    eq FNegExp.createNegated()        = getFExp().fullCopy();
4841    eq FDotSubExp.createNegated()     = createNodeBinary(getRight().fullCopy(), getLeft().fullCopy());
4842    eq FDotAddExp.createNegated()     = new FDotSubExp(new FNegExp(getLeft().fullCopy()), getRight().fullCopy());
4843    eq FAddExp.createNegated()        = new FSubExp(new FNegExp(getLeft().fullCopy()), getRight().fullCopy());
4844    eq FIntegerLitExp.createNegated() = new FIntegerLitExp(- getValue());
4845    eq FRealLitExp.createNegated()    = new FRealLitExp(- getValue());
4846
4847    /**
4848     * Return this expression negated.
4849     *
4850     * Does not copy expression.
4851     */
4852    syn FExp FExp.makeNegated()     = new FNegExp(this);
4853    eq FNegExp.makeNegated()        = getFExp();
4854    eq FDotAddExp.makeNegated()     = new FDotSubExp(new FNegExp(getLeft()), getRight());
4855    eq FAddExp.makeNegated()        = new FSubExp(new FNegExp(getLeft()), getRight());
4856    eq FDotSubExp.makeNegated() {
4857        FExp tmp = getLeft();
4858        setLeft(getRight());
4859        setRight(tmp);
4860        return this;
4861    }
4862    eq FIntegerLitExp.makeNegated() {
4863        setValue(- getValue());
4864        return this;
4865    }
4866    eq FRealLitExp.makeNegated() {
4867        setValue(- getValue());
4868        return this;
4869    }
4870
4871    /**
4872     * Can {@link #makeNegated()} and {@link #createNegated()} do something better
4873     * than just wrapping the expression in a FNegExp?
4874     */
4875    syn boolean FExp.hasSimpleNegation()  = false;
4876    eq FNegExp.hasSimpleNegation()        = true;
4877    eq FDotSubExp.hasSimpleNegation()     = true;
4878    eq FDotAddExp.hasSimpleNegation()     = true;
4879    eq FIntegerLitExp.hasSimpleNegation() = true;
4880    eq FRealLitExp.hasSimpleNegation()    = true;
4881
4882}
4883
4884aspect SourceCeval {
4885    /**
4886     * Source Constant evaluations only implemented for the most basic expressions.
4887     */ 
4888    syn CValue SrcExp.ceval()        = CValue.UNKNOWN;
4889    eq SrcStringLitExp.ceval()       = new CValueString(unEscape());
4890    eq SrcAccessExp.ceval()          = new CValueUnknownAccess(getSrcAccess().name());
4891    eq SrcBooleanLitExpTrue.ceval()  = CValueBoolean.TRUE;
4892    eq SrcBooleanLitExpFalse.ceval() = CValueBoolean.FALSE;
4893    eq SrcIntegerLitExp.ceval()      = new CValueInteger(Integer.parseInt(getUNSIGNED_INTEGER()));
4894    eq SrcRealLitExp.ceval()         = new CValueReal(Double.parseDouble(getUNSIGNED_NUMBER()));
4895    eq SrcArrayConstructor.ceval()   = cevalArray();
4896    eq SrcMatrix.ceval()             = cevalArray();
4897    eq SrcNegExp.ceval() {
4898        CValue value = getSrcExp().ceval();
4899        if (value.isInteger())
4900            return new CValueInteger(-value.intValue());
4901        else if (value.isReal())
4902            return new CValueReal(-value.realValue());
4903        else
4904            return CValue.UNKNOWN;
4905    }
4906   
4907    syn CValue SrcExp.cevalArray() = fillArrayCValue(new CValueArray(sizeCeval()));
4908   
4909    public CValue SrcExp.fillArrayCValue(CValueArray arrayValue) {
4910        List<? extends SrcExp> exps = arrayChildrenForCeval();
4911        if (exps == null) {
4912            arrayValue.addCell(ceval());
4913        } else {
4914            for (SrcExp exp : exps) {
4915                exp.fillArrayCValue(arrayValue);
4916            }
4917        }
4918        return arrayValue;
4919    }
4920   
4921    /**
4922     * It is currently not possible to use an VariableEvaluator for source node
4923     * expressions. This implementation simply delegates to ceval() without
4924     * arguments.
4925     */
4926    syn CValue SrcExp.ceval(VariableEvaluator evaluator) = ceval();
4927   
4928    syn int SrcExp.ndimsCeval() {
4929        List<? extends SrcExp> exps = arrayChildrenForCeval();
4930        if (exps == null) {
4931            return 0;
4932        } else if (exps.getNumChild() == 0) {
4933            return 1;
4934        } else {
4935            return 1 + exps.getChild(0).ndimsCeval();
4936        }
4937    }
4938
4939    syn Size SrcExp.sizeCeval() {
4940        int n = ndimsCeval();
4941        if (n == 0) {
4942            return Size.SCALAR;
4943        } else {
4944            int[] dims = new int[n];
4945            fillSizeCeval(dims, 0);
4946            return new Size(dims);
4947        }
4948    }
4949
4950    public void SrcExp.fillSizeCeval(int[] dims, int i) {
4951        List<? extends SrcExp> exps = arrayChildrenForCeval();
4952        dims[i] = exps.getNumChild();
4953        if (i + 1 < dims.length && dims[i] > 0) {
4954            exps.getChild(0).fillSizeCeval(dims, i + 1);
4955        }
4956    }
4957
4958    syn List<? extends SrcExp> SrcExp.arrayChildrenForCeval()   = null;
4959    eq SrcArrayConstructor.arrayChildrenForCeval() = getSrcFunctionArguments().getSrcExps();
4960    eq SrcMatrix.arrayChildrenForCeval()           = getRows();
4961    eq SrcMatrixRow.arrayChildrenForCeval()        = getSrcExps();
4962}
4963
4964aspect ConstantEvaluable {
4965    SrcExp implements Evaluable;
4966    FExp implements Evaluable;
4967   
4968    public ConstValue SrcExp.evaluateValue() {
4969        try {
4970            return ceval();
4971        } catch (ConstantEvaluationException e) {
4972            return CValue.UNKNOWN;
4973        }
4974    }
4975    public ConstValue FExp.evaluateValue() {
4976        try {
4977            return ceval();
4978        } catch (ConstantEvaluationException e) {
4979            return CValue.UNKNOWN;
4980        }
4981    }
4982}
4983
4984aspect VariableEvaluator {
4985    public static VariableEvaluator ASTNode.defaultVariableEvaluator() {
4986        return VariableEvaluator.instance;
4987    }
4988   
4989    public class VariableEvaluator {
4990        public static final VariableEvaluator instance = new VariableEvaluator(true);
4991        private final boolean externalEvaluationEnabled;
4992       
4993        public VariableEvaluator(boolean externalEvaluationEnabled) {
4994            this.externalEvaluationEnabled = externalEvaluationEnabled;
4995        }
4996       
4997        public CValue ceval(CommonVariableDecl variable) {
4998            return variable.ceval(this);
4999        }
5000       
5001        /**
5002         * Works only for supporting evaluators.
5003         */
5004        public CValue ceval(String name) {
5005            throw new ConstantEvaluationException(null, "This evaluator doesn't support this type of value lookup");
5006        }
5007       
5008        public CValue ceval(CommonVariableDecl variable, Index i) {
5009            return variable.ceval(this, i);
5010        }
5011       
5012        public CValue cevalUse(CommonAccessExp access) {
5013            return access.cevalUse(this);
5014        }
5015       
5016        public AlgorithmEvaluator createAlgorithmEvaluator(AbstractOptionRegistry options, Map<CommonVariableDecl, CValue> values) {
5017            return new AlgorithmEvaluator(externalEvaluationEnabled, options, values);
5018        }
5019       
5020        public AlgorithmEvaluator createEmptyAlgorithmEvaluator(AbstractOptionRegistry options) {
5021            return new AlgorithmEvaluator(true, options, Collections.<CommonVariableDecl, CValue>emptyMap());
5022        }
5023       
5024        public boolean hasEvaluationValue(CommonVariableDecl variable) {
5025            return variable.getLocalCachedEvaluationValue() != null;
5026        }
5027       
5028        public void setEvaluationValue(CommonVariableDecl variable, CValue val) {
5029            variable.setLocalCachedEvaluationValue(val);
5030        }
5031       
5032        public CValue evaluationValue(CommonVariableDecl variable) {
5033            CValue val = variable.getLocalCachedEvaluationValue();
5034            return val == null ? CValue.UNKNOWN : val;
5035        }
5036       
5037        public void clearEvaluationValue(CommonVariableDecl variable) {
5038            variable.clearLocalCachedEvaluationValue();
5039        }
5040       
5041        public CValue timeValue() {
5042            return CValue.UNKNOWN;
5043        }
5044       
5045        public CValue inStreamEpsilon() {
5046            return CValue.UNKNOWN;
5047        }
5048       
5049        public boolean externalEvaluationEnabled() {
5050            return externalEvaluationEnabled;
5051        }
5052       
5053        public CValue evalBinOp(FBinExp exp, CValue left, CValue right) {
5054            return exp.cevalEval(left, right);
5055        }
5056       
5057        public CValue evalUnOp(FUnaryExp exp, CValue val) {
5058            return exp.cevalEval(val);
5059        }
5060    }
5061   
5062    public class PartialVariableEvaluator extends VariableEvaluator {
5063       
5064        public PartialVariableEvaluator(boolean externalEvaluationEnabled) {
5065            super(externalEvaluationEnabled);
5066        }
5067       
5068        @Override
5069        public CValue cevalUse(CommonAccessExp access) {
5070            if (access.variability().knownParameterOrLess()) {
5071                return super.cevalUse(access);
5072            } else {
5073                return createUnknownCValue(access);
5074            }
5075        }
5076       
5077        protected CValue createUnknownCValue(CommonAccessExp access) {
5078            return access.type().unknownCValue();
5079        }
5080       
5081        protected CValue createUnknownCValue(FExp exp) {
5082            return exp.type().unknownCValue();
5083        }
5084       
5085        @Override
5086        public AlgorithmEvaluator createAlgorithmEvaluator(AbstractOptionRegistry options, Map<CommonVariableDecl, CValue> values) {
5087            return new PartialAlgorithmEvaluator(externalEvaluationEnabled(), options, values, this);
5088        }
5089       
5090        @Override
5091        public CValue evalBinOp(FBinExp exp, CValue left, CValue right) {
5092            if (left.isUnknown() || right.isUnknown()) {
5093                return left.merge(right);
5094            }
5095            return exp.cevalEval(left, right);
5096        }
5097       
5098        @Override
5099        public CValue evalUnOp(FUnaryExp exp, CValue val) {
5100            if (val.isUnknown()) {
5101                return val;
5102            }
5103            return exp.cevalEval(val);
5104        }
5105       
5106        public boolean isDependencyEvaluator() {
5107            return false;
5108        }
5109       
5110    }
5111   
5112    public class DependencyVariableEvaluator extends PartialVariableEvaluator {
5113        Map<CommonVariableDecl,CValue> values;
5114       
5115        public DependencyVariableEvaluator() {
5116            super(false);
5117        }
5118       
5119        @Override
5120        public AlgorithmEvaluator createAlgorithmEvaluator(AbstractOptionRegistry options, Map<CommonVariableDecl, CValue> values) {
5121            if (this.values == null) {
5122                this.values = values;
5123            }
5124            return new PartialAlgorithmEvaluator(externalEvaluationEnabled(), options, values, this);
5125        }
5126       
5127        @Override
5128        protected CValue createUnknownCValue(CommonAccessExp use) {
5129            if (use.getAccess().isFAccess()) {
5130                return new CValueUnknownUse(use.asFAccessExp());
5131            } else {
5132                return new CValueUnknownUse();
5133            }
5134        }
5135       
5136        @Override
5137        protected CValue createUnknownCValue(FExp exp) {
5138            CValue val = new CValueUnknownUse();
5139            for (FAccessExp use : exp.findFAccessExpsInTree()) {
5140                val = val.merge(use.cevalUse(this));
5141            }
5142            return val;
5143        }
5144       
5145        @Override
5146        public CValue timeValue() {
5147            return new CValueUnknownUse();
5148        }
5149       
5150        public Map<FAccessExp, Set<FAccessExp>> resolveDependencies(FFunctionCallEquation equation) {
5151            Map<FAccessExp, Set<FAccessExp>> res = new HashMap<>();
5152            for (int i = 0; i < equation.getNumLeft(); i++) {
5153                if (equation.getLeft(i).hasFExp()) {
5154                    FExp e = equation.getLeft(i).getFExp();
5155                    CommonVariableDecl cvd = equation.getCall().myCallOutputs().get(i);
5156                    e.mapComponents(res, values.get(cvd));
5157                }
5158            }
5159            return res;
5160        }
5161       
5162        @Override
5163        public boolean isDependencyEvaluator() {
5164            return true;
5165        }
5166    }
5167   
5168    public void FExp.mapComponents(Map<FAccessExp, Set<FAccessExp>> res, CValue val) {
5169        throw new UnsupportedOperationException("Unsupported FExp in LHS");
5170    }
5171   
5172    public void FArray.mapComponents(Map<FAccessExp, Set<FAccessExp>> res, CValue val) {
5173        Enumerator e = new Enumerator();
5174        mapComponentsArray(res, val.array(), e);
5175    }
5176   
5177    public void FExp.mapComponentsArray(Map<FAccessExp, Set<FAccessExp>> res, CValueArray val, Enumerator e) {
5178        mapComponents(res, val.getCell(e.next()));
5179    }
5180   
5181    public void FArray.mapComponentsArray(Map<FAccessExp, Set<FAccessExp>> res, CValueArray val, Enumerator e) {
5182        for (FExp exp : getFExps()) {
5183            exp.mapComponentsArray(res, val, e);
5184        }
5185    }
5186   
5187    public void FRecordConstructor.mapComponents(Map<FAccessExp, Set<FAccessExp>> res, CValue val) {
5188        CValueRecord rec = val.record();
5189        for (int i = 0; i < getNumArg(); i++) {
5190            getArg(i).mapComponents(res, rec.getMember(i));
5191        }
5192    }
5193   
5194    public void FAccessExp.mapComponents(Map<FAccessExp, Set<FAccessExp>> res, CValue val) {
5195        Set<FAccessExp> s = new HashSet<>();
5196        s.addAll(val.getDependencies());
5197        res.put(this, s);
5198    }
5199   
5200    public Set<FAccessExp> CValue.getDependencies() {
5201        return new HashSet<>();
5202    }
5203   
5204    public Set<FAccessExp> CValueUnknown.getDependencies() {
5205        return unknownUse().getDependencies();
5206    }
5207   
5208    public void FNoExp.mapComponents(Map<FAccessExp, Set<FAccessExp>> res, CValue val) {
5209       
5210    }
5211   
5212    public class AlgorithmEvaluator extends VariableEvaluator {
5213       
5214        protected Map<CommonVariableDecl, CValue> values;
5215        private AbstractOptionRegistry options;
5216       
5217        public AlgorithmEvaluator(boolean evaluateExternalEnabled, AbstractOptionRegistry options, Map<CommonVariableDecl, CValue> values) {
5218            super(evaluateExternalEnabled);
5219            this.values  = values;
5220            this.options = options;
5221        }
5222       
5223        public int externalEvaluation() {
5224            return externalEvaluationEnabled() ? options.getIntegerOption("external_constant_evaluation") : 0;
5225        }
5226       
5227        @Override
5228        public String toString() {
5229            StringBuilder sb = new StringBuilder();
5230            sb.append(super.toString());
5231            sb.append("\n");
5232            for (CommonVariableDecl cvd : values.keySet()) {
5233                sb.append(cvd.toString());
5234                sb.append(" = ");
5235                sb.append(values.get(cvd).toString());
5236                sb.append("\n");
5237            }
5238            return sb.toString();
5239        }
5240       
5241        public CValue ceval(FExp exp) {
5242            return exp.ceval(this);
5243        }
5244       
5245        @Override
5246        public void setEvaluationValue(CommonVariableDecl variable, CValue val) {
5247            super.setEvaluationValue(variable, val);
5248            values.put(variable, val);
5249        }
5250       
5251        public void clear() {
5252            values.clear();
5253        }
5254       
5255        public Map<CommonVariableDecl, CValue> getValues() {
5256            return values;
5257        }
5258       
5259        public void failed(CommonCallable cc, ConstantEvaluationException e) {
5260            throw new FunctionEvaluationException(cc.qualifiedName(), e);
5261        }
5262       
5263        public boolean recursive(CommonCallable cc) {
5264            return true;
5265        }
5266       
5267        /**
5268         * Called when an if statement evaluation is started.
5269         */
5270        public void startIf() {}
5271       
5272        /**
5273         * Called when an if statement evaluation is finished.
5274         */
5275        public void endIf() {}
5276       
5277        /**
5278         * Called when an if branch evaluation is finished.
5279         */
5280        public void branchIf(int res) {}
5281       
5282    }
5283   
5284    public class PartialAlgorithmEvaluator extends AlgorithmEvaluator {
5285        protected PartialVariableEvaluator variableEvaluator;
5286        protected ArrayList<IfEvaluation> ifStack;
5287       
5288        public PartialAlgorithmEvaluator(boolean evaluateExternalEnabled, AbstractOptionRegistry options,
5289                Map<CommonVariableDecl, CValue> values, PartialVariableEvaluator variableEvaluator) {
5290            super(evaluateExternalEnabled, options, values);
5291            this.variableEvaluator = variableEvaluator;
5292            ifStack = new ArrayList<IfEvaluation>();
5293        }
5294       
5295        @Override
5296        public CValue ceval(FExp exp) {
5297            try {
5298                return exp.ceval(this);
5299            } catch (ConstantEvaluationException e) {
5300                return variableEvaluator.createUnknownCValue(exp);
5301            }
5302        }
5303       
5304        @Override
5305        public AlgorithmEvaluator createAlgorithmEvaluator(AbstractOptionRegistry options, Map<CommonVariableDecl, CValue> values) {
5306            return variableEvaluator.createAlgorithmEvaluator(options, values);
5307        }
5308       
5309        @Override
5310        public CValue evalBinOp(FBinExp exp, CValue left, CValue right) {
5311            return variableEvaluator.evalBinOp(exp, left, right);
5312        }
5313       
5314        @Override
5315        public CValue evalUnOp(FUnaryExp exp, CValue val) {
5316            return variableEvaluator.evalUnOp(exp, val);
5317        }
5318       
5319        @Override
5320        public void failed(CommonCallable cc, ConstantEvaluationException e) {
5321            values.clear();
5322            for (CommonVariableDecl cvd : cc.myOutputs()) {
5323                values.put(cvd, CValue.UNKNOWN);
5324            }
5325        }
5326       
5327        @Override
5328        public boolean recursive(CommonCallable cc) {
5329            if (variableEvaluator.isDependencyEvaluator()) {
5330                CValueUnknownUse val = new CValueUnknownUse();
5331                for (CommonVariableDecl cvd : cc.myInputs()) {
5332                    val.merge(values.get(cvd));
5333                }
5334                for (CommonVariableDecl cvd : cc.myOutputs()) {
5335                    values.put(cvd, val);
5336                }
5337                return false;
5338            } else {
5339                throw new ConstantEvaluationException(null, "Partial evaluation of recursive functions not supported.");
5340            }
5341        }
5342       
5343        @Override
5344        public void startIf() {
5345            if (variableEvaluator.isDependencyEvaluator()) {
5346                throw new ConstantEvaluationException(null, "Dependency evaluation of if statements not supported.");
5347            }
5348            ifStack.add(new IfEvaluation());
5349        }
5350       
5351        @Override
5352        public void endIf() {
5353            ifStack.remove(ifStack.size()-1).merge();
5354        }
5355       
5356        @Override
5357        public void branchIf(int res) {
5358            ifStack.get(ifStack.size()-1).restore(res);
5359        }
5360       
5361        /**
5362         * Stores several sets of values evaluated from different if-branches
5363         */
5364        private class IfEvaluation {
5365            protected Map<CommonVariableDecl, CValue> valuesBefore;
5366            protected ArrayList<IfBranchEvaluated> branches;
5367           
5368            public IfEvaluation() {
5369                valuesBefore = new HashMap<CommonVariableDecl, CValue>();
5370                for (CommonVariableDecl cvd : values.keySet()) {
5371                    valuesBefore.put(cvd, values.get(cvd).clone());
5372                }
5373                branches = new ArrayList<IfBranchEvaluated>();
5374            }
5375           
5376            /**
5377             * Called when if branch has been evaluated. Will store the evaluators current
5378             * value set and restore that set as it was before this if-clause was entered.
5379             */
5380            public void restore(int res) {
5381                IfBranchEvaluated lastBranch = new IfBranchEvaluated(res);
5382                branches.add(lastBranch);
5383               
5384                for (CommonVariableDecl cvd : values.keySet()) {
5385                    cvd.setEvaluationValue(PartialAlgorithmEvaluator.this, CValue.UNKNOWN);
5386                }
5387                for (CommonVariableDecl cvd : valuesBefore.keySet()) {
5388                    cvd.setEvaluationValue(PartialAlgorithmEvaluator.this, valuesBefore.get(cvd));
5389                }
5390            }
5391           
5392            /**
5393             * Merge all evaluated branches and write result to evaluators current value set.
5394             */
5395            public void merge() {
5396                IfBranchEvaluated res = branches.get(0);
5397                for (int i = 1 ; i < branches.size(); i++) {
5398                    res.merge(branches.get(i));
5399                }
5400                res.restore();
5401            }
5402           
5403            /**
5404             * Stores values evaluated from an if-branch.
5405             */
5406            private class IfBranchEvaluated {
5407                Map<CommonVariableDecl, CValue> values;
5408                int res;
5409               
5410                public IfBranchEvaluated(int res) {
5411                    this.res = res;
5412                    values = new HashMap<CommonVariableDecl, CValue>();
5413                    for (CommonVariableDecl cvd : PartialAlgorithmEvaluator.this.values.keySet()) {
5414                        values.put(cvd, PartialAlgorithmEvaluator.this.values.get(cvd).clone());
5415                    }
5416                }
5417               
5418                /**
5419                 * Merge values from other branch into this. Differing values results in unknown values.
5420                 */
5421                public void merge(IfBranchEvaluated other) {
5422                    if (res != other.res) {
5423                        throw new ConstantEvaluationException(null, "Partial constant evaluation of if statements with "
5424                                + "differing return statuses is not possible");
5425                    }
5426                    for (CommonVariableDecl cvd : other.values.keySet()) {
5427                        if (values.get(cvd) == null) {
5428                            values.put(cvd, cvd.type().unknownCValue());
5429                        } else {
5430                            values.put(cvd, values.get(cvd).merge(other.values.get(cvd)));
5431                        }
5432                    }
5433                }
5434               
5435                /**
5436                 * Write this branch into the value set used by the evaluator.
5437                 */
5438                public void restore() {
5439                    for (CommonVariableDecl cvd : values.keySet()) {
5440                        cvd.setEvaluationValue(PartialAlgorithmEvaluator.this, values.get(cvd));
5441                    }
5442                }
5443            }
5444        }
5445    }
5446}
Note: See TracBrowser for help on using the repository browser.