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

Last change on this file since 13800 was 13800, checked in by randersson, 7 weeks ago

#5819 Merged trunk into branch

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