source: branches/dev-5819/Compiler/ModelicaFrontEnd/src/jastadd/flattening/Flattening.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: 136.6 KB
Line 
1/*
2    Copyright (C) 2009 Modelon AB
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, version 3 of the License.
7
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12
13    You should have received a copy of the GNU General Public License
14    along with this program.  If not, see <http://www.gnu.org/licenses/>.
15*/
16
17import java.util.HashMap;
18import java.util.Map;
19import java.util.Arrays;
20import java.util.Collections;
21import java.util.Set;
22import java.util.HashSet;
23import java.util.Stack;
24
25aspect FlatTree {
26
27    /**
28     * Create a correctly set up FClass.
29     *
30     * Also creates a FlatRoot and sets its fields.
31     *
32     * @param icl   the class being flattened
33     * @param file  the path to the file to report errors on
34     */
35    public static FClass FClass.create(InstClassDecl icl, String flatName) {
36        FlatRoot flatRoot = new FlatRoot(icl.createFClass());
37        //flatRoot.setFileName(file);
38        FClass fc = flatRoot.getFClass(); // make FClass final
39        fc.userDefinedName = flatName;
40        fc.root().transferRoot(icl.root());
41        fc.setDynamicStateManager(new DynamicStateManager());
42        return fc;
43    }
44
45    /**
46     * Set the name of the FClass.
47     *
48     * If a user-defined name has been set, use it, otherwise use the given name.
49     */
50    public void FClass.setName(String name) {
51        if (userDefinedName != null) 
52            name = userDefinedName;
53        setFAccess(new FAccessString(name));
54    }
55
56    /**
57     * User-defined name for the flat class.
58     */
59    private String FClass.userDefinedName = null;
60
61    /**
62     * Create a new FClass object.
63     *
64     * Override for subclasses needing a subclass of FClass.
65     */
66    public FClass InstClassDecl.createFClass() {
67        return new FClass();
68    }
69
70}
71
72aspect Flattening {
73
74    /**
75     * Generic traversal method used to find a particular class instance
76     * in the instance tree, and if so, flatten it.
77     */
78    public InstNode InstProgramRoot.findFlattenInst(String className,FClass fc) throws ModelicaClassNotFoundException {
79       
80        InstLookupResult<InstClassDecl> icd = lookupInstClassQualified(className);
81        if (icd.successful()) {
82            icd.target().flattenInstClassDecl(fc);
83        } else {
84            throw new ModelicaClassNotFoundException(className);
85        }
86       
87        return icd.target();
88    }
89
90    public void InstClassDecl.flattenInstClassDecl(FClass fc) {
91        int level = 1;
92        HashMap<InstNode,Integer> oldLevels = setModificationLevel(level);
93        beginStep("flattenInstClassDecl()");
94        fc.setName(qualifiedName());
95        buildConnectionSets(fc);
96        breakOnErrors();
97        beginStep("flattenComponents()");
98        Flattener f = new Flattener(fc);
99        flatten(f, FlattenBindingExp.ALL, level);
100        getInstGeneratedInners().flatten(f, FlattenBindingExp.ALL, level);
101        flattenUsedFuncsAndEnums(f);
102        flattenInstClassDeclExtra(f);
103        fc.update(f);
104        endStep("flattenComponents()");
105        fc.updateVariabilityForVariablesInWhen();
106        fc.genConnectionEquations(f);
107        fc.update(f);
108        fc.createExperiment(annotation("experiment"));
109        breakOnErrors();
110        endStep("flattenInstClassDecl()");
111        fc.transformationStepDebug();
112        clearModificationLevel(oldLevels);
113    }
114
115
116    public void InstSimpleShortClassDecl.flattenInstClassDecl(FClass fc) {
117        actualInstClass().flattenInstClassDecl(fc);
118        fc.setFAccess(new FAccessString(qualifiedName()));
119    }
120
121    public void InstLibNode.flattenInstClassDecl(FClass fc) {
122        actualInstClass().flattenInstClassDecl(fc);
123    }
124   
125    /** This class accumulates all flattened equations and variables. It is a layer
126     * of abstraction between the flat AST and the flattening operation. After the operation is
127     * done, the flat AST needs to be updated by calling the attribute FClass.updateFC().
128     *
129     */ 
130    public class Flattener {
131        private FClass fc;
132        private List<FGlobalVariable>   globalVariables = new List<FGlobalVariable>();
133        private List<FVariable>         variables       = new List<FVariable>();
134        private List<FAbstractEquation> normalEqns      = new List<FAbstractEquation>();
135        private List<FAbstractEquation> initialEqns     = new List<FAbstractEquation>();
136        private List<FAbstractEquation> parameterEqns   = new List<FAbstractEquation>();
137       
138        private List<FFunctionDecl> functionDecls = new List<FFunctionDecl>();
139        private List<FRecordDecl> recordDecls = new List<FRecordDecl>();
140        private List<FEnumDecl> enumDecls = new List<FEnumDecl>();       
141        private List<FDerivedType> derivedTypes = new List<FDerivedType>();
142       
143        private Set<String> flattenedNodes = new HashSet<String>();
144       
145       
146        public Flattener(FClass fc) {
147            this.fc = fc;
148        }
149       
150        public FClass getFClass() {
151            return fc; // TODO: Remove this method
152        }
153       
154        public boolean isFlattened(InstNode n) {
155            return flattenedNodes.contains(n.qualifiedTypeName());
156        }
157
158        public boolean isFlattenedGlobalVariable(InstNode n) {
159            return flattenedNodes.contains(n.surroundingInstClass().qualifiedName() + "." + n.qualifiedName());
160        }
161
162        public List<FAbstractEquation> getNormalEquations() {
163            return normalEqns;
164        }
165       
166        public List<FAbstractEquation> getInitialEquations() {
167            return initialEqns;
168        }
169       
170        public List<FAbstractEquation> getParameterEquations() {
171            return parameterEqns;
172        }
173       
174        public List<FGlobalVariable> getFGlobalVariables() {
175            return globalVariables;
176        }
177       
178        public List<FVariable> getFVariables() {
179            return variables;
180        }
181       
182        public List<FFunctionDecl> getFFunctionDecls() {
183            return functionDecls;
184        }
185       
186        public List<FRecordDecl> getFRecordDecls() {
187            return recordDecls;
188        }
189       
190        public List<FEnumDecl> getFEnumDecls() {
191            return enumDecls;
192        }
193       
194        public List<FDerivedType> getFDerivedTypes() {
195            return derivedTypes;
196        }
197       
198        public void addGlobalVariable(FVariable fvariable) {
199            addFlattened(fvariable.name());
200            globalVariables.add((FGlobalVariable)fvariable);
201        }
202       
203        public void addFVariable(FVariable fvariable) {
204            variables.add(fvariable);
205        }
206       
207        public void addNormalEquation(FAbstractEquation fae) {
208            normalEqns.add(fae);
209        }
210       
211         public void addParameterEquation(FAbstractEquation fae) {
212            parameterEqns.add(fae);
213        }
214       
215        public void addFFunctionDecl(FFunctionDecl ffd) {
216            addFlattened(ffd.name());
217            functionDecls.add(ffd);
218        }
219       
220        public void addFRecordDecl(FRecordDecl frd) {
221            addFlattened(frd.name());
222            recordDecls.add(frd);
223        }
224       
225        public void addFEnumDecl(FEnumDecl fed) {
226            addFlattened(fed.name());
227            enumDecls.add(fed);
228        }
229       
230        public void addFDerivedType(FDerivedType fdt) {
231            addFlattened(fdt.name());
232            derivedTypes.add(fdt);
233        }
234
235        private void addFlattened(String name) {
236            flattenedNodes.add(name);
237        }
238       
239       
240        public FlatAnnotation flatAnnotation(String ... path) {
241            return fc.flatAnnotation(path);
242        }
243       
244        private int numComponents = 0;
245
246        public void countComponent() {
247            numComponents++;
248        }
249       
250        public int getComponentCount() {
251            return numComponents;
252        }
253       
254        public void contribute(InstNode n) {
255            n.contribute(this, fc);
256        }
257    }
258   
259    // refined in OptimicaFlattening
260    public void FClass.update(Flattener f) {
261        setFGlobalVariableList(f.getFGlobalVariables());
262        setFVariableList(f.getFVariables());
263        setFAbstractEquationList(f.getNormalEquations());
264        setFInitialEquationList(f.getInitialEquations());
265        setParameterEquationList(f.getParameterEquations());
266       
267        setFFunctionDeclList(f.getFFunctionDecls());
268        setFRecordDeclList(f.getFRecordDecls());
269        setFEnumDeclList(f.getFEnumDecls());
270        setFDerivedTypeList(f.getFDerivedTypes());
271       
272        numComponents = f.getComponentCount();
273    }
274
275    /**
276     * Delegate for adding extra flattening code to top-level model.
277     */
278   
279    class InstClassDecl {
280        private static final ArrayList<ExtraFlattener> extraFlatteners = new ArrayList<ExtraFlattener>();
281       
282        public static ExtraFlattener addExtraFlattener(ExtraFlattener ef) {
283            extraFlatteners.add(ef);
284            return ef;
285        }
286       
287        public static abstract class ExtraFlattener {
288            public abstract void flattenExtra(Flattener f, InstClassDecl icd);
289        }
290    }
291   
292    protected void InstClassDecl.flattenInstClassDeclExtra(Flattener f) {
293        for (ExtraFlattener ef : extraFlatteners) {
294            ef.flattenExtra(f, this);
295        }
296    }
297
298    /**
299     * Find functions, record and enumeration declarations that need to be flattened.
300     */
301    public void ASTNode.flattenUsedFuncsAndEnums(Flattener f) {
302        for (ASTNode n : this) 
303            n.flattenUsedFuncsAndEnums(f);
304    }
305
306    public void InstNode.flattenUsedFuncsAndEnums(Flattener f) {
307        getInstComponentDeclList().flattenUsedFuncsAndEnums(f);
308        getFAbstractEquationList().flattenUsedFuncsAndEnums(f);
309        getInstExtendsList().flattenUsedFuncsAndEnums(f);
310        for (InstModification im : totalMergedEnvironment()) 
311            im.flattenUsedFuncsAndEnums(f);
312        super.flattenUsedFuncsAndEnums(f);
313    }
314
315    public void InstComponentDecl.flattenUsedFuncsAndEnums(Flattener f) {
316        if (useInFlattening()) {
317            super.flattenUsedFuncsAndEnums(f);
318            if (isOperatorRecord() && isFlow())
319                type().matchOverloadedZero().flattenFunction(f);
320        }
321    }
322
323    @Override
324    public void InstClassDecl.flattenUsedFuncsAndEnums(Flattener f) {
325        super.flattenUsedFuncsAndEnums(f);
326        getInstGeneratedInners().flattenUsedFuncsAndEnums(f);
327    }
328
329    public void InstSimpleShortClassDecl.flattenUsedFuncsAndEnums(Flattener f) {
330        actualInstClass().flattenUsedFuncsAndEnums(f);
331    }
332
333    public void InstLibNode.flattenUsedFuncsAndEnums(Flattener f) {
334        actualInstClass().flattenUsedFuncsAndEnums(f);
335    }
336
337    public void FConnectClause.flattenUsedFuncsAndEnums(Flattener f) {
338        super.flattenUsedFuncsAndEnums(f);
339        getConnector1().myInstComponentDecl().flattenOverloadedOperatorsForFlow(f);
340        getConnector2().myInstComponentDecl().flattenOverloadedOperatorsForFlow(f);
341    }
342   
343    public void InstNode.flattenOverloadedOperatorsForFlow(Flattener f) {
344        for (InstComponentDecl icd : getInstComponentDecls())
345            icd.flattenOverloadedOperatorsForFlow(f);
346        for (InstExtends ie : getInstExtendss())
347            ie.flattenOverloadedOperatorsForFlow(f);
348    }
349
350    public void InstComponentDecl.flattenOverloadedOperatorsForFlow(Flattener f) {
351        if (useInFlattening()) {
352            if (isOperatorRecord() && isFlow())
353                type().flattenOverloadedOperatorsForFlow(f);
354            else
355                super.flattenOverloadedOperatorsForFlow(f);
356        }
357    }
358
359    public void FType.flattenOverloadedOperatorsForFlow(Flattener f) {}
360
361    public void FOperatorRecordType.flattenOverloadedOperatorsForFlow(Flattener f) {
362        matchOverloadedOperator(null, FExp.OP_NEG).flattenFunction(f);
363        matchOverloadedOperator(this, FExp.OP_SUB).flattenFunction(f);
364        matchOverloadedOperator(this, FExp.OP_ADD).flattenFunction(f);
365    }
366
367    public void InstValueModification.flattenUsedFuncsAndEnums(Flattener f) {
368        if (isFlattened(this)) {
369            getFExp().flattenUsedFuncsAndEnums(f);
370        }
371    }
372   
373    inh boolean InstValueModification.isFlattened(InstValueModification ivm);
374    eq InstModification.getChild().isFlattened(InstValueModification ivm)      = true;
375    eq InstAssignable.getChild().isFlattened(InstValueModification ivm)        = !inRecordDecl() && myInstValueMod() == ivm;
376    eq InstForIndex.getChild().isFlattened(InstValueModification ivm)          = true;
377    eq InstRecordConstructor.getChild().isFlattened(InstValueModification ivm) = true;
378    eq Root.getChild().isFlattened(InstValueModification ivm)                  = true;
379
380
381    public void InstFunctionCall.flattenUsedFuncsAndEnums(Flattener f) {
382        InstCallable target = myInstCallable();
383        target.flattenFunction(f);
384        getArgs().flattenUsedFuncsAndEnums(f);
385    }
386   
387    public void FBuiltInFunctionCall.flattenUsedFuncsAndEnums(Flattener f) {
388        for (ASTNode n : this) {
389            if (n != getOriginalArgs()) {
390                n.flattenUsedFuncsAndEnums(f);
391            }
392        }
393    }
394   
395    public void InstExternalObject.flattenUsedFuncsAndEnums(Flattener f) {
396        myDestructor().flattenFunction(f);
397        super.flattenUsedFuncsAndEnums(f);
398    }
399   
400    public void InstRecordConstructor.flattenUsedFuncsAndEnums(Flattener f) {
401        getRecord().flattenMyRecord(f);
402        getArgs().flattenUsedFuncsAndEnums(f);
403    }
404   
405    public void InstDefaultArgument.flattenUsedFuncsAndEnums(Flattener f) {
406        getFExp().flattenUsedFuncsAndEnums(f);
407    }
408
409    public void InstAccess.flattenUsedFuncsAndEnums(Flattener f) {
410        super.flattenUsedFuncsAndEnums(f);
411        if (myInstComponentDecl().isRecord() && myInstComponentDecl().isConstant() && !hasUnknownIndices() && isTopInstAccess()) 
412            ((InstAssignable) myInstComponentDecl()).flattenMyType(f);
413    }
414
415    public void FExp.flattenUsedFuncsAndEnums(Flattener f) {
416        super.flattenUsedFuncsAndEnums(f);
417        InstClassDecl oper = overloadedOperator(true);
418        boolean scalar = oper == null;
419        if (scalar)
420            oper = overloadedOperator(false);
421        if (oper != null) {
422            oper.flattenFunction(f);
423            int i = 0;
424            for (FExp arg : childFExps()) {
425                FType inType = oper.myInputs().get(i).type();
426                FType argType = arg.type();
427                if (scalar) 
428                    argType = argType.scalarType();
429                if (!inType.typeCompatible(argType, true))
430                    inType.matchOverloadedConstructor(argType).flattenFunction(f);
431                i++;
432            }
433        }
434    }
435
436    public void InstClassAccess.flattenUsedFuncsAndEnums(Flattener f) {
437        if (myInstClassDecl().extendsEnum())
438            myInstClassDecl().flattenEnum(f);
439    }
440
441    public void FReinit.flattenUsedFuncsAndEnums(Flattener f) {
442        containingInstNode().flattenStateSelect(f);
443        getFExp().flattenUsedFuncsAndEnums(f);
444    }
445
446    public void InstNode.flattenStateSelect(Flattener f) {
447        lookupInstClass("StateSelect").target().flattenEnum(f);
448    }
449
450    public void InstAccess.flattenMyRecord(Flattener f) {
451        myInstClassDecl().flattenRecord(f);
452    }
453   
454    // Flatten function if not already done
455    public void InstPartialFunction.flattenFunction(Flattener f) {
456        myInstClass().flattenFunction(f);
457    }
458   
459    public void InstClassDecl.flattenFunction(Flattener f) {}
460   
461    public void InstBaseClassDecl.flattenFunction(Flattener f) {
462        getInstRestriction().flattenFunction(f, this);
463    }
464   
465    public void InstSimpleShortClassDecl.flattenFunction(Flattener f) {
466        actualInstClass().flattenFunction(f);
467    }
468   
469    public void InstLibNode.flattenFunction(Flattener f) {
470        actualInstClass().flattenFunction(f);
471    }
472   
473    public void InstRestriction.flattenFunction(Flattener f, InstBaseClassDecl icd) {}
474   
475    public void InstFunction.flattenFunction(Flattener f, InstBaseClassDecl icd) {
476        icd.flattenThisFunction(f);
477    }
478
479    public void InstBaseClassDecl.flattenThisFunction(Flattener f) {
480        if (!f.isFlattened(this)) {
481            FFunctionDecl ffd = createFFunction(f, findFunctionExternal());
482            copyDerivativeAnnotations(f, ffd.annotation());
483            ffd.copyInlineAnnotation(findInlineAnnotationRoot());
484            ffd.smoothOrder(smoothOrder());
485            flattenUsedFuncsAndEnums(f);
486            ffd.updateRecordArraySizes();
487           
488            contribute(f, ffd);
489        }
490    }
491
492    private FFunctionDecl InstBaseClassDecl.createFFunctionDecl() {
493        FFunctionDecl res;
494        if (isConstructor()) {
495            res = new FConstructorDecl();
496        } else if (isDestructor()) {
497            res = new FDestructorDecl();
498        } else {
499            res = new FFunctionDecl();
500        }
501       
502        res.setFAlgorithm(new FAlgorithm(new List<FStatement>()));
503        return res;
504    }
505   
506    protected FFunctionDecl InstBaseClassDecl.createFFunction(Flattener f, InstExternal ie) {
507        FFunctionDecl ffd = createFFunctionDecl();
508        ffd.setFAccess(new FAccessString(qualifiedName()));
509        f.addFFunctionDecl(ffd);
510       
511        List<FFunctionVariable> vars = new List<FFunctionVariable>();
512        List<FStatement> stmts = new List<FStatement>();
513       
514       
515        flattenComponentsInFunction(f, vars, stmts, new HashSet<String>(), FUNC_AND_REC_MOD_LEVEL);
516       
517        if (ie != null) {
518            flattenExternal(f, stmts, ie);
519        } else {
520            FAlgorithm fab = findFunctionAlgorithm();
521            if (fab != null) {
522                FStatement.flattenFStatementList(f, fab.getFStatements(), stmts);
523            }
524        }
525       
526        int num = stmts.getNumChild();
527        if (num == 0 || !(stmts.getChild(num - 1) instanceof FReturnStmt)) 
528            stmts.addChild(new FReturnStmt());
529
530        ffd.setFFunctionVariableList(vars);
531        ffd.setFAlgorithm(new FAlgorithm(stmts));
532        return ffd;
533    }
534
535    public static final int InstNode.FUNC_AND_REC_MOD_LEVEL = 1000;
536
537    protected void InstBaseClassDecl.flattenExternal(Flattener f, List<FStatement> stmts, InstExternal ie) {
538        List<FStatement> stmts2 = new List<FStatement>();
539        ie.flatten(f, stmts2);
540        for (FStatement stmt : stmts2) {
541            stmts.addChild(stmt);
542        }
543    }
544   
545    private void InstBaseClassDecl.copyDerivativeAnnotations(Flattener f, AnnotationNode dest) {
546        copyDerivativeAnnotations(f, findDerivativeAnnotationRoot(), dest);
547    }
548
549    /**
550     * Utility method for finding an annotation tree that contains one of the
551     * provided subpaths. It will optionaly look in the external and the
552     * annotation of extending classes.
553     */
554    protected AnnotationNode InstClassDecl.findAnnotationRoot(boolean lookInExternal, boolean lookInExtends, String ... subPaths) {
555        return AnnotationNode.NO_ANNOTATION;
556    }
557
558    @Override
559    protected AnnotationNode InstBaseClassDecl.findAnnotationRoot(boolean lookInExternal, boolean lookInExtends, String ... subPaths) {
560        for (String subPath : subPaths) {
561            AnnotationNode node = annotation(subPath);
562            if (node.exists()) {
563                return annotation();
564            }
565        }
566        if (lookInExternal) {
567            InstExternal ie = findFunctionExternal();
568            if (ie != null) {
569                for (String subPath : subPaths) {
570                    AnnotationNode node = ie.annotation(subPath);
571                    if (node.exists()) {
572                        return ie.annotation();
573                    }
574                }
575            }
576        }
577        if (lookInExtends) {
578            for (InstExtends instExtends : getInstExtendss()) {
579                AnnotationNode node = instExtends.myInstClass().findAnnotationRoot(lookInExternal, lookInExtends, subPaths);
580                if (node.exists()) {
581                    return node;
582                }
583            }
584        }
585        return super.findAnnotationRoot(lookInExternal, lookInExtends, subPaths);
586    }
587
588    @Override
589    protected AnnotationNode InstSimpleShortClassDecl.findAnnotationRoot(boolean lookInExternal, boolean lookInExtends, String ... subPaths) {
590        return actualInstClass().findAnnotationRoot(lookInExternal, lookInExtends, subPaths);
591    }
592
593    @Override
594    protected AnnotationNode InstLibNode.findAnnotationRoot(boolean lookInExternal, boolean lookInExtends, String ... subPaths) {
595        return actualInstClass().findAnnotationRoot(lookInExternal, lookInExtends, subPaths);
596    }
597
598    protected AnnotationNode InstClassDecl.findDerivativeAnnotationRoot() {
599        return findAnnotationRoot(true, true, "derivative");
600    }
601
602    protected AnnotationNode InstClassDecl.findInlineAnnotationRoot() {
603        return findAnnotationRoot(true, true, "Inline", "LateInline", "InlineAfterIndexReduction");
604    }
605
606    protected AnnotationNode InstClassDecl.findSmoothOrderAnnotationRoot() {
607        return findAnnotationRoot(true, true, "smoothOrder");
608    }
609
610    private void InstBaseClassDecl.copyDerivativeAnnotations(Flattener f, AnnotationNode src, AnnotationNode dest) {
611        for (AnnotationNode derSrcNode : src.allFor("derivative")) {
612            InstClassDecl fd_decl = derSrcNode.lookupInstClass().target().actualInstClass();
613            AnnotationNode derDestNode = dest.addNode("derivative");
614            fd_decl.flattenFunction(f);
615            FExp derNameExp = new FAccessExp(new FAccessString(fd_decl.qualifiedName()));
616            derDestNode.setValue(derNameExp);
617            for (AnnotationNode attrSrcNode : derSrcNode) {
618                if ("noDerivative".equals(attrSrcNode.name()) && attrSrcNode.isAccess()) {
619                    AnnotationNode noDer = derDestNode.addNode("noDerivative");
620                    noDer.setValue(new FAccessExp(attrSrcNode.valueToString()));
621                } else if ("zeroDerivative".equals(attrSrcNode.name()) && attrSrcNode.isAccess()) {
622                    AnnotationNode zeroDer = derDestNode.addNode("zeroDerivative");
623                    zeroDer.setValue(new FAccessExp(attrSrcNode.valueToString()));
624                } else if ("order".equals(attrSrcNode.name()) && attrSrcNode.isIntegerValue()) {
625                    AnnotationNode order = derDestNode.addNode("order");
626                    order.setValue(new FIntegerLitExp(attrSrcNode.integer()));
627                }
628            }
629        }
630    }
631
632    public void FFunctionDecl.updateRecordArraySizes() {
633        for (FFunctionVariable ffv : getFFunctionVariables())
634            ffv.updateRecordArraySizes();
635    }
636   
637    public void FFunctionVariable.updateRecordArraySizes() {
638        // TODO: this should probably be in attributes as well
639        // TODO: if exp is access to input with unknown array sizes, handle that
640        if (hasBindingExp() && isRecord())
641            getType().updateRecordArraySizes(getBindingExp().type());
642    }
643   
644    public void FType.updateRecordArraySizes(FType from) {
645        setSize(from.getSize());
646    }
647   
648    public void FRecordType.updateRecordArraySizes(FType from) {
649        super.updateRecordArraySizes(from);
650        FRecordType rfrom = (FRecordType) from;
651        for (FRecordComponentType comp : getComponents())
652            comp.getFType().updateRecordArraySizes(componentType(comp.getName(), rfrom.getComponents()));
653    }
654   
655    public void FFunctionType.updateRecordArraySizes(FType from) {
656        super.updateRecordArraySizes(from);
657        FFunctionType rfrom = (FFunctionType) from;
658        for (FRecordComponentType comp : getInputs())
659            comp.getFType().updateRecordArraySizes(componentType(comp.getName(), rfrom.getInputs()));
660        for (FRecordComponentType comp : getOutputs())
661            comp.getFType().updateRecordArraySizes(componentType(comp.getName(), rfrom.getOutputs()));
662    }
663
664    public void InstNode.flattenComponentsInFunction(Flattener f, List<FFunctionVariable> vars, List<FStatement> stmts,
665            Set<String> added, int level) {
666        HashMap<InstNode,Integer> oldLevels = setModificationLevel(level);
667        for (InstExtends ie : getInstExtendss()) {
668            ie.flattenComponentsInFunction(f, vars, stmts, added, level + 1);
669        }
670        for (InstComponentDecl icd : getInstComponentDecls()) {
671            if (added.add(icd.name())) {
672                HashMap<InstNode,Integer> oldLevels2 = icd.setModificationLevel(level + 1);
673                icd.flattenInFunction(f, vars, stmts);
674                icd.flattenUsedFuncsAndEnums(f);
675                icd.clearModificationLevel(oldLevels2);
676            }
677        }
678        clearModificationLevel(oldLevels);
679    }
680
681    syn FAlgorithm InstNode.findFunctionAlgorithm() {
682        if (getNumFAbstractEquation() > 0) {
683            FAbstractEquation equ = getFAbstractEquation(0);
684            if (equ instanceof FAlgorithm)
685                return (FAlgorithm) equ;
686        } else {
687            for (InstExtends ie : getInstExtendss()) {
688                FAlgorithm tmp = ie.findFunctionAlgorithm();
689                if (tmp != null) 
690                    return tmp;
691            }
692        }
693        return null;
694    }
695   
696    syn InstExternal InstClassDecl.findFunctionExternal() {
697        for (InstExtends ie : getInstExtendss()) {
698            InstExternal tmp = ie.myInstClass().findFunctionExternal();
699            if (tmp != null) 
700                return tmp;
701        }
702        return null;
703    }
704    eq InstFullClassDecl.findFunctionExternal()        = 
705        hasInstExternal() ? getInstExternal() : super.findFunctionExternal();
706    eq InstSimpleShortClassDecl.findFunctionExternal() = actualInstClass().findFunctionExternal();
707    eq InstLibNode.findFunctionExternal()              = actualInstClass().findFunctionExternal();
708   
709    // Flatten record if not already done
710    public void InstClassDecl.flattenRecord(Flattener f) {}
711   
712    public void InstBaseClassDecl.flattenRecord(Flattener f) {
713        getInstRestriction().flattenRecord(f, this);
714    }
715   
716    public void InstRestriction.flattenRecord(Flattener f, InstBaseClassDecl icd) {}
717   
718    public void InstConnector.flattenRecord(Flattener f, InstBaseClassDecl icd) {
719        if (inheritedRestriction() != null)
720            inheritedRestriction().flattenRecord(f, icd);
721    }
722
723    public void InstMRecord.flattenRecord(Flattener f, InstBaseClassDecl icd) {
724        icd.flattenThisRecord(f);
725    }
726
727    public void InstNode.flattenThisRecord(Flattener f) {
728        String name = qualifiedTypeName();
729        if (!f.isFlattened(this)) {
730            FRecordDecl frd = new FRecordDecl();
731            frd.setFAccess(new FAccessString(name));
732           
733            Set<String> names = new HashSet<String>();
734            flattenComponentsInRecord(f, frd, names, FUNC_AND_REC_MOD_LEVEL);
735           
736            f.addFRecordDecl(frd);
737           
738            flattenUsedFuncsAndEnums(f);
739        }
740    }
741
742    public void InstNode.flattenComponentsInRecord(Flattener f, FRecordDecl frd, Set<String> names, int level) {
743        HashMap<InstNode,Integer> oldLevels = setModificationLevel(level);
744        for (InstExtends ie : getInstExtendss())
745            ie.flattenComponentsInRecord(f, frd, names, level + 1);
746        for (InstComponentDecl icd : getInstComponentDecls()) {
747            HashMap<InstNode,Integer> oldLevels2 = icd.setModificationLevel(level + 1);
748            icd.flattenInRecord(f, frd, names);
749            icd.clearModificationLevel(oldLevels2);
750        }
751        clearModificationLevel(oldLevels);
752    }
753
754    public void InstSimpleShortClassDecl.flattenComponentsInRecord(Flattener f, FRecordDecl frd, Set<String> names, int level) {
755        actualInstClass().flattenComponentsInRecord(f, frd, names, level);
756    }
757
758    public void InstLibNode.flattenComponentsInRecord(Flattener f, FRecordDecl frd, Set<String> names, int level) {
759        actualInstClass().flattenComponentsInRecord(f, frd, names, level);
760    }
761
762    public void InstExternal.flatten(Flattener f, List<FStatement> sl) {
763        getFAlgorithm().getFStatement(0).flatten(f, sl);
764    }
765   
766    syn nta FAlgorithm InstExternal.getFAlgorithm() {
767        FAlgorithm fab = new FAlgorithm(new List());
768        fab.addFStatement(createStmt());
769        return fab;
770    }
771
772    public FExternalStmt InstExternal.createStmt() {
773        InstClassDecl func = surroundingInstClass();
774        FExternalStmt stmt = new FExternalStmt();
775        SrcClassDecl scd = myTopSrcClassDecl();
776        stmt.setLibTopPackagePath(scd == null ? "" : scd.myLibRootPath().toAbsolutePath().toString()); // scd is null for builtins
777        stmt.setFExternalLanguage(hasFExternalLanguage() ? 
778                getFExternalLanguage().treeCopy() : 
779                new FCExternalLanguage());
780        stmt.extractLibrary(this);
781        contribute(stmt);
782        if (hasInstExternalCall()) {
783            InstExternalCall call = getInstExternalCall();
784            if (call.hasReturnVar()) {
785                stmt.setReturnVar(new InstAccessExp(call.getReturnVar().treeCopy()));
786            }
787            stmt.setName(call.getName());
788            for (FExp arg : call.getArgs()) {
789                stmt.addArg(arg.treeCopy());
790            }
791        } else {
792            boolean hasReturn = func.myOutputs().size() == 1 && 
793                    func.myOutputs().get(0).canBeExternalReturn(stmt.getFExternalLanguage());
794            if (hasReturn) {
795                stmt.setReturnVar(new InstAccessExp(new InstComponentAccess(func.myOutputs().get(0).name())));
796            }
797            stmt.setName(func.name());
798            for (InstComponentDecl arg : func.allInstComponentDecls()) {
799                if (!hasReturn || !arg.isOutput()) {
800                    arg.addExternalArg(stmt);
801                }
802            }
803        }
804        return stmt;
805    }
806   
807    public void InstComponentDecl.addExternalArg(FExternalStmt stmt) {}
808    public void InstAssignable.addExternalArg(FExternalStmt stmt) {
809        InstAccessExp access = new InstAccessExp(new InstComponentAccess(name()));
810        stmt.addArg(access);
811        for (int i = 0; i < ndims(); i++) {
812            stmt.addArg(new FSizeExp(access.treeCopy(), new Opt(new FIntegerLitExp(i + 1))));
813        }
814    }
815   
816    syn boolean InstComponentDecl.canBeExternalReturn(FExternalLanguage lang) = false;
817    eq InstAssignable.canBeExternalReturn(FExternalLanguage lang) = 
818        !isArray() && lang.canBeReturn(type());
819   
820    syn boolean FExternalLanguage.canBeReturn(FType type) = !type.isArray();
821    eq FFortran77ExternalLanguage.canBeReturn(FType type) = !type.isComposite() && !type.isString();
822   
823    public boolean FExternalStmt.flatten(Flattener f, List<FStatement> sl) {
824        List<FExp> args = new List<FExp>();
825        for (FExp arg : getArgs()) {
826            args.add(arg.flatten(f));
827        }
828        Opt<CommonAccessExp> ret = hasReturnVar() ? 
829                new Opt<>(getReturnVar().flatten(f).asCommonAccessExp()) : 
830                new Opt<CommonAccessExp>();
831               
832        FExternalStmt stmt = new FExternalStmt(getFExternalLanguage().treeCopy(), ret, getName(), args, getLibTopPackagePath(), new List<FAttribute>());
833        stmt.extractLibrary(this);
834        sl.add(stmt);
835        contribute(stmt);
836        return false;
837    }
838   
839    public void InstComponentDecl.flattenInFunction(Flattener f, List<FFunctionVariable> vars, List<FStatement> stmts) {}
840   
841    @Override
842    public void InstAssignable.flattenInFunction(Flattener f, List<FFunctionVariable> vars, List<FStatement> stmts) {
843        if (!flattenAsGlobalVariableFromFunction()) {
844            if (hasInstValueMod())
845                getBindingFExp().flattenUsedFuncsAndEnums(f);
846            FAccess access = getFAccess().treeCopy().removeFArraySubscripts();
847            FType type = type().flatten(f, this, !isInput());
848            CausalityConnectorPrefix io = myCausalityConnectorPrefix();
849           
850            vars.addChild(new FFunctionVariable(io.functionVisibility(), io, type, new Opt<FExp>(), access));
851           
852            if (isComposite()) {
853                addFInitArrayStmt(f, stmts, isInput(), expandedFAccessCalc(), new ForNames());
854            }
855            if (!isInput()) {
856                addBindingAssignments(f, stmts);
857            }
858            myInstClass().flattenRecord(f);
859        }
860    }
861   
862    public void InstComponentDecl.addFInitArrayStmt(Flattener f, List<FStatement> l, boolean input, FAccess access, ForNames names) {
863       
864    }
865   
866    public void InstAssignable.addFInitArrayStmt(Flattener f, List<FStatement> l, boolean input, FAccess access, ForNames names) {
867        if (isArray()) {
868            if (input) {
869                size().addSizeCheck(f, l, this, access);
870            } else {
871                FInitArrayStmt stmt = new FInitArrayStmt(new FAccessExp(access), false, new List<FExp>());
872                stmt.shouldBeSorted = true;
873                l.add(stmt);
874            }
875        }
876    }
877   
878    public void InstRecord.addFInitArrayStmt(Flattener f, List<FStatement> l, boolean input, FAccess access, ForNames names) {
879        super.addFInitArrayStmt(f, l, input, access, names);
880        if (input) {
881            if (isArray()) {
882                InstComponentDecl rec = scalar();
883                if (rec == null) {
884                    return;
885                }
886                names.addLayer(ndims());
887                names.fillLayer(null);
888                List<FStatement> ll = new List<FStatement>();
889                rec.addFInitArrayStmtCell(f, ll, input, access.copyAndAddFas(names.createFArraySubscripts()), names);
890                names.createForLoops(l, ll, access);
891                names.removeLayer();
892            } else {
893                addFInitArrayStmtCell(f, l, input, access, names);
894            }
895        }
896    }
897   
898    public void InstComponentDecl.addFInitArrayStmtCell(Flattener f, List<FStatement> l, boolean input, FAccess access, ForNames names) {
899        for (InstComponentDecl icd : allInstComponentDecls()) {
900            icd.addFInitArrayStmt(f, l, input, access.copyAndAppend(icd.name()), names);
901        }
902    }
903   
904    public void Size.addSizeCheck(Flattener f, List<FStatement> l, InstAssignable n, FAccess access) {
905        for (int i = 0; i < ndims(); i++) {
906            if (needSizeCheck(i)) {
907                String msg = "Mismatching sizes in function '" + n.surroundingInstClass().qualifiedName() +
908                        "', component '" + access.toString() + "', dimension '" + (i+1) + "'";
909                FAssert call = new FAssert(new FEqExp(flattenFExp(f, i), new FUnknownSizeExp(new FAccessExp(access.treeCopy()), i)), new FStringLitExp(msg), new Opt<FExp>());
910                FFunctionCallStmt stmt = new FFunctionCallStmt(new List<FFunctionCallLeft>(), call);
911                stmt.shouldBeSorted = true;
912                l.add(stmt);
913            }
914        }
915    }
916   
917    public boolean Size.needSizeCheck(int i) { return size[i] != UNKNOWN; }
918    public boolean MutableSize.needSizeCheck(int i) { return (exps[i] != null && !(exps[i] instanceof FColonSizeExp)) || super.needSizeCheck(i); }
919   
920    public void InstComponentDecl.addBindingAssignments(Flattener f, List<FStatement> l) {
921        for (InstComponentDecl icd : allInstComponentDecls()) {
922            icd.addBindingAssignments(f, l);
923        }
924    }
925   
926    public void InstAssignable.addBindingAssignments(Flattener f, List<FStatement> l) {
927        if (hasBindingFExp()) {
928            FAssignableExp left = setLocationOf(new FAccessExp(expandedFAccessCalc()));
929            FStatement stmt;
930            if (scalarizedAsFFunctionCallStmt()) {
931                List<FFunctionCallLeft> lefts = new List<FFunctionCallLeft>();
932                lefts.add(new FFunctionCallLeft(new Opt<FExp>(left)));
933                stmt = new FFunctionCallStmt(lefts, (FAbstractFunctionCall) getBindingFExp().flatten(f));
934            } else {
935                stmt = new FAssignStmt(left, getBindingFExp().flatten(f));
936            }
937            stmt.shouldBeSorted = true;
938            l.add(stmt);
939        } else {
940            super.addBindingAssignments(f, l);
941        }
942    }
943
944    syn FAccess InstAssignable.expandedFAccessCalc() = expandedFAccess().append(name());
945
946    inh FAccess InstComponentDecl.expandedFAccess();
947    eq InstClassDecl.getChild().expandedFAccess()          = new FAccessFull();
948    eq InstRecordConstructor.getChild().expandedFAccess()  = new FAccessFull();
949    eq InstComponentDecl.getChild().expandedFAccess()      = expandedFAccess();
950    eq InstArrayComponentDecl.getChild().expandedFAccess() = appendMyName(expandedFAccess());
951    eq InstAssignable.getChild().expandedFAccess() {
952        if (size().isUnknown()) {
953            return expandedFAccess().append(name(), size().flattenSubscript());
954        } else {
955            return expandedFAccess().append(name());
956        }
957    }
958
959    public class InstLookupResult<T extends InstNode> {
960        /**
961         * Check if lookup found a target that is not the same as the given one.
962         */
963        public boolean foundOther(T t) {
964            return successful() && target() != t;
965        }
966    }
967   
968    public FType FType.flatten(Flattener f, InstAssignable ia, boolean keepSizeExpressions) {
969        FType res = fullCopy();
970        res.setSize(getSize().flatten(f, res, keepSizeExpressions));
971        return res;
972    }
973   
974    @Override
975    public FType FPrimitiveType.flatten(Flattener f, InstAssignable ia, boolean keepSizeExpressions) {
976        FType res;
977        if(keepSizeExpressions && !getSize().variability().knownParameterOrLess()) {
978            MutableSize mutableSize = (MutableSize) getSize();
979            List<FExp> l = mutableSize.flattenExps(f);
980            if (l.getNumChild() > 0 && l.getNumChild() == mutableSize.ndims()) {
981                FPrimitiveType copy = fullCopy();
982                copy.setSize(Size.SCALAR);
983                res = new FArrayType(copy , l);
984            } else {
985                res = fullCopy();
986                res.setSize(getSize().flatten(f, res, keepSizeExpressions));
987            }
988        } else {
989            res = fullCopy();
990            res.setSize(getSize().flatten(f, res, keepSizeExpressions));
991        }
992        return res;
993    }
994   
995    public List<FExp> MutableSize.flattenExps(Flattener f) {
996        List<FExp> l = new List<FExp>();
997        for (int i = 0; i < exps.length; i++) {
998            if (shouldFlattenChild(i)) {
999                l.add(exps[i].flatten(f));
1000            }
1001        }
1002        return l;
1003    }
1004
1005    public boolean MutableSize.shouldFlattenChild(int i) {
1006        return exps[i] != null && !(exps[i] instanceof FColonSizeExp) && 
1007                (size[i] == Size.UNKNOWN || !exps[i].inFunction());
1008    }
1009
1010    public FRecordComponentType FRecordComponentType.flatten(Flattener f, InstAssignable ia, boolean keepSizeExpressions) {
1011        return new FRecordComponentType(getName(), getFType().flatten(f, ia, keepSizeExpressions));
1012    }
1013   
1014    @Override
1015    public FType FRecordType.flatten(Flattener f, InstAssignable ia, boolean keepSizeExpressions) {
1016        List<FRecordComponentType> comps = new List<FRecordComponentType>();
1017        for (FRecordComponentType frct : getComponents()) {
1018            comps.add(frct.flatten(f, ia, keepSizeExpressions));
1019        }
1020        FRecordType res = new FRecordType(getSize(), getName(), comps, getFClass());
1021        res.setSize(getSize().flatten(f, res, keepSizeExpressions));
1022        res.flattened = true;
1023        return res;
1024    }
1025   
1026    @Override
1027    public FType FFunctionType.flatten(Flattener f, InstAssignable ia, boolean keepSizeExpressions) {
1028        List<FRecordComponentType> inputs = new List<FRecordComponentType>();
1029        for (FRecordComponentType frct : getInputs()) {
1030            inputs.add(frct.flatten(f, ia, keepSizeExpressions));
1031        }
1032        List<FRecordComponentType> outputs = new List<FRecordComponentType>();
1033        for (FRecordComponentType frct : getOutputs()) {
1034            outputs.add(frct.flatten(f, ia, keepSizeExpressions));
1035        }
1036        FFunctionType res = new FFunctionType(getSize(), getName(), inputs, outputs, getFClass());
1037        res.setSize(getSize().flatten(f, res, keepSizeExpressions));
1038        res.flattened = true;
1039        return res;
1040    }
1041   
1042    @Override
1043    public FType FExternalObjectType.flatten(Flattener f, InstAssignable ia, boolean keepSizeExpressions) {
1044        FType res = new FExternalObjectType(getSize(), getName(), getConstructor().flatten(f), getDestructor().flatten(f));
1045        res.setSize(getSize().flatten(f, res, keepSizeExpressions));
1046        return res;
1047    }
1048   
1049    private boolean FRecordType.flattened = false;
1050    rewrite FRecordType {
1051        when (flattened) to FRecordType {
1052            setFClass(myFClass());
1053            flattened = false;
1054            return this;
1055        }
1056    }
1057   
1058    private boolean FFunctionType.flattened = false;
1059    rewrite FFunctionType {
1060        when (flattened) to FFunctionType {
1061            setFClass(myFClass());
1062            flattened = false;
1063            return this;
1064        }
1065    }
1066   
1067    public Size Size.flatten(Flattener f, ASTNode context, boolean keepSizeExpressions) {
1068        return this;
1069    }
1070   
1071    public MutableSize MutableSize.flatten(Flattener f, ASTNode context, boolean keepSizeExpressions) {
1072        MutableSize res = new MutableSize(size.length);
1073        System.arraycopy(size, 0, res.size, 0, size.length);
1074        if (keepSizeExpressions) {
1075            for (int i = 0; i < exps.length; i++) {
1076                if (shouldFlattenChild(i)) {
1077                    res.exps[i] = context.affixExpression(exps[i].flatten(f));
1078                }
1079            }
1080        }
1081        return res;
1082    }
1083   
1084    /**
1085     * Affix the given expression to the tree.
1086     *
1087     * Where supported, adds it to dynamicFExp(), otherwise throws UnsupportedOperationException.
1088     *
1089     * @return the expression, possibly rewritten
1090     */
1091    public FExp ASTNode.affixExpression(FExp exp) {
1092        throw new UnsupportedOperationException("Method affixExpression(FExp) not supported by class " + getClass().getSimpleName());
1093    }
1094   
1095    public FExp FExp.affixExpression(FExp exp) {
1096        return dynamicFExp(exp);
1097    }
1098   
1099    public FExp FFunctionCall.affixExpression(FExp exp) {
1100        // can't use dynamicExp(), since this node might not be in tree (InstFunctionCall.flatten())
1101        // TODO: if InstFunctionCall.flatten() is changed so that the size is flattened in a
1102        //       rewrite on FFunctionCall instead, then dynamicExp() can be used here
1103        exp.parent = this;
1104        return exp;
1105    }
1106   
1107    public FExp FType.affixExpression(FExp exp) {
1108        // TODO: need better way of including exp in tree
1109        exp.parent = this;
1110        return exp;
1111    }
1112
1113    public enum FlattenBindingExp {
1114        ALL, PARAMETER, NONE;
1115    }
1116
1117    syn boolean InstAssignable.shouldFlattenExp(FlattenBindingExp binding) = 
1118            (binding == FlattenBindingExp.ALL) || 
1119            (binding == FlattenBindingExp.PARAMETER && variability().parameterOrLess());
1120
1121    // Generic method for flattening
1122    public void ASTNode.flatten(Flattener f, FlattenBindingExp binding, int level) {
1123        for (ASTNode n : this) {
1124            n.flatten(f, binding, level);
1125        }
1126    }
1127
1128    public void InstNode.flatten(Flattener f, FlattenBindingExp binding, int level) {
1129        HashMap<InstNode,Integer> oldLevels = setModificationLevel(level);
1130        flattenEquations(f);
1131        getInstComponentDeclList().flatten(f, binding, level + 1);
1132        getInstExtendsList().flatten(f, binding, level + 1);
1133        f.contribute(this);
1134        clearModificationLevel(oldLevels);
1135    }
1136
1137    public void InstNode.flattenEquations(Flattener f) {
1138        for (FAbstractEquation ae : getFAbstractEquations()) 
1139            ae.flatten(f);
1140    }
1141
1142    /**
1143     * Check if this component is present in the model (i.e. not a disabled conditional
1144     * and not a non-selected duplicate).
1145     */
1146    syn boolean InstComponentDecl.isPresent() = !isDisabled() && !isDuplicate();
1147    eq InstArrayComponentDecl.isPresent()     = getIndex() > 0 && super.isPresent();
1148
1149    /**
1150     * Check if this component should be considered during flattening.
1151     */
1152    syn boolean InstComponentDecl.useInFlattening()    = isPresent() && !(isOuter() && !isInner());
1153
1154    public void InstComponentDecl.flatten(Flattener f, FlattenBindingExp binding, int level) {
1155        if (useInFlattening()) {
1156            super.flatten(f, binding, level);
1157            if (!isPrimitive() && !hasFArraySubscripts() && !isConnector()) {
1158                f.countComponent();
1159            }
1160        }
1161    }
1162
1163    public void InstExpandableConnectorDecl.flatten(Flattener f, FlattenBindingExp binding, int level) {
1164        super.flatten(f, FlattenBindingExp.PARAMETER, level);
1165    }
1166
1167    public void InstClassDecl.buildConnectionSets(FClass fc) {
1168        beginStep("buildConnectionSets()");
1169        ConnectionSetManager csm = fc.getConnectionSetManager();
1170        buildConnectionSets(new FAccessEmpty(), csm, true);
1171        csm.buildOverconstrainedConnectionTrees();
1172        csm.elaborateExpandableConnectors();
1173        endStep("buildConnectionSets()");
1174    }
1175   
1176    public void InstComponentDecl.flattenInRecord(Flattener f, FRecordDecl frd, Set<String> names) {}
1177   
1178    public boolean FVariable.modifiableInRecord = true;
1179    public void InstAssignable.flattenInRecord(Flattener f, FRecordDecl frd, Set<String> names) {
1180        if (names.add(name())) {
1181            FAccess access;
1182            if (isArray()) {
1183                List<FAccessPart> l = new List<FAccessPart>();
1184                l.add(new FAccessPartArray(name(), size().flattenFArraySubscripts(f)));
1185                access = new FAccessFull(l);
1186            } else {
1187                access = new FAccessString(name());
1188            }
1189            FVariable fv = createFVariable(f, access, FlattenBindingExp.NONE, false);
1190            fv.modifiableInRecord = isModifiable();
1191            frd.addFVariableNoTransform(fv);
1192            flattenMyType(f);
1193        }
1194    }
1195   
1196    public FArraySubscripts Size.flattenFArraySubscripts(Flattener f) {
1197        if (ndims() > 0) {
1198            List<FSubscript> l = new List<FSubscript>();
1199            for (int i = 0; i < ndims(); i++) {
1200                l.add(flattenFSubscript(f, i));
1201            }
1202            return FArraySubscripts.createFArraySubscripts(l);
1203        }
1204        return null;
1205    }
1206   
1207    public FSubscript Size.flattenFSubscript(Flattener f, int i) {
1208        int s = get(i);
1209        return s == Size.UNKNOWN ? new FColonSubscript() : new FIntegerSubscript(s);
1210    }
1211   
1212    public FSubscript MutableSize.flattenFSubscript(Flattener f, int i) {
1213        if (exps[i] == null || exps[i] instanceof FColonSizeExp ||
1214                exps[i].variability().knownParameterOrLess()) {
1215            return super.flattenFSubscript(f, i);
1216        }
1217        return exps[i].flatten(f).createFSubscript();
1218    }
1219
1220    public void InstAssignable.flatten(Flattener f, FlattenBindingExp binding, int level) {
1221        flatten(f, binding, level, false);
1222    }
1223
1224    public void InstAssignable.flatten(Flattener f, FlattenBindingExp binding, int level, boolean global) {
1225        if (useInFlattening() && (global || !flattenAsGlobalVariable())) {
1226            if (hasBindingFExp()) {
1227                getBindingFExp().flattenAssertExternal(f);
1228            }
1229            HashMap<InstNode,Integer> oldLevels = setModificationLevel(level);
1230            FAccess name;
1231            if (global) {
1232                name = getFAccess().copyAndPrepend(surroundingInstClass().qualifiedName()).copyAndAddFas(size().flattenFArraySubscripts(f));
1233            } else {
1234                name = getFAccess().copyAndAddFas(size().flattenFArraySubscripts(f));
1235            }
1236            FVariable fv = createFVariable(f, name, binding, global);
1237            if (global) {
1238                f.addGlobalVariable(fv);
1239            } else {
1240                f.addFVariable(fv);
1241            }
1242            if (fv.getCausalityConnectorPrefix().isStream() && useCausalPorts()) {
1243                FVariable inStream = fv.treeCopy();
1244                FAccess inStreamAccess = createInStreamAccess(inStream.getFAccess());
1245                inStream.setFAccess(inStreamAccess);
1246                inStream.setCausalityConnectorPrefix(CausalityConnectorPrefix.INSTREAM);
1247                fv.annotation().vendorNode().forPath("internal/instream").setValue(new FStringLitExp(inStreamAccess.name()));
1248                f.addFVariable(inStream);
1249            }
1250            flattenMyType(f);
1251            clearModificationLevel(oldLevels);
1252        }
1253    }
1254   
1255    inh FAccess InstAssignable.createInStreamAccess(FAccess streamAccess);
1256    eq InstClassDecl.getChild().createInStreamAccess(FAccess streamAccess) {
1257        FAccess result = streamAccess.copyAndAddSuffix("__instream_");
1258        int i = 2;
1259        while (componentExists(new QualifiedName(result.name()))) {
1260            result = streamAccess.copyAndAddSuffix("__instream_" + i);
1261            i++;
1262        }
1263        return result;
1264    }
1265   
1266    public void ASTNode.flattenAssertExternal(Flattener f) {
1267        for (ASTNode n : this) {
1268            n.flattenAssertExternal(f);
1269        }
1270    }
1271   
1272    public void InstFunctionCall.flattenAssertExternal(Flattener f) {
1273        if (variability().knownParameterOrLess() && myInstCallable().isExternalFunction()) {
1274            try {
1275                String msg = "Error " + runtimeErrorString("Structural parameter external function call '"
1276                        + name() + "' did not evaluate to same result as during compilation");
1277                CValue cval = ceval();
1278                if (cval.hasBuildLiteral()) {
1279                    f.addParameterEquation(new FFunctionCallEquation(new List<FFunctionCallLeft>(), 
1280                            new FAssert(new FEqExp(cval.buildLiteral(), flatten(f)),
1281                                    new FStringLitExp(msg), new Opt<FExp>())));
1282                }
1283            } catch (ConstantEvaluationException e) {}
1284        }
1285    }
1286   
1287    public String ASTNode.runtimeErrorString(String msg) {
1288        StringBuilder sb = new StringBuilder();
1289        sb.append("Error ");
1290        errorLocation(sb);
1291        sb.append("': ");
1292        sb.append(msg);
1293        return sb.toString().replace("\\", "\\\\");
1294    }
1295   
1296    public String ASTNode.errorLocation() {
1297        StringBuilder sb = new StringBuilder();
1298        errorLocation(sb);
1299        return sb.toString();
1300    }
1301   
1302    public void ASTNode.errorLocation(StringBuilder sb) {
1303        sb.append("at line ");
1304        sb.append(beginLineRecursive());
1305        sb.append(", column ");
1306        sb.append(beginColumnRecursive());
1307        sb.append(", in file '");
1308        sb.append(fileName());
1309        sb.append("'");
1310    }
1311   
1312    syn boolean ASTNode.externalDependency() {
1313        for (ASTNode n : this) {
1314            if (n.externalDependency()) {
1315                return true;
1316            }
1317        }
1318        return false;
1319    }
1320    eq InstFunctionCall.externalDependency() =  ((InstNode)myInstCallable()).externalDependency();
1321   
1322    syn lazy boolean InstFullClassDecl.externalDependency() = hasInstExternal() || super.externalDependency();
1323   
1324   
1325    public abstract void InstAssignable.flattenMyType(Flattener f);
1326
1327    public void InstPrimitive.flattenMyType(Flattener f) {
1328        myInstClass().addFDerivedType(f);
1329        flattenUsedFuncsAndEnums(f);
1330    }
1331
1332    public void InstEnum.flattenMyType(Flattener f) {
1333        myInstClass().flattenEnum(f);
1334        flattenUsedFuncsAndEnums(f);
1335    }
1336
1337    public void InstExternalObject.flattenMyType(Flattener f) {
1338        myInstClass().addFDerivedType(f);
1339        flattenUsedFuncsAndEnums(f);
1340    }
1341
1342    public void InstPartialFunction.flattenMyType(Flattener f) {
1343        throw new UnsupportedOperationException("Partial function component only allowed in functions");
1344    }
1345
1346    public void InstRecord.flattenMyType(Flattener f) {
1347        if (flattenRedeclaredType()) {
1348            InstComponentDecl rec = scalar();
1349            if (rec != null) {
1350                rec.flattenThisRecord(f);
1351            }
1352        } else {
1353            myInstClass().flattenRecord(f);
1354        }
1355    }
1356
1357    syn InstComponentDecl InstComponentDecl.scalar() {
1358        InstComponentDecl rec = this;
1359        for (int i = 0; i < ndims(); i++) {
1360            if (rec.getNumInstComponentDecl() == 0) {
1361                return null;
1362            } else {
1363                rec = rec.getInstComponentDecl(0);
1364            }
1365        }
1366        return rec;
1367    }
1368
1369    syn String InstNode.qualifiedTypeName() = qualifiedName();
1370   
1371    eq InstArrayComponentDecl.qualifiedTypeName(){
1372        if (flattenRedeclaredType()) {
1373            return surroundingInstClass().qualifiedName() + ":" + getFAccess().name();
1374        } else {
1375            return myInstClass().qualifiedName();
1376        }
1377    }
1378   
1379    eq InstComponentDecl.qualifiedTypeName() {
1380        if (flattenRedeclaredType()) {
1381            return surroundingInstClass().qualifiedName() + ":" + qualifiedName();
1382        } else {
1383            return myInstClass().qualifiedName();
1384        }
1385    }
1386   
1387    syn boolean InstComponentDecl.flattenRedeclaredType() = InstNode.containsRedeclared(this);
1388   
1389    syn boolean InstNode.containsRedeclared() = InstNode.containsRedeclared(this);
1390    public static boolean InstNode.containsRedeclared(InstNode in) {
1391        for (InstComponentDecl icd : in.getInstComponentDecls()) {
1392            if (icd.containsRedeclared()) {
1393                return true;
1394            }
1395        }
1396        for (InstClassDecl icd : in.getInstClassDecls()) {
1397            if (icd.containsRedeclared()) {
1398                return true;
1399            }
1400        }
1401        return false;
1402    }
1403   
1404    eq InstReplacingComposite.containsRedeclared() = true;
1405    eq InstReplacingRecord.containsRedeclared() = true;
1406    eq InstReplacingPrimitive.containsRedeclared() = true;
1407   
1408    eq InstClassDecl.containsRedeclared() = false;
1409    eq InstReplacingFullClassDecl.containsRedeclared() = true;
1410    eq InstReplacingShortClassDecl.containsRedeclared() = true;
1411    eq InstReplacingSimpleShortClassDecl.containsRedeclared() = true;
1412
1413    /*
1414     * Flattening of string comments.
1415     */
1416
1417    private static final char[][] SrcStringComment.ESCAPE_CHARS = {
1418        {'b', '\b'}, {'\"', '\"'}, {'f', '\f'}, {'n', '\n'}, {'r', '\r'}, {'t', '\t'}, { '\'', '\''}
1419    };
1420    private static final Map<Character, Character> SrcStringComment.ESCAPE_MAP = initializeEscapeMap();
1421    private static final char SrcStringComment.BACKSLASH = '\\';
1422
1423    /**
1424     * Creates a {@link Map} instance mapping all the pairs in {@code ESCAPE_CHARS}.
1425     * <p>
1426     * The first character in each pair of {@code ESCAPE_CHARS} is a key to the value,
1427     * i.e. the second character in the pair.
1428     */ 
1429    private static final Map<Character, Character> SrcStringComment.initializeEscapeMap() {
1430        Map<Character, Character> map = new HashMap<Character, Character>();
1431        for (char[] pair : ESCAPE_CHARS) {
1432            map.put(pair[0], pair[1]);
1433        }
1434        return Collections.<Character, Character> unmodifiableMap(map);
1435    }
1436
1437    /**
1438     * Flattens this comment, removing all escape sequences and replacing them with the corresponding character.
1439     * <p>
1440     * Note that this method also removes stray backslashes, or double backslashes.
1441     *
1442     * @return
1443     *          a {@link FStringComment} instance (a comment node in the flat tree).
1444     */
1445    public FStringComment SrcStringComment.flatten() {
1446        String comment = getComment();
1447        StringBuilder escapedComment = new StringBuilder();
1448        int length = comment.length();
1449
1450        for (int i = 0; i < length; ++i) {
1451            char c = comment.charAt(i);
1452
1453            if (c == BACKSLASH) {
1454                if (++i < length) {
1455                    char c2 = comment.charAt(i);
1456                    if (ESCAPE_MAP.containsKey(c2)) {
1457                        c2 = ESCAPE_MAP.get(c2);
1458                    } else if (c2 == BACKSLASH) {
1459                        continue;
1460                    }
1461                    escapedComment.append(c2);
1462                }
1463            } else {
1464                escapedComment.append(c);
1465            }
1466        }
1467        return new FStringComment(escapedComment.toString().replaceAll("\\\\", ""));
1468    }
1469
1470    public String SrcStringComment.getComment() {
1471        return getSrcExp().concatStringLit();
1472    }
1473
1474    public String ASTNode.concatStringLit() {
1475        StringBuilder sb = new StringBuilder();
1476        concatStringLit(sb);
1477        return sb.toString();
1478    }
1479
1480    public void ASTNode.concatStringLit(StringBuilder sb) {
1481        for(ASTNode child : children) {
1482            child.concatStringLit(sb);
1483        }
1484    }
1485
1486    @Override
1487    public void SrcStringLitExp.concatStringLit(StringBuilder sb) {
1488        sb.append(getSTRING());
1489    }
1490
1491    public FEnumLiteral InstEnumLiteral.createFEnumLiteral() {
1492        FEnumLiteral e = new FEnumLiteral(new FAccessString(name()), new Opt());
1493        SrcStringComment comment = myStringComment();
1494        if (comment != null) {
1495            e.setFStringComment(comment.flatten());
1496        }
1497        return e;
1498    }
1499
1500    public void InstClassDecl.flattenEnum(Flattener f) {
1501        if (!f.isFlattened(this)) {
1502            // Flatten all InstEnums corresponding to FEnumLiterals
1503            FEnumLiteralList l = new FEnumLiteralList();
1504            for (InstEnumLiteral ie : enumLiterals()) 
1505                l.addFEnumLiteral(ie.createFEnumLiteral());
1506            FIdDecl id = new FIdDecl(new FAccessString(qualifiedName()));
1507            FEnumDecl ed = new FEnumDecl(id, l, new Opt());
1508            SrcStringComment comment = myStringComment();
1509            if (comment != null) {
1510                ed.setFStringComment(comment.flatten());
1511            }
1512            addFDerivedType(f);
1513            f.addFEnumDecl(ed); 
1514        }
1515    }
1516   
1517    public void InstSimpleShortClassDecl.flattenEnum(Flattener f) {
1518        actualInstClass().flattenEnum(f);
1519    }
1520   
1521    public void InstLibNode.flattenEnum(Flattener f) {
1522        actualInstClass().flattenEnum(f);
1523    }
1524
1525    public FVariable InstAssignable.createEmptyFGlobalVariable(Flattener f) {
1526        FGlobalVariable res = new FGlobalVariable();
1527        res.setFType(type().flatten(f, this, false));
1528        return res;
1529    }
1530   
1531    public abstract FVariable InstAssignable.createEmptyFVariable();
1532   
1533    public FVariable InstPrimitive.createEmptyFVariable() {
1534        if (isReal()) {
1535            return new FRealVariable();
1536        } else if (isInteger()) {
1537            return new FIntegerVariable();
1538        } else if (isBoolean()) {
1539            return new FBooleanVariable();
1540        } else if (isString()) {
1541            return new FStringVariable();
1542        } else if (isEnum()) {
1543            FEnumVariable fv = new FEnumVariable();
1544            fv.setEnum(new FAccessString(myInstClass().actualInstClass().qualifiedName()));
1545            return fv;
1546        } else {
1547            throw new UnsupportedOperationException("InstPrimitive without type");
1548        }
1549    }
1550
1551    public FVariable InstRecord.createEmptyFVariable() {
1552        FRecordVariable rec = new FRecordVariable();
1553        rec.setRecord(new FRecordAccess(qualifiedTypeName()));
1554        return rec;
1555    }
1556   
1557    public FVariable InstPartialFunction.createEmptyFVariable() {
1558        throw new UnsupportedOperationException("Partial function component only allowed in functions");
1559    }
1560   
1561    public FVariable InstExternalObject.createEmptyFVariable() {
1562        FExternalObjectVariable exo = new FExternalObjectVariable();
1563        exo.setConstructor(new FAccessString(myConstructor().qualifiedName()));
1564        return exo;
1565    }
1566   
1567    public void InstNode.addAttributes(Flattener f, List<FAttribute> attr, Environment env) {
1568        addAttributes(f, attr, env, AttributeExpRetriever.DEFAULT, true);
1569    }
1570   
1571    public void InstNode.addAttributes(Flattener f,
1572            List<FAttribute> attr, Environment env, AttributeExpRetriever aer, boolean cls) {
1573        for (InstModification im : env) 
1574            im.collectAttributes(f, attr, aer, cls);
1575    }
1576   
1577    public void InstComponentDecl.addAttributesToFV(Flattener f, List<FAttribute> attr, Stack<Integer> indexStack,
1578            FlattenBindingExp binding, boolean isBound) {
1579        if (isArray()) {
1580            int i = 0;
1581            for (InstComponentDecl icd : allInstComponentDecls()) {
1582                indexStack.push(i++);
1583                icd.addAttributesToFV(f, attr, indexStack, binding, isBound);
1584                indexStack.pop();
1585            }
1586        } else {
1587            for (InstComponentDecl icd : allInstComponentDecls()) {
1588                if (icd.useInFlattening()) {
1589                    icd.generateAdditionalAttributes(f, attr, indexStack, binding, isBound);
1590                }
1591            }
1592        }
1593    }
1594   
1595    @Override
1596    public void InstAssignable.addAttributesToFV(Flattener f, List<FAttribute> attr, Stack<Integer> indexStack,
1597            FlattenBindingExp binding, boolean isBound) {
1598        if (!variability().knownParameterOrLess()) {
1599            AttributeExpRetriever mut = new AttributeExpRetriever() {
1600                public FExp retrieve(InstValueModification im, boolean isEach) {
1601                    FExp exp = super.retrieve(im, isEach);
1602                    InstNode decl = im.myInstNode();
1603                    InstNode ancestor = InstAssignable.this.matchingAncestor(decl);
1604                    return (isEach || decl == InstAssignable.this || !exp.isArray()) ? 
1605                            exp : exp.dynamicFExp(splitBindingFExp(exp, ancestor, ndims()));
1606                }
1607            };
1608            addAttributes(f, attr, totalMergedEnvironment(), mut, false);
1609        }
1610        super.addAttributesToFV(f, attr, indexStack, binding, isBound);
1611    }
1612   
1613    public void InstComponentDecl.generateAdditionalAttributes(Flattener f, List<FAttribute> attr, Stack<Integer> indexStack,
1614            FlattenBindingExp binding, boolean isBound) {
1615       
1616    }
1617   
1618    @Override
1619    public void InstAssignable.generateAdditionalAttributes(Flattener f, List<FAttribute> attr, Stack<Integer> indexStack,
1620            FlattenBindingExp binding, boolean isBound) {
1621        FAttribute a = findMatching(attr, name());
1622        boolean canBind = hasBindingFExp() || variability().knownParameterOrLess();
1623        List<FAttribute> list = new List<FAttribute>();
1624        if (a != null) {
1625            list.addAll(a.getFAttributes());
1626        }
1627        boolean flattenBinding = shouldFlattenExp(binding);
1628        if (flattenBinding && !isConstant() && declaredSizeCalc().isUnknownNoEval()) {
1629            FInternalAttribute ia = (FInternalAttribute)findMatching(list, "size()");
1630            if (ia == null) {
1631                ia = new FInternalAttribute(FAttribute.SIZE, new FArray(new List<FExp>()));
1632                list.add(ia);
1633            }
1634            ia.setValue(size().createFExp().addInDim(indexStack, 0, (FArray)ia.getValue()));
1635        }
1636        if (flattenBinding) {
1637            HashMap<InstNode,Integer> m = setModificationLevel(FUNC_AND_REC_MOD_LEVEL+1);
1638            addAttributesToFV(f, list, indexStack, binding, isBound || canBind);
1639            clearModificationLevel(m);
1640        }
1641        if (a == null && (list.getNumChild() > 0 || (!isBound && canBind))) {
1642            a = new FAttribute(getClassName().flatten(f), 
1643                    new FIdDecl(new FAccessString(name())), 
1644                    new Opt(), true, 0, new Opt(), new Opt(), list);
1645            attr.add(a);
1646        } else if (a != null) {
1647            a.setFAttributeList(list);
1648        }
1649       
1650        if (!isBound && canBind) {
1651            a.setValue(flattenBindingFExp(f).addInDim(indexStack, 0, (FArray)a.getValue()));
1652        }
1653    }
1654   
1655    public FExp FExp.addInDim(Stack<Integer> s, int d, FArray arr) {
1656        if (d == s.size()) {
1657            return this;
1658        } else {
1659            if (arr == null) {
1660                arr = new FArray();
1661            }
1662            int i = s.get(d);
1663            List<FExp> l = arr.getFExpListNoTransform();
1664            if (i < l.getNumChildNoTransform()) {
1665                l.setChild(addInDim(s, d+1, (FArray)l.getChildNoTransform(i)), i);
1666            } else {
1667                arr.addFExpNoTransform(addInDim(s, d+1, null));
1668            }
1669            return arr;
1670        }
1671    }
1672   
1673    public void InstClassDecl.addFDerivedType(Flattener f) {
1674        if (!f.isFlattened(this) && (extendsPrimitive() || isExternalObject())) {
1675            List<FAttribute> attr = new List<FAttribute>();
1676            addAttributes(f, attr, totalMergedEnvironment());
1677            FType baseType = primitiveScalarType().fullCopy();
1678            f.addFDerivedType(new FDerivedType(qualifiedName(), baseType, attr));
1679        }
1680    }
1681   
1682    public void InstSimpleShortClassDecl.addFDerivedType(Flattener f) {
1683        actualInstClass().addFDerivedType(f);
1684    }
1685   
1686    public void InstLibNode.addFDerivedType(Flattener f) {
1687        actualInstClass().addFDerivedType(f);
1688    }
1689
1690    public FVariable InstAssignable.createFVariable(Flattener f) {
1691        return createFVariable(f, getFAccess(), FlattenBindingExp.ALL, false);
1692    }
1693
1694    public FVariable InstAssignable.createFVariable(Flattener f, FAccess name, FlattenBindingExp binding, boolean global) {
1695        FVariable fv = global ? createEmptyFGlobalVariable(f) : createEmptyFVariable();
1696        fv.setVisibilityType(createVisibilityType());
1697        fv.setTypePrefixVariability(variability());
1698        fv.setCausalityConnectorPrefix(myCausalityConnectorPrefix());
1699       
1700        if (myInstClass().extendsPrimitive()) {
1701            fv.setDerivedType(myInstClass().actualInstClass().qualifiedName());
1702        }
1703       
1704        boolean flattenBinding = shouldFlattenExp(binding);
1705        List<FAttribute> attrs = new List<FAttribute>();
1706        if (!inRecordDecl()) {
1707            attrs.addAll(fv.getFAttributes());
1708            addAttributesToFV(f, attrs, new Stack<Integer>(), binding,
1709                    !flattenBinding || hasBindingFExp() || variability().knownParameterOrLess());
1710        }
1711        fv.setFAttributeList(attrs);
1712        if (flattenBinding) {
1713            FExp e = flattenBindingFExp(f);
1714            if (e != null)
1715                fv.setBindingExp(e);
1716        }
1717       
1718        SrcStringComment comment = myStringComment();
1719        if (comment != null) {
1720            fv.setFStringComment(comment.flatten());
1721        }
1722       
1723        fv.setFAccess(name);
1724        fv.setLocation(this);
1725       
1726        contribute(f, fv);
1727       
1728        return fv;
1729    }
1730
1731    public CausalityConnectorPrefix InstAssignable.myCausalityConnectorPrefix() {
1732        if (!isTopLevelCausalOrConnector()) {
1733            return CausalityConnectorPrefix.NONE;
1734        }
1735        if (isConnectorVariable()) {
1736            if (isInput()) {
1737                return CausalityConnectorPrefix.INPUT;
1738            } else if (isOutput()) {
1739                return CausalityConnectorPrefix.OUTPUT;
1740            } else if (isFlow()) {
1741                return CausalityConnectorPrefix.FLOW;
1742            } else if (isStream()) {
1743                return CausalityConnectorPrefix.STREAM;
1744            } else if (!variability().parameterOrLess()) {
1745                return CausalityConnectorPrefix.POTENTIAL;
1746            } else {
1747                return CausalityConnectorPrefix.NONE;
1748            }
1749        } else {
1750            if (isInput()) {
1751                return CausalityConnectorPrefix.INPUT;
1752            } else if (isOutput()) {
1753                return CausalityConnectorPrefix.OUTPUT;
1754            } else {
1755                return CausalityConnectorPrefix.NONE;
1756            }
1757        }
1758    }
1759
1760    public VisibilityType InstAssignable.createVisibilityType() {
1761        if (inExpandableConnector()) {
1762            return VisibilityType.EXPANDABLE;
1763        } else if (isPublicVar()) {
1764            return VisibilityType.PUBLIC;
1765        } else {
1766            return VisibilityType.PROTECTED;
1767        }
1768    }
1769
1770    /**
1771     * Retrieve the binding expression of an InstAssignable node.
1772     *
1773     * Always null for components that are not assignable.
1774     */
1775    syn FExp InstComponentDecl.myBindingInstExp() = null;
1776    eq InstAssignable.myBindingInstExp()          = hasInstValueMod() ? myInstValueMod().getFExp() : null;
1777
1778    /**
1779     * Check if this component has a binding expression.
1780     *
1781     * Always false for components that are not assignable.
1782     */
1783    syn boolean InstComponentDecl.hasBindingFExp() = false;
1784    eq InstAssignable.hasBindingFExp()             = getBindingFExp() != null;
1785
1786    /**
1787     * Retrieve the part of the binding expression that applies to this InstAssignable.
1788     */
1789    syn FExp InstComponentDecl.getBindingFExp() = null;
1790    syn lazy FExp InstAssignable.getBindingFExp() {
1791        //log.debug("In file: " + fileName() + " at line: " + beginLine() + ": " + prettyPrint(""));
1792        FExp exp = parentBindingFExp();
1793        if (exp != null) {
1794            exp = exp.component(name());
1795        } else if (hasInstValueMod()) {
1796            InstValueModification im = myInstValueMod();
1797            exp = im.getFExp();
1798            if (ndims() < exp.ndims()) {
1799                if (exp.size().isEmpty()) {
1800                    exp = null;
1801                } else {
1802                    InstNode decl = im.myInstNode();
1803                    decl = matchingAncestor(decl);
1804                    exp = exp.dynamicFExp(splitBindingFExp(exp, decl, ndims()));
1805                }
1806            }
1807        }
1808        return exp;
1809    }
1810   
1811    inh FExp InstComponentDecl.parentBindingFExp();
1812    eq Root.getChild().parentBindingFExp()                   = null;
1813    eq InstClassDecl.getChild().parentBindingFExp()          = null;
1814    eq FExp.getChild().parentBindingFExp()                   = null;
1815    eq InstComponentDecl.getChild().parentBindingFExp()      = null;
1816    eq InstAssignable.getChild().parentBindingFExp()         = getBindingFExp();
1817    eq InstArrayComponentDecl.getChild().parentBindingFExp() {
1818        FExp exp = parentBindingFExp();
1819        return exp != null && getIndex() > 0 ? exp.dynamicFExp(exp.splitArrayExp(getIndex())) : exp;
1820    }
1821   
1822    public FExp InstAssignable.flattenBindingFExp(Flattener f) {
1823        try {
1824            if (variability().knownParameterOrLess()) {
1825                CValue cval = ceval();
1826                if (cval.hasBuildLiteral()) {
1827                    FExp t = dynamicFExp(cval.buildInstLiteral());
1828                    t.flattenUsedFuncsAndEnums(f);
1829                    clearDynamicFExp();
1830                    return cval.buildLiteral();
1831                }
1832            }
1833        } catch (ConstantEvaluationException e) {}
1834        if (hasBindingFExp()) {
1835            InstValueModification im = myInstValueMod();
1836            return getBindingFExp().flatten(f);
1837        }
1838        return null;
1839    }
1840       
1841   
1842    /**
1843     * Extract the part of a binding array expression that refers to this primitive or record.
1844     *
1845     * Will not create new nodes unless necessary.
1846     *
1847     * @param fe    the expression to split
1848     * @param node  the node where the binding expression was declared
1849     * @param dims  the expected number of dimensions of the resulting expression
1850     */
1851    inh FExp InstNode.splitBindingFExp(FExp fe, InstNode node, int dims);
1852    eq InstClassDecl.getChild().splitBindingFExp(FExp fe, InstNode node, int dims) = fe;
1853    eq InstRoot.getChild().splitBindingFExp(FExp fe, InstNode node, int dims)      = fe;
1854    eq Root.getChild().splitBindingFExp(FExp fe, InstNode node, int dims)          = fe;
1855    eq InstNode.getChild().splitBindingFExp(FExp fe, InstNode node, int dims)      =
1856        (node == this) ? fe : splitBindingFExp(fe, node, dims);
1857    eq InstArrayComponentDecl.getChild().splitBindingFExp(FExp fe, InstNode node, int dims) =
1858        (node == this || fe.ndims() <= dims) ? fe : 
1859            fe.dynamicFExp(splitBindingFExp(fe, node, dims + 1)).splitArrayExp(getIndex());
1860    eq InstShortClassDecl.getChild().splitBindingFExp(FExp fe, InstNode node, int dims) {
1861        if (fe.ndims() <= dims) {
1862            return fe;
1863        } else {
1864            FExp nfe = (node == this) ? fe : splitBindingFExp(fe, node, dims + nTypeDims());
1865            for (int i = 0; i < nTypeDims(); i++) {
1866                nfe = fe.dynamicFExp(nfe).splitArrayExp(size().get(i));
1867            }
1868            return nfe;
1869        }
1870    }
1871   
1872    /**
1873     * \Return the expression corresponding to the given index in this array expression.
1874     *
1875     * Will not create new nodes unless necessary.
1876     */
1877    syn FExp FExp.splitArrayExp(Index index) {
1878        FExp res = this;
1879        for (int i : index.index())
1880            res = res.splitArrayExp(i);
1881        return res;
1882    }
1883   
1884    /**
1885     * Return the expression corresponding to the given index in this array expression.
1886     *
1887     * Will not create new nodes unless necessary.
1888     */
1889    syn FExp FExp.splitArrayExp(int index)     = new FSubscriptedExp(unboundCopy(), index, ndims());
1890    eq FArray.splitArrayExp(int index)         {
1891        if (isIterArray()) {
1892            return getFExp(0).splitArrayExp(index);
1893        }
1894       
1895        if (getNumFExp() >= index ) {
1896            return getFExp(index - 1);
1897        }
1898        return null;
1899    }
1900    eq FAccessExp.splitArrayExp(int index)     = createNode(getFAccess().splitArrayAccess(index));
1901    eq InstAccessExp.splitArrayExp(int index)  = createNode(getInstAccess().splitArrayAccess(index));
1902    eq InstDerExp.splitArrayExp(int index)     = new InstDerExp(getFExp().splitArrayExp(index));
1903    eq FArrayDimAsArgsExp.splitArrayExp(int index) {
1904        if (getNumFExp() == 1)
1905            return fillExp();
1906        List<FExp> args = new List<FExp>();
1907        for (int i = 1, n = getNumFExp(); i < n; i++)
1908            args.add(getFExp(i).fullCopy());
1909        return createNode(args);
1910    }
1911    eq FFillExp.splitArrayExp(int index) {
1912        FExp res = super.splitArrayExp(index);
1913        if (getNumFExp() > 1)
1914            ((FFillExp) res).setFillExp(getFillExp().fullCopy());
1915        return res;
1916    }
1917    eq FSubscriptedExp.splitArrayExp(int index) {
1918        FSubscriptedExp exp = (FSubscriptedExp) unboundCopy();
1919        exp.getFArraySubscripts().specifyNext(index);
1920        return exp;
1921    }
1922    eq FIterExp.splitArrayExp(int index) {
1923        Map<String,FExp> repl = new HashMap<String,FExp>();
1924        getForIndex(0).addReplacementEntry(repl, index);
1925        FExp res = dynamicFExp(getFExp().treeCopy()).replaceIndices(repl);
1926        if (getNumForIndex() > 1) {
1927            List<CommonForIndex> indices = new List<CommonForIndex>();
1928            for (int i = 1, n = getNumForIndex(); i < n; i++)
1929                indices.add(getForIndex(i).fullCopy());
1930            res = new FArray(new List(new FIterExp(res, indices)));
1931        }
1932        return res;
1933    }
1934    // TODO: consider if expressions
1935
1936    /**
1937     * Add an entry to an index replacement map for this for index, for the i:th element
1938     * in the resulting array.
1939     */
1940    public void CommonForIndex.addReplacementEntry(Map<String,FExp> repl, int i) {
1941        repl.put(name(), getFExp().getArray().get(i).treeCopy());
1942    }
1943
1944    /**
1945     * Return a new access that has index instead of the first array subscript with ndims() > 1.
1946     *
1947     * If access has no subscripts, a set of subscripts with all colons is first created.
1948     *
1949     * Note: Current implementation assumes that only last name part needs to be considered.
1950     */
1951    syn CommonAccess CommonAccess.splitArrayAccess(int index);
1952   
1953    /**
1954     * Return a new name that has index instead of the first array subscript with ndims() > 1.
1955     *
1956     * If name has no subscripts, a set of subscripts with all colons is first created.
1957     */
1958    syn FAccess FAccess.splitArrayAccess(int index); 
1959    eq FAccessEmpty.splitArrayAccess(int index) = new FAccessEmpty();
1960    eq FAccessString.splitArrayAccess(int index) {
1961        FAccessFull res = new FAccessFull(getName());
1962        int i = res.getNumFAccessPart();
1963        res.setFAccessPart(res.getFAccessPart(i - 1).splitArrayAccess(index, ndims()), i - 1);
1964        return res;
1965    }
1966    eq FAccessFull.splitArrayAccess(int index) {
1967        FAccessFull res = fullCopy();
1968        int i = getNumFAccessPart();
1969        res.setFAccessPart(getFAccessPart(i - 1).splitArrayAccess(index, ndims()), i - 1);
1970        return res;
1971    }
1972   
1973    /**
1974     * Return a new name part that has index instead of the first array subscript with ndims() > 1.
1975     *
1976     * If name part has no subscripts, a set of subscripts with all colons and ndims subscripts
1977     * is first added to the new part.
1978     */
1979    syn FAccessPart FAccessPart.splitArrayAccess(int index, int ndims) {
1980        FArraySubscripts fas = FArraySubscripts.createFColonSubscripts(ndims);
1981        fas.specifyNext(index);
1982        return new FAccessPartArray(getName(), fas);
1983    }
1984    eq FAccessPartArray.splitArrayAccess(int index, int ndims) {
1985        FAccessPartArray res = fullCopy();
1986        res.parent = parent; // Hack to allow lookups of uses from specifyNext()
1987        res.getFArraySubscripts().specifyNext(index);
1988        res.parent = null;
1989        return res;
1990    }
1991   
1992    syn InstAccess InstAccess.splitArrayAccess(int index) = this;
1993   
1994    eq InstDot.splitArrayAccess(int index) {
1995        List<InstAccess> l = new List<InstAccess>();
1996        boolean split = false;
1997        for (InstAccess ia : getInstAccesss()) {
1998            if (!split && ia.isArray()) {
1999                l.add(ia.splitArrayAccess(index));
2000                split = true;
2001            } else {
2002                l.add(ia.treeCopy());
2003            }
2004        }
2005        return new InstDot(l);
2006    }
2007   
2008    eq InstScalarAccess.splitArrayAccess(int index) {
2009        FArraySubscripts fas = FArraySubscripts.createFColonSubscripts(ndims());
2010        fas.specifyNext(index);
2011        return getArrayCopy(fas);
2012    }
2013
2014    eq InstArrayAccess.splitArrayAccess(int index) {
2015        InstArrayAccess access = fullCopy();
2016        access.setParent(getTopInstAccess());
2017        access.getFArraySubscripts().specifyNext(index);
2018        return access;
2019    }
2020
2021    eq InstGlobalAccess.splitArrayAccess(int index) = 
2022        new InstGlobalAccess(getInstAccess().splitArrayAccess(index));
2023   
2024    public void FArraySubscripts.specifyNext(int index) {}
2025    public void FArrayExpSubscripts.specifyNext(int index) {
2026        for (int i = 0; i < getNumFSubscript(); i++) {
2027            if (getFSubscript(i).ndims() > 0) {
2028                setFSubscript(getFSubscript(i).specify(index), i);
2029                return;
2030            }
2031        }
2032    }
2033   
2034    syn FSubscript FSubscript.specify(int index);
2035    eq FExpSubscript.specify(int index)     = 
2036        getFExp().getArray().getFExp(index - 1).treeCopy().createFSubscript();
2037    eq FIntegerSubscript.specify(int index) = this;
2038    eq FColonSubscript.specify(int index)   = new FIntegerSubscript(index);
2039
2040    // TODO: The names here needs to be clearer. (Down to and including getInstValueMod().)
2041    /**
2042     * Check if this InstComponentDecl is an assignable has an InstModification setting
2043     * its binding expression.
2044     */
2045    syn boolean InstComponentDecl.hasInstValueMod() = (myInstValueMod() != null);
2046
2047    /**
2048     * Check if this InstComponentDecl is an assignable with a value modifier
2049     */
2050    syn boolean InstComponentDecl.hasBindingExp() = false;
2051    eq InstAssignable.hasBindingExp()             = hasInstValueMod();
2052
2053    /**
2054     * Retrieve the InstModification setting the binding expression of
2055     * this component.
2056     *
2057     * If the component is not an assignable, or is an assignable that does
2058     * not have a binding expression, return <code>null</code>.
2059     */
2060    syn InstValueModification InstComponentDecl.myInstValueMod() = null;
2061    syn lazy InstValueModification InstAssignable.myInstValueMod() = myInstValueModCalc();
2062    syn InstValueModification InstArrayComponentDecl.myInstValueMod() = myInstValueModCalc();
2063   
2064    syn InstValueModification InstComponentDecl.myInstValueModCalc() {
2065        InstValueModification ivm = parentInstValueMod();
2066        if (ivm != null) {
2067            return ivm;
2068        }
2069        for (InstModification im : totalMergedEnvironment()) {
2070            if (im.hasInstValueMod()) {
2071                return im.getInstValueMod();
2072            }
2073        }
2074        return null;
2075    }
2076
2077    /**
2078     * Retrieve the InstModification setting the binding expression of
2079     * the parent component.
2080     *
2081     * If the parent component is not an assignable, or is an assignable that does
2082     * not have a binding expression, return <code>null</code>.
2083     */
2084    inh InstValueModification InstComponentDecl.parentInstValueMod();
2085    eq Root.getChild().parentInstValueMod()              = null;
2086    eq FExp.getChild().parentInstValueMod()              = null;
2087    eq InstClassDecl.getChild().parentInstValueMod()     = null;
2088    eq InstComponentDecl.getChild().parentInstValueMod() = myInstValueMod();
2089   
2090    /**
2091     * Check if this InstValueModification is part of a modification
2092     * that is declared "each".
2093     */
2094    syn boolean InstModification.hasEach() = inModWithEach();
2095    eq InstArgument.hasEach()              = getEach() || inModWithEach();
2096
2097    /**
2098     * Check if this modification is in another modification that is declared "each".
2099     */
2100    inh boolean InstModification.inModWithEach();
2101    eq InstArgument.getChild().inModWithEach()          = hasEach();
2102    eq InstNode.getChild().inModWithEach()              = false;
2103    eq InstRecordConstructor.getChild().inModWithEach() = false;
2104    eq InstArrayModification.getChild().inModWithEach() = true;
2105    syn boolean InstArrayModification.inModWithEach()   = true;
2106
2107    /**
2108     * \ingroup aspect_Flattening
2109     *
2110     * Check if a modification has a value modification.
2111     */
2112    syn boolean InstModification.hasInstValueMod() = false;
2113
2114    /**
2115     * \ingroup aspect_Flattening
2116     *
2117     * Check if a modification has a value modification. True for
2118     * InstValueModification.
2119     */
2120    eq InstValueModification.hasInstValueMod() = true;
2121   
2122    /**
2123     * \ingroup aspect_Flattening
2124     *
2125     * Check if a modification has a value modification. Delegate computation
2126     * to son.
2127     */
2128    eq InstCompleteModification.hasInstValueMod() = hasInstValueModification();
2129   
2130    syn FExp InstModification.instValueMod()   = null;
2131    eq InstValueModification.instValueMod()    = getFExp();
2132    eq InstCompleteModification.instValueMod() = getInstValueModification().getFExp();
2133   
2134    syn InstValueModification InstModification.getInstValueMod() = null;
2135    eq InstValueModification.getInstValueMod()    = this;
2136    eq InstCompleteModification.getInstValueMod() = getInstValueModification();
2137   
2138    /**
2139     * Delegate object that retrieves the FExp of an InstValueModification, and
2140     *        possibly alters it.
2141     *
2142     * Default implementation only retrieves the expression.
2143     */
2144    public class AttributeExpRetriever {
2145        public FExp retrieve(InstValueModification im, boolean isEach) { return im.instValueMod(); }
2146        public static final AttributeExpRetriever DEFAULT = new AttributeExpRetriever();
2147    }
2148
2149    public void ASTNode.collectAttributes(Flattener f,
2150            List<FAttribute> attrs, AttributeExpRetriever aer, boolean cls) {
2151        for (int i = 0; i < getNumChild(); i++)
2152            getChild(i).collectAttributes(f, attrs, aer, cls);
2153    }
2154
2155    // This is just to avoid collecting SrcComponentModification:s that resides inside
2156    // SrcClassRedeclares.
2157    public void InstClassRedeclare.collectAttributes(Flattener f,
2158            List<FAttribute> attrs, AttributeExpRetriever aer, boolean cls) {}
2159
2160    syn boolean InstComponentDecl.isBuiltIn()    = false;
2161    eq InstBuiltIn.isBuiltIn()                   = true;
2162    syn boolean InstBuiltInClassDecl.isBuiltIn() = true;
2163    syn boolean SrcBuiltInClassDecl.isBuiltIn()  = true;
2164    inh boolean SrcClassDecl.isBuiltIn();
2165    eq Root.getChild().isBuiltIn() = false;
2166    eq Program.getBuiltInType().isBuiltIn() = true;
2167    eq Program.getBuiltInFunction().isBuiltIn() = true;
2168   
2169    syn SourceRoot Root.asSourceRoot() {
2170        throw new UnsupportedOperationException("Method not implemented for class " + getClass().getSimpleName() + "!");
2171    }
2172    eq SourceRoot.asSourceRoot() = this;
2173   
2174    public void InstComponentModification.collectAttributes(Flattener f,
2175            List<FAttribute> attrs, AttributeExpRetriever aer, boolean cls) {
2176        if (hasInstModification()) {
2177            InstModification im = getInstModification();
2178            boolean attr_set = findMatching(attrs, getName().name()) != null;
2179            // If attribute is not set, add to list
2180            if (!attr_set && (cls || !im.isOnPrimitiveTypeDecl())) {
2181                CommonAccess typeName = new FAccessString(getName().myInstComponentDecl().myInstClass().name());
2182                FIdDecl name = new FIdDecl(new FAccessString(getName().name()));
2183                FAttribute a = new FAttribute(typeName, name, true, modificationLevel());
2184                if (im.hasInstValueMod() && getName().myInstComponentDecl().isBuiltIn()) {
2185                    InstValueModification ivm = im.getInstValueMod();
2186                    a.setValue(aer.retrieve(ivm, ivm.hasEach()).flatten(f));
2187                }
2188                if (getSrcComponentModification().getEach())
2189                    a.setFEach(new FEach());
2190                if (getSrcComponentModification().getFinal())
2191                    a.setFFinal(new FFinal());
2192                List<FAttribute> l = new List<FAttribute>();
2193                l.addAll(a.getFAttributes());
2194                im.collectAttributes(f, l, aer, cls);
2195                a.setFAttributeList(l);
2196                if (a.hasValue() || a.getNumFAttributeNoTransform() > 0) {
2197                    attrs.add(a);
2198                }
2199            }
2200        }
2201    }
2202
2203    inh boolean InstModification.isOnPrimitiveTypeDecl();
2204    eq InstExtends.getChild().isOnPrimitiveTypeDecl()           = extendsPrimitive();
2205    eq InstNode.getChild().isOnPrimitiveTypeDecl()              = false;
2206    eq InstRecordConstructor.getChild().isOnPrimitiveTypeDecl() = false;
2207
2208
2209    /**
2210     * Get the modification level that is set for containing InstNode.
2211     *
2212     * @throws UnsupportedOperationException  if setModificationLevel() has not been called on surrounding InstNode
2213     */
2214    inh int InstModification.modificationLevel();
2215    eq Root.getChild().modificationLevel()     = 0;
2216    eq InstNode.getChild().modificationLevel() = myModificationLevel;
2217
2218    /**
2219     * Set the modification level for contained modifications.
2220     *
2221     * @throws IllegalArgumentException  if level is negative
2222     */
2223    public HashMap<InstNode,Integer> InstNode.setModificationLevel(int level) {
2224        HashMap<InstNode,Integer> old = new HashMap<InstNode,Integer>();
2225        setModificationLevelHelper(old, level);
2226        return old;
2227    }
2228
2229    public void InstNode.setModificationLevelHelper(HashMap<InstNode,Integer> old, int level) {
2230        myModificationLevel = level;
2231        old.put(this, myModificationLevel);
2232        for (InstNode extra : extraNodesToSetModLevelFor()) {
2233            if (extra != null && !old.containsKey(extra)) {
2234                extra.setModificationLevelHelper(old, extra.nextModLevelForExtraNode(level));
2235            }
2236        }
2237    }
2238
2239    public void InstNode.clearModificationLevel(HashMap<InstNode,Integer> old) {
2240        for (InstNode n : old.keySet()) {
2241            n.myModificationLevel = old.get(n);
2242        }
2243    }
2244
2245    syn int InstNode.nextModLevelForExtraNode(int level)                  = level + 1;
2246    eq InstExtendsShortClass.nextModLevelForExtraNode(int level)          = level;
2247    eq InstReplacingExtendsShortClass.nextModLevelForExtraNode(int level) = level;
2248    eq InstInlineExtends.nextModLevelForExtraNode(int level)              = level;
2249
2250    inh InstNode InstNode.parentNodeToSetModLevelFor();
2251    eq InstClassDecl.getChild().parentNodeToSetModLevelFor()    = hasModificationLevel() ? null : this;
2252    eq InstExtends.getChild().parentNodeToSetModLevelFor()      = hasModificationLevel() ? null : this;
2253    eq InstRoot.getChild().parentNodeToSetModLevelFor()         = null;
2254    eq Root.getChild().parentNodeToSetModLevelFor()             = null;
2255
2256    syn InstNode[] InstNode.extraNodesToSetModLevelFor()        = listExtraNodesToSetModLevelFor(false);
2257    eq InstComponentDecl.extraNodesToSetModLevelFor()           = listExtraNodesToSetModLevelFor(true, myInstClass());
2258    eq InstExtends.extraNodesToSetModLevelFor()                 = listExtraNodesToSetModLevelFor(true, myInstClass());
2259    eq InstClassDecl.extraNodesToSetModLevelFor()               = listExtraNodesToSetModLevelFor(true);
2260    eq InstSimpleShortClassDecl.extraNodesToSetModLevelFor()    = listExtraNodesToSetModLevelFor(false, actualInstClass());
2261    eq InstLibNode.extraNodesToSetModLevelFor()                 = listExtraNodesToSetModLevelFor(false, actualInstClass());
2262    eq InstReplacingComposite.extraNodesToSetModLevelFor()      = 
2263        listExtraNodesToSetModLevelFor(true, getInstComponentRedeclare().getInstComponentDecl(), myInstClass());
2264    eq InstReplacingRecord.extraNodesToSetModLevelFor()         = 
2265        listExtraNodesToSetModLevelFor(true, getInstComponentRedeclare().getInstComponentDecl(), myInstClass());
2266    eq InstReplacingPrimitive.extraNodesToSetModLevelFor()      = 
2267        listExtraNodesToSetModLevelFor(true, getInstComponentRedeclare().getInstComponentDecl(), myInstClass());
2268    eq InstReplacingFullClassDecl.extraNodesToSetModLevelFor()  = 
2269        listExtraNodesToSetModLevelFor(true, getInstClassRedeclare().redeclaringInstClassDecl());
2270    eq InstReplacingShortClassDecl.extraNodesToSetModLevelFor() = 
2271        listExtraNodesToSetModLevelFor(true, getInstClassRedeclare().redeclaringInstClassDecl());
2272    eq InstReplacingSimpleShortClassDecl.extraNodesToSetModLevelFor() = 
2273        listExtraNodesToSetModLevelFor(false, getInstClassRedeclare().redeclaringInstClassDecl(), actualInstClass());
2274
2275    protected InstNode[] InstNode.listExtraNodesToSetModLevelFor(boolean ext, InstNode... nodes) {
2276        InstNode[] res = new InstNode[nodes.length + (ext ? getNumInstExtends() : 0) + 1];
2277        System.arraycopy(nodes, 0, res, 0, nodes.length);
2278        for (int i = nodes.length; i < res.length - 1; i++) {
2279            res[i] = getInstExtends(i - nodes.length);
2280        }
2281        res[res.length - 1] = parentNodeToSetModLevelFor();
2282        return res;
2283    }
2284
2285    private int InstNode.myModificationLevel = Integer.MAX_VALUE;
2286
2287    syn boolean InstNode.hasModificationLevel() = myModificationLevel != Integer.MAX_VALUE;
2288
2289}
2290
2291aspect FlatteningDebug {
2292    coll HashSet<InstAccess> FClass.collectInstAccesses() [new HashSet<InstAccess>()] with add root FClass;
2293    InstAccess contributes
2294        this 
2295    to FClass.collectInstAccesses() for myFClass();
2296    inh FClass InstAccess.myFClass();
2297
2298}
2299
2300
2301aspect FlatExpressions {
2302   
2303    public FAttribute FAttribute.flatten(Flattener f) {
2304        FAttribute flat = createEmptyNode();
2305        flat.setType(getType().fullCopy());
2306        flat.setName(getName().fullCopy());
2307        if (hasValue())
2308            flat.setValue(getValue().flatten(f));
2309        flat.setLevel(getLevel());
2310        if (hasFEach())
2311            flat.setFEach(getFEach().fullCopy());
2312        if (hasFFinal())
2313            flat.setFFinal(getFFinal().fullCopy());
2314        List<FAttribute> flatAttrs = new List<FAttribute>();
2315        for (FAttribute attr : getFAttributes())
2316            flatAttrs.add(attr.flatten(f));
2317        flat.setFAttributeList(flatAttrs);
2318        return flat;
2319    }
2320
2321    public FArraySubscripts FArraySubscripts.flatten(Flattener f) {
2322        return treeCopy();
2323    }
2324    public FArraySubscripts FArrayExpSubscripts.flatten(Flattener f) {
2325        List l = new List();
2326        for (FSubscript fs : getFSubscripts())
2327            l.add(fs.flatten(f));
2328        return FArraySubscripts.createFArraySubscripts(l);
2329    }
2330
2331    abstract public FSubscript FSubscript.flatten(Flattener f);
2332
2333    public FSubscript FColonSubscript.flatten(Flattener f) {
2334        if (expandSize()) {
2335            return size().flattenSubscript(0);
2336        } else {
2337            return new FColonSubscript();
2338        }
2339    }
2340   
2341    inh boolean FSubscript.expandSize();
2342    inh boolean FEndExp.expandSize();
2343    eq Root.getChild().expandSize()             = true;
2344    eq InstNode.getChild().expandSize()         = true;
2345    eq CommonAccess.getChild().expandSize()           = true;
2346    eq InstDot.getInstAccess(int i).expandSize() {
2347        for (int j = 0; j < i; j++) {
2348            if (!getInstAccess(j).indexVariability().indexParameterOrLess()) {
2349                return false;
2350            }
2351        }
2352        return true;
2353    }
2354   
2355    public FSubscript Size.flattenSubscript(int i) {
2356        return new FExpSubscript(new FRangeExp(new FIntegerLitExp(1),new FIntegerLitExp(get(i))));
2357    }
2358   
2359    public FSubscript MutableSize.flattenSubscript(int i) {
2360        if (isUnknown()) {
2361            return new FColonSubscript();
2362        } else {
2363            return super.flattenSubscript(i);
2364        }
2365    }
2366   
2367    public FArraySubscripts Size.flattenSubscript() {
2368        if (ndims() == 0) {
2369            return null;
2370        }
2371        List<FSubscript> list = new List<FSubscript>();
2372        for (int i = 0; i < ndims(); i++) {
2373            list.add(flattenSubscript(i));
2374        }
2375        return FArraySubscripts.createFArraySubscripts(list);
2376    }
2377   
2378    public FSubscript FIntegerSubscript.flatten(Flattener f) { 
2379        return new FIntegerSubscript(getValue());
2380    }
2381
2382    public FSubscript FExpSubscript.flatten(Flattener f) {
2383        return getFExp().flatten(f).createFSubscript();
2384    }
2385
2386    public FExp FExp.flatten(Flattener f) {
2387        throw new UnsupportedOperationException();
2388    }
2389
2390    public FIgnoredBuiltIn FIgnoredBuiltIn.flatten(Flattener f) {
2391        return new FIgnoredBuiltIn();
2392    }
2393
2394    @Override
2395    public FExp FDeferExp.flatten(Flattener f) {
2396        return getFExp().flatten(f);
2397    }
2398
2399    /**
2400     * Separate method for extensibility.
2401     */
2402    private FAccessExp InstComponentDecl.createCommonAccessExp(FAccess name, int order) {
2403        if (order > 0) {
2404            return new FDerExp(name, order);
2405        } else {
2406            return new FAccessExp(name);
2407        }
2408    }
2409
2410    /**
2411     * Create a constant FSubscript.
2412     */
2413    public FSubscript CValue.createFSubscript() {
2414        return buildLiteral().createFSubscript();
2415    }
2416   
2417    public FSubscript CValueInteger.createFSubscript() {
2418        return new FIntegerSubscript(intValue());
2419    }
2420
2421    public FExp FArray.flatten(Flattener f) {
2422        if (isIterArray() && !size().isUnknown()) {
2423            return ((FIterExp)getFExp(0)).flattenArray(f);
2424        }
2425        List l = new List();
2426        for (FExp exp : getFExps()) {
2427            l.add(exp.flatten(f));
2428        }
2429        return createNode(l);
2430    }
2431   
2432    public FArray FIterExp.flattenArray(Flattener f) {
2433        Iterable<CommonForIndex> forIndices = getForIndexs();
2434        Indices ind = Indices.create(forIndices);
2435        FArray res = flattenArray(f, forIndices, ind, ind.iterator(), ind.size(), 0);
2436        for (CommonForIndex fi : forIndices) {
2437            fi.clearEvaluationValue();
2438        }
2439        return res;
2440    }
2441   
2442    public FArray FIterExp.flattenArray(Flattener f, Iterable<CommonForIndex> forIndices, Indices ind, Iterator<Index> indIt, Size s, int dim) {
2443        List<FExp> l = new List<FExp>();
2444        if (dim == s.ndims() - 1) {
2445            for (int i = 0; i < s.get(dim); i++) {
2446                ind.translate(indIt.next()).setValues(forIndices);
2447                getFExp().flushAllRecursive();
2448                l.add(getFExp().flatten(f));
2449            }
2450        } else {
2451            for (int i = 0; i < s.get(dim); i++) {
2452                l.add(flattenArray(f, forIndices, ind, indIt, s, dim+1));
2453            }
2454        }
2455        return new FArray(l);
2456    }
2457   
2458    public void Index.setValues(Iterable<? extends CommonForIndex> forIndices) {
2459        int i = 0;
2460        for (CommonForIndex fi : forIndices) {
2461            fi.setEvaluationValue(CValueInteger.valueOf(index[i++]));
2462        }
2463    }
2464   
2465    public FExp FReductionExp.flatten(Flattener f) {
2466        if (isArray() && !size().isUnknown()) {
2467            return getArray().buildFlattened(f, this);
2468        }
2469        return (FReductionExp) createNode(getFExp().flatten(f));
2470    }
2471   
2472    public FExp FIterExp.flatten(Flattener f) {
2473        if (!size().isUnknown()) {
2474            return getArray().buildFlattened(f, this);
2475        }
2476        List<CommonForIndex> fil = new List<CommonForIndex>();
2477        for (CommonForIndex fi : getForIndexList())
2478            fil.add(fi.flatten(f));
2479        return new FIterExp(getFExp().flatten(f), fil);
2480    }
2481
2482    public FExp FSubscriptedExp.flatten(Flattener f) {
2483        return new FSubscriptedExp(getFExp().flatten(f), getFArraySubscripts().flatten(f));
2484    }
2485
2486    public FIdDecl FIdDecl.flatten(Flattener f) {
2487        return (FIdDecl)fullCopy();
2488    }
2489
2490    public FExp FRangeExp.flatten(Flattener f) {
2491        List l = new List();
2492        for (FExp e : getFExps())
2493            l.add(e.flatten(f));
2494        return new FRangeExp(l);
2495    }
2496
2497    public FLinspace FLinspace.flatten(Flattener f) {
2498        return new FLinspace(getStartExp().flatten(f), 
2499                             getStopExp().flatten(f), 
2500                             getN().flatten(f));
2501    }
2502
2503    public FExp FIfExp.flatten(Flattener f) {
2504        if (getIfExpNoTransform().variability().knownParameterOrLess()) {
2505            try {
2506                CValue cval = getIfExpNoTransform().ceval();
2507                if (cval.hasBooleanValue()) {
2508                    return cval.booleanValue() ? 
2509                            getThenExp().flatten(f) : 
2510                            getElseExp().flatten(f);
2511                }
2512            } catch (ConstantEvaluationException e) {}
2513        }
2514        return new FIfExp(getIfExp().flatten(f),
2515                          getThenExp().flatten(f),
2516                          getElseExp().flatten(f));
2517    }
2518
2519    public FExp FBinExp.flatten(Flattener f) {
2520        InstClassDecl oper = overloadedOperator();
2521        if (oper == null)
2522            return createNode(getLeft().flatten(f), getRight().flatten(f));
2523        else if (oper.myInputs().get(0).ndims() != getLeft().ndims() || oper.myInputs().get(1).ndims() != getRight().ndims())
2524            return getArray().buildFlattened(f, this);
2525        else
2526            return oper.flattenOverloadedFunctionCall(f, getLeft(), getRight());
2527    }
2528
2529    public FExp FUnaryExp.flatten(Flattener f)   {
2530        InstClassDecl oper = overloadedOperator();
2531        if (oper == null)
2532            return createNode(getFExp().flatten(f));
2533        else if (oper.myInputs().get(0).ndims() != getFExp().ndims())
2534            return getArray().buildFlattened(f, this);
2535        else
2536            return oper.flattenOverloadedFunctionCall(f, getFExp());
2537    }
2538
2539    /**
2540     * Create an FArray containing flattened subexpressions.
2541     */
2542    public FExp Array.buildFlattened(Flattener f, FExp context);
2543   
2544    public FExp FExp.buildFlattened(Flattener f, FExp context) {
2545        return flatten(f);
2546    }
2547   
2548    public FExp ArrayExp.buildFlattened(Flattener f, FExp context) {
2549        return buildFArray(new FlattenedBuilder(f, context, 0));
2550    }
2551
2552    public FExp ArrayExp.buildFlattened(Flattener f, FExp context, int order) {
2553        return buildFArray(new FlattenedBuilder(f, context, order));
2554    }
2555
2556    public class ArrayExp {
2557        /**
2558         * Helper object for {@link #buildFlattened(FAccess, FExp)}.
2559         */
2560        protected static class FlattenedBuilder implements ElementBuilder {
2561            private Flattener f;
2562            private FExp context;
2563            private int order;
2564           
2565            public FlattenedBuilder(Flattener f, FExp context, int order) {
2566                this.f = f;
2567                this.context = context;
2568                this.order = order;
2569            }
2570           
2571            public FExp build(FExp e) {
2572                if (order > 0) {
2573                    return context.dynamicFExp(new InstHDerExp(e, order)).flatten(f);
2574                } else {
2575                    return context.dynamicFExp(e).flatten(f);
2576                }
2577            }
2578        }
2579    }
2580
2581    public FExp FLitExp.flatten(Flattener f)     { return fullCopy(); }
2582    public FExp FEnumLitExp.flatten(Flattener f) { return new FEnumLitExp(getEnum(), getValue(), new Opt<FEnumType>()); }
2583   
2584    public FExp FModFuncExp.flatten(Flattener f) {
2585        FExp toRound = new FDivExp(getX().flatten(f), getY().flatten(f));
2586        FExp rounded = type().isInteger() ? new FIntegerFuncExp(toRound) : new FFloorFuncExp(toRound);
2587        return new FSubExp(getX().flatten(f), new FMulExp(rounded, getY().flatten(f)));
2588    }
2589       
2590    public FExp FEventGenExp.flatten(Flattener f)    { return createNode(getX().flatten(f)); }
2591    public FExp FBinEventGenExp.flatten(Flattener f) { return createNode(getX().flatten(f), getY().flatten(f)); }
2592    public FExp FRemFuncExp.flatten(Flattener f)     { return new FSubExp(getX().flatten(f), new FMulExp(new FDivFuncExp(getX().flatten(f), getY().flatten(f)), getY().flatten(f)));}
2593    public FExp FUnaryBuiltIn.flatten(Flattener f)   { return createNode(getFExp().flatten(f)); }
2594    public FExp FEdgeExp.flatten(Flattener f)        { return new FAndExp(getFExp().flatten(f), new FNotExp(getFExp().flatten(f).createFPreExp())); }
2595   
2596    public FExp FLoadResource.flatten(Flattener f)   {
2597        try {
2598            CValue cval = ceval();
2599            if (cval.hasStringValue()) {
2600                String s = cval.stringValue();
2601                if (new File(s).isDirectory()) {
2602                    return new FStringLitExp(s);
2603                }
2604                return createNode(new FStringLitExp(s));
2605            }
2606            // TODO: unit tests depending on lack of error handling
2607            // throw new InternalCompilerError("Could not evaluate loadResource during flattening");
2608        } catch (ConstantEvaluationException e) {
2609            // TODO: unit tests depending on lack of error handling
2610            // throw new InternalCompilerError("Could not evaluate loadResource during flattening: " + e.getModelicaStackTrace());
2611        }
2612        return createNode(getFExp().flatten(f));
2613    }
2614   
2615    // These operators save reference to source node in instance tree until end of flattening - used for error checking them
2616    public FExp FChangeExp.flatten(Flattener f)      { return new FNeqExp(getFExp().flatten(f), FPreExp.create(getFExp().flatten(f), this)); }
2617    public FExp InstPreExp.flatten(Flattener f)      {
2618        if (getFExp().variability().parameterOrLess()) {
2619            return getFExp().flatten(f);
2620        }
2621        return FPreExp.create(getFExp().flatten(f), this);
2622    }
2623   
2624    public FExp FExp.createFPreExp() {
2625        throw new UnsupportedOperationException("createFPreExp() is not supported for class type " + getClass().getSimpleName());
2626    }
2627    public FExp FAccessExp.createFPreExp() {
2628        return new FPreExp(getFAccessNoTransform());
2629    }
2630    public FExp FLitExp.createFPreExp() {
2631        return this;
2632    }
2633    public FExp FSubscriptedExp.createFPreExp() {
2634        return new FSubscriptedExp(getFExpNoTransform().createFPreExp(), 
2635                getFArraySubscriptsNoTransform());
2636    }
2637    public FExp FArray.createFPreExp() {
2638        return this; // Assume literal;
2639    }
2640    public FExp FRecordConstructor.createFPreExp() {
2641        return this; // Assume literal;
2642    }
2643   
2644    public FExp FNoArgBuiltIn.flatten(Flattener f)             { return createEmptyNode(); }
2645    public FExp FMathematicalFunctionCall.flatten(Flattener f) { return createNode(getFExp().flatten(f)); }
2646    public FExp FAtan2Exp.flatten(Flattener f)                 { return createNode(getFExp().flatten(f), getY().flatten(f)); }
2647    public FExp FHomotopyExp.flatten(Flattener f)              {
2648        if (myOptions().getStringOption("homotopy_type") == OptionRegistry.Homotopy.ACTUAL) {
2649            return getActual().flatten(f);
2650        }
2651        if (myOptions().getStringOption("homotopy_type") == OptionRegistry.Homotopy.SIMPLIFIED) {
2652            return getSimplified().flatten(f);
2653        }
2654        return createNode(getActual().flatten(f), getSimplified().flatten(f)); 
2655    }
2656    public FExp FSemiLinearExp.flatten(Flattener f)   { return new FSemiLinearExp(getX().flatten(f), getPosSlope().flatten(f), getNegSlope().flatten(f)); }
2657    public FExp FDelayExp.flatten(Flattener f)        { return createNode(getFExp().flatten(f), getDelay().flatten(f), hasMax() ? new Opt(getMax().flatten(f)) : new Opt()); }
2658    public FExp FGetInstanceName.flatten(Flattener f) { return new FStringLitExp(calcInstanceName()); }
2659    public FExp FSpatialDistExp.flatten(Flattener f)     {
2660        return new FSpatialDistExp(
2661            getIn0().flatten(f), getIn1().flatten(f), 
2662            getX().flatten(f), getPositiveVelocity().flatten(f),
2663            getInitialPoints().flatten(f), getInitialValues().flatten(f)
2664        );
2665    }
2666
2667    public FUnsupportedBuiltIn FUnsupportedBuiltIn.flatten(Flattener f) { throw new UnsupportedOperationException(); }
2668   
2669    public FCross        FCross.flatten(Flattener f)        { return new FCross(getX().flatten(f), getY().flatten(f)); }
2670    public FOuterProduct FOuterProduct.flatten(Flattener f) { return new FOuterProduct(getX().flatten(f), getY().flatten(f)); }
2671    public FSampleExp    FSampleExp.flatten(Flattener f)    { return new FSampleExp(getOffset().flatten(f), getInterval().flatten(f)); }
2672    public FSmoothExp    FSmoothExp.flatten(Flattener f)    { return new FSmoothExp(getOrder().flatten(f), getFExp().flatten(f)); }
2673   
2674    public FReinit FReinit.flatten(Flattener f) {
2675        FReinit res = new FReinit(getVar().flatten(f), getFExp().flatten(f));
2676        res.setInstanceTreeSource(this);
2677        return res;
2678    }
2679   
2680   
2681    public FAssert FAssert.flatten(Flattener f) {
2682        Opt level = hasLevel() ? new Opt(getLevel().flatten(f)) : new Opt();
2683        return createNode(getTest().flatten(f), getMsg().flatten(f), level); 
2684    }
2685   
2686    public FExp FCardinality.flatten(Flattener f) { return createNode(getFExp().flatten(f)); }
2687   
2688    public FExp FDecouple.flatten(Flattener f) { 
2689        return getFExp().flatten(f);
2690    }
2691
2692    public FConnectionsOp FConnectionsOp.flatten(Flattener f) { throw new UnsupportedOperationException(); }
2693    public FConnectionsOp FConnBoolOp.flatten(Flattener f) {
2694        FConnBoolOp res = createNode(getA().flatten(f));
2695        res.connectionGraph = connectionGraph;
2696        return res;
2697    }
2698   
2699    public FStringExp FStringExp.flatten(Flattener f) {
2700        FStringExp flattened = new FStringExp();
2701        flattened.setValue(getValue().flatten(f));
2702        if (hasMinimumLength())
2703            flattened.setMinimumLength(getMinimumLength().flatten(f));
2704        if (hasLeftJustified())
2705            flattened.setLeftJustified(getLeftJustified().flatten(f));
2706        if (hasSignificantDigits())
2707            flattened.setSignificantDigits(getSignificantDigits().flatten(f));
2708        if (hasFormat())
2709            flattened.setFormat(getFormat().flatten(f));
2710        return flattened;
2711    }
2712    public FExp FDotAddExp.flatten(Flattener f) { 
2713        return type().isString() ? 
2714                new FStringAddExp(getLeft().flatten(f), getRight().flatten(f)) : 
2715                super.flatten(f);
2716    }
2717   
2718    public FMinMaxExp FMinMaxExp.flatten(Flattener f) { 
2719        return createNode(getX().flatten(f), hasY() ? getY().flatten(f) : null); 
2720    }
2721   
2722    public FExp FSizeExp.flatten(Flattener f) {
2723        return new FSizeExp(getFExp().flatten(f), 
2724                hasDim() ? new Opt<FExp>(getDim().flatten(f)) : new Opt<FExp>());
2725    }
2726   
2727    public FExp InstDerExp.flatten(Flattener f) {
2728        return setLocationOf(getFExp().flattenDer(f, order()));
2729    }
2730   
2731    public FExp FExp.flattenDer(Flattener f, int order) {
2732        return diff(TIME, order).flatten(f);
2733    }
2734   
2735     public FExp CommonAccessExp.flattenDer(Flattener f, int order) {
2736         return setLocationOf(flatten(f, order));
2737     }
2738
2739    public FInfArgsFunctionCall FInfArgsFunctionCall.flatten(Flattener f) {
2740        List<FExp> l = new List<FExp>();
2741        for (FExp e : getFExps()) 
2742            l.add(e.flatten(f));
2743        return createNode(l); 
2744    }
2745   
2746    public FFillExp FFillExp.flatten(Flattener f) {
2747        FFillExp res = (FFillExp) super.flatten(f);
2748        res.setFillExp(getFillExp().flatten(f));
2749        return res;
2750    }
2751   
2752    public FCatExp FCatExp.flatten(Flattener f) {
2753        FCatExp res = (FCatExp) super.flatten(f);
2754        res.setDim(getDim().flatten(f));
2755        return res;
2756    }
2757   
2758    public FTimeExp FTimeExp.flatten(Flattener f) { return setLocationOf(new FTimeExp()); }
2759   
2760    public FExp FEndExp.flatten(Flattener f)  {
2761        if (expandSize()) {
2762            return mySize().flattenFExp(f, 0);
2763        } else {
2764            return new FEndExp();
2765        }
2766    }
2767   
2768    public FExp Size.flattenFExp(Flattener f, int d) {
2769        return createFExp(d);
2770    }
2771   
2772    public FExp MutableSize.flattenFExp(Flattener f, int d) {
2773        if (exps[d] != null) {
2774            return exps[d].flatten(f);
2775        } else {
2776            return super.flattenFExp(f, d);
2777        }
2778    }
2779   
2780    inh FExp SrcDummyModification.myFExp();
2781    eq InstFunctionArgument.getChild().myFExp()   = null;
2782    eq InstPositionalArgument.getChild().myFExp() = getFExp();
2783    eq InstNamedArgument.getChild().myFExp()      = getFExp();
2784    eq Root.getChild().myFExp()                   = null;
2785
2786    public FRecordConstructor InstRecordConstructor.flatten(Flattener f) {
2787        List<FExp> args = new List();
2788        for (InstFunctionArgument ifa : getArgs()) {
2789            args.add(ifa.flatten(f));
2790        }
2791        return new FRecordConstructor(getRecord().flattenRecordName(), args);
2792    }
2793
2794    public FExp InstComponentDecl.flattenInRecordConstructor(Flattener f) {
2795        return null;
2796    }
2797   
2798    public FExp InstAssignable.flattenInRecordConstructor(Flattener f) {
2799        if (hasBindingFExp()) {
2800            return flattenBindingFExp(f);
2801        } else {
2802            return cevalNoBExp(defaultVariableEvaluator(), Index.NULL).buildLiteral();
2803        }
2804    }
2805   
2806    public FRecordAccess InstAccess.flattenRecordName() {
2807        return new FRecordAccess(myInstClassDecl().qualifiedName());
2808    }
2809   
2810    public FFunctionCall FFunctionCall.flatten(Flattener f) {
2811        List args = new List();
2812        for (FExp e : getArgs()) 
2813            args.add(e.flatten(f));
2814        getFTypeNoTransform().clearFlattened();
2815        return new FFunctionCall(getName().flatten(f), args, getFType().flatten(f, null, true));
2816    }
2817   
2818    public void ASTNode.clearFlattened() {
2819        for (ASTNode n : noTransform()) {
2820            n.clearFlattened();
2821        }
2822    }
2823    public void FRecordType.clearFlattened() { flattened = false; super.clearFlattened(); }
2824    public void FFunctionType.clearFlattened() { flattened = false; super.clearFlattened(); }
2825
2826    public FExp InstFunctionCall.flatten(Flattener f) {
2827        if (callsLoadResource() && !inFunction()) {
2828            if (isFunctionCallClause()) {
2829                ASTNode.CANNOT_EVALUATE_LOADRESOURCE.invoke(this, this, "");
2830            } else {
2831                try {
2832                    return ceval().buildLiteral();
2833                } catch (ConstantEvaluationException e) {
2834                    ASTNode.CANNOT_EVALUATE_LOADRESOURCE.invoke(this, this, e.getModelicaStackTrace());
2835                }
2836            }
2837        }
2838        List args = new List();
2839        for (InstFunctionArgument e : getArgs()) 
2840            args.add(e.flatten(f));
2841        InstCallable target = myInstCallable().actualInstCallable();
2842        FAccess name = new FAccessString(target.qualifiedName());
2843        return createFFunctionCall(name, args, getFType().flatten(f, null, true));
2844    }
2845
2846    public static final SimpleProblemProducer ASTNode.CANNOT_EVALUATE_LOADRESOURCE =
2847            new SimpleErrorProducer("CANNOT_EVALUATE_LOADRESOURCE", ProblemKind.SEMANTIC,
2848                    "Could not evaluate function call which depends on loadResource during flattening: %s%s");
2849
2850    public FFunctionCall InstFunctionCall.createFFunctionCall(FAccess name, List args, FType type) {
2851        return setLocationOf(new FFunctionCall(name, args, type));
2852    }
2853   
2854    public FFunctionCall InstPartialFunctionCall.createFFunctionCall(FAccess name, List args, FType type) {
2855        List<CommonAccess> argNames = new List<CommonAccess>();
2856        for (String s : namedArgs())
2857            argNames.add(new FAccessString(s));
2858        return new FPartialFunctionCall(name, args, type, argNames);
2859    }
2860
2861    public FFunctionCall InstVectorFunctionCall.createFFunctionCall(FAccess name, List args, FType type) {
2862        boolean[] vectorFlags = new boolean[getNumArg()];
2863        int i = 0;
2864        for (InstFunctionArgument e : getArgs())
2865            vectorFlags[i++] = e.isVectorized();
2866        return new FVectorFunctionCall(name, args, type, size(), vectorFlags);
2867    }
2868
2869    public FFunctionCall InstClassDecl.flattenOverloadedFunctionCall(Flattener f, FExp... args) {
2870        FType[] argTypes = new FType[args.length];
2871        for (int i = 0; i < args.length; i++)
2872            argTypes[i] = args[i].type();
2873        return flattenOverloadedFunctionCall(f, args, argTypes);
2874    }
2875
2876    public FFunctionCall InstClassDecl.flattenOverloadedFunctionCall(Flattener f, FExp[] args, FType[] argTypes) {
2877        // TODO: handle array operations (scalar * matrix, etc)
2878        FAccess name = new FAccessString(qualifiedName());
2879        int nIn = myInputs().size();
2880        if (nIn > args.length)
2881            args = Arrays.copyOf(args, nIn);
2882        Map<InstComponentDecl,FExp> argMap = new HashMap<InstComponentDecl,FExp>();
2883        for (int i = 0; i < nIn; i++) {
2884            InstComponentDecl in = myInputs().get(i);
2885            argMap.put(in, args[i]);
2886        }
2887        FExp.FunctionContextReplacer crp = new FExp.ExpFunctionContextReplacer(argMap);
2888        for (int i = 0; i < nIn; i++) {
2889            InstComponentDecl in = myInputs().get(i);
2890            if (args[i] == null) {
2891                args[i] = crp.get(in).flatten(f);
2892            } else if (!in.type().typeCompatible(argTypes[i], true)) {
2893                InstClassDecl constructor = in.type().matchOverloadedConstructor(argTypes[i]);
2894                args[i] = constructor.flattenOverloadedFunctionCall(f, args[i]);
2895            } else {
2896                args[i] = args[i].flatten(f);
2897            }
2898        }
2899        List<FExp> argList = new List<FExp>(args);
2900        return new FFunctionCall(name, argList, functionType().flatten(f, null, true));
2901    }
2902
2903    public FExp InstFunctionArgument.flatten(Flattener f) {
2904        return getFExp().flatten(f);
2905    }
2906
2907    public FExp InstDefaultArgument.flatten(Flattener f) {
2908        return getFExp().flatten(f);
2909    }
2910
2911    public abstract FForIndex CommonForIndex.flatten(Flattener f);
2912
2913    @Override
2914    public FForIndex InstForIndex.flatten(Flattener f) {
2915        return new FForIndex(getInstPrimitive().createFVariable(f), getFExp().flatten(f));
2916    }
2917
2918    @Override
2919    public FForIndex FForIndex.flatten(Flattener f) {
2920        return (FForIndex) fullCopy();
2921    }
2922
2923    /**
2924     * Flatten variability specifier.
2925     *
2926     * This is done during variability calculation to keep compatibility with FExp.
2927     */
2928    abstract public TypePrefixVariability SrcTypePrefixVariability.flatten();
2929    public TypePrefixVariability SrcContinuous.flatten()     { return Variability.CONTINUOUS;     }
2930    public TypePrefixVariability SrcDiscrete.flatten()       { return Variability.DISCRETE;       }
2931    public TypePrefixVariability SrcParameter.flatten()      { return Variability.FIXEDPARAMETER; }
2932    public TypePrefixVariability SrcIndexParameter.flatten() { return Variability.INDEXPARAMETER; }
2933    public TypePrefixVariability SrcConstant.flatten()       { return Variability.CONSTANT;       }
2934}
2935
2936aspect InstantiatedExpressions {
2937
2938   
2939    public EquationType SrcAbstractEquation.equationType() {
2940        return isInitial() ? EquationType.INITIAL : EquationType.NORMAL;
2941    }
2942
2943    public EquationType SrcAlgorithm.equationType() {
2944        return isInitial() ? EquationType.INITIAL : EquationType.NORMAL;
2945    }
2946
2947    public <T extends FAbstractEquation> T SrcAbstractEquation.copyStringComment(T eqn) {
2948        SrcStringComment comment = myStringComment();
2949        if (comment != null) {
2950            eqn.setFStringComment(comment.flatten());
2951        }
2952        return eqn;
2953    }
2954
2955    public FAbstractEquation SrcAbstractEquation.instantiate() {
2956        return contribute(copyLocationTo(new FUnsupportedEquation(equationType())));
2957    }
2958
2959    public FAbstractEquation SrcEquation.instantiate() {
2960        return contribute(copyLocationTo(copyStringComment(new FEquation(
2961                equationType(), getLeft().instantiate(), getRight().instantiate()))));
2962    }
2963   
2964    public FAbstractEquation SrcConnectClause.instantiate() {
2965        FConnectClause c = new FConnectClause(equationType(), this,
2966                getConnector1().newInstAccess(),
2967                getConnector2().newInstAccess());
2968        c.setLocation(this);
2969        return contribute(copyStringComment(c));
2970    }
2971   
2972    protected FIfWhenElseEquation SrcIfWhenElseEquation.instantiate(FIfWhenElseEquation res) {
2973        res.setType(equationType());
2974        for (SrcAbstractEquation eqn : getSrcAbstractEquations())
2975            res.addFAbstractEquation(eqn.instantiate());
2976        res.setLocation(this);
2977        return contribute(copyStringComment(res));
2978    }
2979   
2980    protected FIfWhenEquation SrcIfWhenEquation.instantiate(FIfWhenEquation res) {
2981        super.instantiate(res);
2982        res.setTest(getTest().instantiate());
2983        if (hasElse())
2984            res.setElse(getElse().instantiate());
2985        return res;
2986    }
2987   
2988    public abstract FIfWhenElseEquation SrcIfWhenElseEquation.instantiate();
2989   
2990    public FIfWhenElseEquation SrcIfEquation.instantiate() {
2991        return instantiate(new FIfEquation());
2992    }
2993   
2994    public FIfWhenElseEquation SrcWhenEquation.instantiate() {
2995        return instantiate(new FWhenEquation());
2996    }
2997   
2998    public FIfWhenElseEquation SrcElseEquation.instantiate() {
2999        return instantiate(new FElseEquation());
3000    }
3001       
3002    public FFunctionCallEquation SrcFunctionCallEquation.instantiate() {
3003        List<FFunctionCallLeft> l = new List<FFunctionCallLeft>();
3004        for (SrcFunctionCallLeft a : getLefts()) 
3005            l.add(a.instantiate());
3006        return contribute(copyLocationTo(copyStringComment(
3007                new FFunctionCallEquation(equationType(), l, getCall().instantiate()))));
3008    }
3009   
3010    public  FFunctionCallLeft SrcFunctionCallLeft.instantiate() {
3011        Opt id = hasSrcAccess() ? 
3012                new Opt(setLocationOf(new InstAccessExp(getSrcAccess().newInstAccess()))) : 
3013                new Opt();
3014        return new FFunctionCallLeft(id);
3015    }
3016   
3017    public FAlgorithm SrcAlgorithm.instantiate() {
3018        List l = SrcStatement.instantiateStatementList(getSrcStatements());
3019        return copyLocationTo(new FAlgorithm(equationType(), l));
3020    }
3021   
3022    public InstExternal SrcExternalClause.instantiate() {
3023        // TODO: Interpret annotations and add information to InstExternal
3024        Opt lang = hasSrcExternalLanguage() ? new Opt(getSrcExternalLanguage().instantiate()) : new Opt();
3025        Opt call = hasSrcExternalFunctionCall() ? new Opt(getSrcExternalFunctionCall().instantiate()) : new Opt();
3026        return copyLocationTo(new InstExternal(this, lang, call));
3027    }
3028   
3029    public static final String FCExternalLanguage.LANGUAGE_STRING         = "C";
3030    public static final String FFortran77ExternalLanguage.LANGUAGE_STRING = "FORTRAN 77";
3031    public static final String FBuiltinExternalLanguage.LANGUAGE_STRING   = "builtin";
3032   
3033    public FExternalLanguage SrcExternalLanguage.instantiate() {
3034        String lang = getLanguage();
3035        if (lang.equals(FCExternalLanguage.LANGUAGE_STRING))
3036            return new FCExternalLanguage();
3037        else if (lang.equals(FFortran77ExternalLanguage.LANGUAGE_STRING))
3038            return new FFortran77ExternalLanguage();
3039        else if (lang.equals(FBuiltinExternalLanguage.LANGUAGE_STRING))
3040            return new FBuiltinExternalLanguage();
3041        else 
3042            return new FUnknownExternalLanguage(lang);
3043    }
3044   
3045    public InstExternalCall SrcExternalFunctionCall.instantiate() {
3046        InstExternalCall res = new InstExternalCall();
3047        if (hasReturnVar())
3048            res.setReturnVar(getReturnVar().newInstAccess());
3049        res.setName(getFunctionName().name());
3050        for (SrcExp e : getArgs())
3051            res.addArg(e.instantiate());
3052        return res;
3053    }
3054   
3055    public static List SrcStatement.instantiateStatementList(List<SrcStatement> l) {
3056        List l2 = new List();
3057        for (SrcStatement s : l) 
3058            l2.add(s.instantiate());
3059        return l2;
3060    }
3061   
3062    public FStatement SrcStatement.instantiate() {
3063        FStatement s = instantiateStatement();
3064        s.setLocation(this);
3065        return s;
3066    }
3067   
3068    protected abstract FStatement SrcStatement.instantiateStatement();
3069   
3070    protected FAssignStmt SrcAssignStmt.instantiateStatement() {
3071        InstAccessExp left = new InstAccessExp(getLeft().newInstAccess());
3072        left.setLocation(this);
3073        return new FAssignStmt(left, getRight().instantiate());
3074    }
3075   
3076    protected FFunctionCallStmt SrcFunctionCallStmt.instantiateStatement() {
3077        List<FFunctionCallLeft> l = new List<FFunctionCallLeft>();
3078        for (SrcFunctionCallLeft a : getLefts()) 
3079            l.add(a.instantiate());
3080        return new FFunctionCallStmt(l, getSrcFunctionCall().instantiate());
3081    }
3082   
3083    protected FBreakStmt SrcBreakStmt.instantiateStatement() {
3084        return new FBreakStmt();
3085    }
3086   
3087    protected FReturnStmt SrcReturnStmt.instantiateStatement() {
3088        return new FReturnStmt();
3089    }
3090   
3091    protected FIfWhenStmt SrcIfWhenStmt.instantiateStatement() {
3092        List l = new List();
3093        for (SrcIfWhenClause c : getSrcIfWhenClauses()) 
3094            l.add(c.instantiate());
3095        return instantiateIfWhenStmt(l);
3096    }
3097   
3098    protected abstract FIfWhenStmt SrcIfWhenStmt.instantiateIfWhenStmt(List l);
3099   
3100    protected FIfStmt SrcIfStmt.instantiateIfWhenStmt(List icl) {
3101        List esl = new List();
3102        if (hasSrcElseClause()) {
3103            esl = SrcStatement.instantiateStatementList(getSrcElseClause().getStmts());
3104        }
3105        return new FIfStmt(icl, esl);
3106    }
3107   
3108    protected FWhenStmt SrcWhenStmt.instantiateIfWhenStmt(List l) {
3109        return new FWhenStmt(l);
3110    }
3111   
3112    public FIfWhenClause SrcIfWhenClause.instantiate() {
3113        FExp t = getTest().instantiate();
3114        List l = SrcStatement.instantiateStatementList(getSrcStatements());
3115        FIfWhenClause c = instantiateIfWhenClause(t, l);
3116        c.setLocation(this);
3117        return c;
3118    }
3119   
3120    protected abstract FIfWhenClause SrcIfWhenClause.instantiateIfWhenClause(FExp t, List l);
3121   
3122    protected FIfClause SrcIfClause.instantiateIfWhenClause(FExp t, List l) {
3123        return new FIfClause(t, l);
3124    }
3125   
3126    protected FWhenClause SrcWhenClause.instantiateIfWhenClause(FExp t, List l) {
3127        return new FWhenClause(t, l);
3128    }
3129   
3130   
3131    protected InstForStmt SrcForStmt.instantiateStatement() {
3132        List il = new List();
3133        for (SrcForIndex i : getSrcForIndexList()) 
3134            il.add(i.instantiate());
3135        List sl = SrcStatement.instantiateStatementList(getSrcStatementList());
3136        return new InstForStmt(il, sl);
3137    }
3138   
3139    protected FWhileStmt SrcWhileStmt.instantiateStatement() {
3140        List l = SrcStatement.instantiateStatementList(getSrcWhileStmts());
3141        return new FWhileStmt(getTest().instantiate(), l);
3142    }
3143
3144    public FArrayExpSubscripts SrcArraySubscripts.instantiate() {
3145        List l = new List();
3146        for (SrcSubscript s : getSrcSubscripts())
3147            l.add(s.instantiate());
3148        return copyLocationTo(new FArrayExpSubscripts(l));
3149    }
3150   
3151    abstract public FSubscript SrcSubscript.instantiate();
3152    public FSubscript SrcColonSubscript.instantiate() { 
3153        return copyLocationTo(new FColonSubscript());
3154    }
3155   
3156    public FSubscript SrcExpSubscript.instantiate() {
3157        return copyLocationTo(getSrcExp().instantiate().createFSubscript());
3158    }
3159   
3160    public FExp SrcExp.instantiate() {
3161        return copyLocationTo(new FUnsupportedExp());
3162    }
3163
3164   
3165    public InstDerExp SrcDerExp.instantiate() {
3166        return copyLocationTo(new InstDerExp(getSrcExp().instantiate()));
3167    }
3168
3169    public FExp SrcParExp.instantiate() {
3170        return getSrcExp().instantiate();
3171    }
3172
3173    public FExp SrcAccessExp.instantiate() {
3174        return copyLocationTo(new InstAccessExp(getSrcAccess().newInstAccess()));
3175    }
3176
3177
3178    public InstAccess SrcAccess.instantiate() { 
3179        return copyLocationTo(newInstAccess());
3180    }
3181
3182    public FExp SrcArrayConstructor.instantiate() {
3183       List l = new List();
3184       for (SrcExp e : getSrcFunctionArguments().getSrcExps())
3185           l.add(e.instantiate());
3186       return copyLocationTo(new FArray(l));
3187    }
3188   
3189    public FExp SrcIterExp.instantiate() {
3190        List<CommonForIndex> ifil = new List<CommonForIndex>();
3191        // Add indices backwards, since they should be interpreted in the opposite order compared to for loops
3192        for (int i = getNumSrcForIndex() - 1; i >= 0; i--)
3193            ifil.add(getSrcForIndex(i).instantiate());
3194        return copyLocationTo(new FIterExp(getSrcExp().instantiate(), ifil));
3195    }
3196
3197    public FExp SrcRangeExp.instantiate() {
3198        List l = new List();
3199        for (SrcExp e : getSrcExps()) 
3200            l.add(e.instantiate());
3201        return copyLocationTo(new FRangeExp(l));
3202    }
3203
3204    public FExp SrcIfExp.instantiate() {
3205        InstIfExp n = new InstIfExp(getSrcIfExp().instantiate(),
3206                                    getThenExp().instantiate(),
3207                                    getElseExp().instantiate());
3208        return copyLocationTo(n);
3209    }
3210
3211    public FExp SrcMatrix.instantiate() {
3212        FMatrix m = new FMatrix();
3213        for (SrcMatrixRow r : getRows())
3214            m.addFExp(r.instantiate());
3215        return copyLocationTo(m);
3216    }
3217   
3218    public FMatrixRow SrcMatrixRow.instantiate() {
3219        FMatrixRow r = new FMatrixRow();
3220        for (SrcExp e : getSrcExps())
3221            r.addFExp(e.instantiate());
3222        return copyLocationTo(r);
3223    }
3224   
3225    public FExp SrcAddExp.instantiate() { 
3226        return copyLocationTo(new FAddExp(getLeft().instantiate(),getRight().instantiate()));
3227    }
3228   
3229    public FExp SrcSubExp.instantiate() { 
3230        return copyLocationTo(new FSubExp(getLeft().instantiate(),getRight().instantiate()));
3231    }
3232
3233    public FExp SrcMulExp.instantiate() { 
3234        return copyLocationTo(new FMulExp(getLeft().instantiate(),getRight().instantiate()));
3235    }
3236   
3237    public FExp SrcDivExp.instantiate() { 
3238        return copyLocationTo(new FDivExp(getLeft().instantiate(),getRight().instantiate()));
3239    }
3240   
3241    public FExp SrcPowExp.instantiate() { 
3242        return copyLocationTo(new FPowExp(getLeft().instantiate(),getRight().instantiate()));
3243    }
3244   
3245    public FExp SrcDotAddExp.instantiate() { 
3246        return copyLocationTo(new FDotAddExp(getLeft().instantiate(),getRight().instantiate()));
3247    }
3248   
3249    public FExp SrcDotSubExp.instantiate() { 
3250        return copyLocationTo(new FDotSubExp(getLeft().instantiate(),getRight().instantiate()));
3251    }
3252
3253    public FExp SrcDotMulExp.instantiate() { 
3254        return copyLocationTo(new FDotMulExp(getLeft().instantiate(),getRight().instantiate()));
3255    }
3256   
3257    public FExp SrcDotDivExp.instantiate() { 
3258        return copyLocationTo(new FDotDivExp(getLeft().instantiate(),getRight().instantiate()));
3259    }
3260   
3261    public FExp SrcDotPowExp.instantiate() { 
3262        return copyLocationTo(new FDotPowExp(getLeft().instantiate(),getRight().instantiate()));
3263    }
3264   
3265    public FExp SrcNegExp.instantiate() { 
3266        return copyLocationTo(new FNegExp(getSrcExp().instantiate()));
3267    }
3268
3269    public FExp SrcLtExp.instantiate() { 
3270        return copyLocationTo(new FLtExp(getLeft().instantiate(),getRight().instantiate()));
3271    }
3272
3273    public FExp SrcLeqExp.instantiate() { 
3274        return copyLocationTo(new FLeqExp(getLeft().instantiate(),getRight().instantiate()));
3275    }
3276   
3277    public FExp SrcGtExp.instantiate() { 
3278        return copyLocationTo(new FGtExp(getLeft().instantiate(),getRight().instantiate()));
3279    }
3280   
3281    public FExp SrcGeqExp.instantiate() { 
3282        return copyLocationTo(new FGeqExp(getLeft().instantiate(),getRight().instantiate()));
3283    }
3284   
3285    public FExp SrcEqExp.instantiate() { 
3286        return copyLocationTo(new FEqExp(getLeft().instantiate(),getRight().instantiate()));
3287    }
3288   
3289    public FExp SrcNeqExp.instantiate() { 
3290        return copyLocationTo(new FNeqExp(getLeft().instantiate(),getRight().instantiate()));
3291    }
3292   
3293    public FExp SrcNotExp.instantiate() { 
3294        return copyLocationTo(new FNotExp(getSrcExp().instantiate()));
3295    }
3296   
3297    public FExp SrcOrExp.instantiate() { 
3298        return copyLocationTo(new FOrExp(getLeft().instantiate(),getRight().instantiate()));
3299    }
3300   
3301    public FExp SrcAndExp.instantiate() { 
3302        return copyLocationTo(new FAndExp(getLeft().instantiate(),getRight().instantiate()));
3303    }
3304
3305    public FExp SrcRealLitExp.instantiate() {
3306        double value = Double.parseDouble(getUNSIGNED_NUMBER());
3307        return copyLocationTo(new FRealLitExp(value));
3308    }
3309   
3310    public FExp SrcIntegerLitExp.instantiate() { 
3311        try {
3312            int value = Integer.parseInt(getUNSIGNED_INTEGER());
3313            return copyLocationTo(new FIntegerLitExp(value));
3314        } catch (NumberFormatException e) {
3315            double value = Double.parseDouble(getUNSIGNED_INTEGER());
3316            return copyLocationTo(new FOverflowIntLitExp(value, getUNSIGNED_INTEGER()));
3317        }
3318    }
3319   
3320    public FExp SrcStringLitExp.instantiate() { 
3321        return copyLocationTo(new FStringLitExp(getSTRING()));
3322    }
3323   
3324    public FExp SrcBooleanLitExpTrue.instantiate() { 
3325        return copyLocationTo(new FBooleanLitExpTrue());
3326    }
3327   
3328    public FExp SrcBooleanLitExpFalse.instantiate() { 
3329        return copyLocationTo(new FBooleanLitExpFalse());
3330    }
3331   
3332    public FExp SrcTimeExp.instantiate() { 
3333        return copyLocationTo(new FTimeExp());
3334    }   
3335
3336    public FExp SrcEndExp.instantiate() { 
3337        return copyLocationTo(new FEndExp());
3338    }
3339   
3340    public InstNamedArgument SrcNamedArgument.instantiate() {
3341        return copyLocationTo(new InstNamedArgument(getSrcExp().instantiate(), getName().instantiate()));
3342    }
3343   
3344    protected FAbstractFunctionCall SrcFunctionCall.createInstNode(InstAccess name, List<InstFunctionArgument> args) {
3345        return new InstFunctionCall(name, args);
3346    }
3347   
3348    protected FAbstractFunctionCall SrcPartialFunctionCall.createInstNode(InstAccess name, List<InstFunctionArgument> args) {
3349        return new InstPartialFunctionCall(name, args);
3350    }
3351   
3352    public FAbstractFunctionCall SrcFunctionCall.instantiate() {
3353        // Instantiate arguments
3354        List<InstFunctionArgument> args = new List<InstFunctionArgument>();
3355        if (hasSrcFunctionArguments()) {
3356            int i = 0;
3357            for (SrcExp arg : getSrcFunctionArguments().getSrcExpList()) {
3358                InstPositionalArgument iarg = new InstPositionalArgument(arg.instantiate(), i++);
3359                iarg.setLocation(arg);
3360                args.add(iarg);
3361            }
3362            for (SrcNamedArgument arg : getSrcFunctionArguments().getSrcNamedArguments())
3363                args.add(arg.instantiate());
3364        }
3365       
3366        // Create InstFunctionCall
3367        return copyLocationTo(createInstNode(getName().newInstAccess(), args));
3368    }
3369
3370    public InstForIndex SrcForIndex.instantiate() {
3371        InstForIndexPrimitive ip = new InstForIndexPrimitive(getSrcForIndexDecl().name(), 
3372                new InstParseAccess("Integer"), new Opt<FArraySubscripts>(), getSrcForIndexDecl(), 
3373                new Opt<InstModification>(), new Opt<InstConstrainingComponent>(), new Opt<FExp>());
3374        InstForIndex res;
3375        if (hasSrcExp()) {
3376            res = new InstForIndexWithExp(ip, getSrcExp().instantiate());
3377        } else {
3378            res = new InstForIndexNoExp(ip);
3379        }
3380        return copyLocationTo(res);
3381    }
3382   
3383    public InstForClauseE SrcForClauseE.instantiate() {
3384        List<InstForIndex> forIndex = new List();
3385        List<FAbstractEquation> eqns = new List();
3386        for (SrcForIndex fi : getSrcForIndexs()) {
3387            forIndex.add(fi.instantiate());     
3388        }
3389        for (SrcAbstractEquation ae : getSrcAbstractEquations()) {
3390            eqns.add(ae.instantiate());
3391        }
3392        return copyStringComment(new InstForClauseE(equationType(), forIndex, eqns));
3393    }
3394
3395}
3396
3397aspect AttributeContributor {
3398   
3399    /**
3400     * Class used during instantiation of equations and flattening of variables
3401     * to delegate to different contributors. This class is subtyped for each
3402     * contributor.
3403     */
3404    public abstract class AttributeContributor {
3405        private final String name;
3406
3407        public AttributeContributor(String name) {
3408            this.name = name;
3409        }
3410
3411        /**
3412         * This method is called during instantiation when an equation is
3413         * created.
3414         * Instance accesses are expected if component references are made.
3415         */
3416        protected void contribute(SrcAbstractEquation src, FAbstractEquation dest) {}
3417
3418        /**
3419         * This method is called during flattening of components. All
3420         * expressions that are added must be flattened.
3421         */
3422        protected void contribute(Flattener f, InstAssignable src, FVariable dest) {}
3423
3424        /**
3425         * This method is called during flattening of functions. All
3426         * expressions that are added must be flattened.
3427         */
3428        protected void contribute(Flattener f, InstBaseClassDecl src, FFunctionDecl dest) {}
3429
3430        /**
3431         * This method is called during flattening of the model. All
3432         * expressions that are added must be flattened.
3433         */
3434        protected void contribute(Flattener f, InstNode src, FClass dest) {}
3435
3436        /**
3437         * This method is called during flattening of external statements. All
3438         * expressions that are added must be flattened.
3439         */
3440        protected void contribute(AnnotationNode src, FExternalStmt dest) {}
3441
3442        /**
3443         * This method is called in order to determine if an attribute should
3444         * be considered as active. Return true if the attributes that was
3445         * added earlier alters the models behaviour.
3446         */
3447        protected boolean containsActiveAttributes(FAbstractEquation equation) { return false; }
3448
3449        /**
3450         * This method is called in order to determine if an attribute should
3451         * be considered as active. Return true if the attributes that was
3452         * added earlier alters the models behaviour.
3453         */
3454        protected boolean containsActiveAttributes(FVariable variable) { return false; }
3455
3456        /**
3457         * This method is called in order to determine if an attribute should
3458         * be considered as active. Return true if the attributes that was
3459         * added earlier alters the models behaviour.
3460         */
3461        protected boolean containsActiveAttributes(FFunctionDecl function) { return false; }
3462
3463        /**
3464         * This method is called in order to determine if an attribute should
3465         * be considered as active. Return true if the attributes that was
3466         * added earlier alters the models behaviour.
3467         */
3468        protected boolean containsActiveAttributes(FClass fClass) { return false; }
3469
3470        @Override
3471        public String toString() {
3472            return name;
3473        }
3474    }
3475
3476    /**
3477     * A list that contains all attribute contributors. New contributors are added
3478     * dynamically during static evaluation by calling addAttributeContributor().
3479     *
3480     * @see ASTNode.addAttributeContributor()
3481     */
3482    private static Collection<AttributeContributor> ASTNode.ATTRIBUTE_CONTRIBUTES;
3483   
3484    /**
3485     * Add InstantiationContributor to the list of contributors. This method
3486     * should only be called from SrcAbstractEquation in order to ensure that the
3487     * checker is added corretly during static evaluation, hence the private
3488     * visibility.
3489     */
3490    private static AttributeContributor ASTNode.addAttributeContributor(AttributeContributor contributor) {
3491        if (ATTRIBUTE_CONTRIBUTES == null)
3492            ATTRIBUTE_CONTRIBUTES = new ArrayList<AttributeContributor>();
3493        ATTRIBUTE_CONTRIBUTES.add(contributor);
3494        return contributor;
3495    }
3496   
3497    public static Collection<AttributeContributor> ASTNode.attributeContributors() {
3498        return Collections.unmodifiableCollection(ATTRIBUTE_CONTRIBUTES);
3499    }
3500   
3501    public class SrcAbstractEquation {
3502        public <N extends FAbstractEquation> N contribute(N equation) {
3503            for (AttributeContributor contributor : attributeContributors())
3504                contributor.contribute(this, equation);
3505            return equation;
3506        }
3507    }
3508   
3509    public class InstAssignable {
3510        public <N extends FVariable> N contribute(Flattener f, N variable) {
3511            for (AttributeContributor contributor : attributeContributors())
3512                contributor.contribute(f, this, variable);
3513            return variable;
3514        }
3515    }
3516   
3517    public class InstBaseClassDecl {
3518        public <N extends FFunctionDecl> N contribute(Flattener f, N function) {
3519            for (AttributeContributor contributor : attributeContributors())
3520                contributor.contribute(f, this, function);
3521            return function;
3522        }
3523    }
3524   
3525    public class InstNode {
3526        public FClass contribute(Flattener f, FClass fClass) {
3527            for (AttributeContributor contributor : attributeContributors())
3528                contributor.contribute(f, this, fClass);
3529            return fClass;
3530        }
3531    }
3532   
3533    public class InstExternal {
3534        public FExternalStmt contribute(FExternalStmt stmt) {
3535            for (AttributeContributor contributor : attributeContributors()) {
3536                contributor.contribute(annotation(), stmt);
3537            }
3538            return stmt;
3539        }
3540    }
3541   
3542    public class FExternalStmt {
3543        public FExternalStmt contribute(FExternalStmt stmt) {
3544            for (AttributeContributor contributor : attributeContributors()) {
3545                contributor.contribute(annotation(), stmt);
3546            }
3547            return stmt;
3548        }
3549    }
3550   
3551}
3552
3553aspect ComponentCount {
3554    private int FClass.numComponents = 0;
3555
3556    protected void FClass.countComponent() {
3557        numComponents++;
3558    }
3559
3560    public int FClass.numberOfComponents() {
3561        return numComponents;
3562    }
3563}
3564
Note: See TracBrowser for help on using the repository browser.