source: branches/dev-5819/Compiler/ModelicaFrontEnd/src/jastadd/flattening/connections/ExpandableConnectors.jrag @ 13800

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

#5819 Merged trunk into branch

File size: 53.4 KB
Line 
1/*
2    Copyright (C) 2013 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
17aspect ExpandableConnectors {
18   
19    public class ExpandableConnectorSets {
20       
21        private Map<InstComponentDecl,ExpandableSet> map;
22        private Set<ExpandableSet> sets;
23        private java.util.List<Connection> connections;
24        private java.util.List<InstAccess> uses;
25        private boolean expansionDone;
26
27       
28        public ExpandableConnectorSets() {
29            map = new LinkedHashMap<>();
30            sets = new LinkedHashSet<>();
31            connections = new ArrayList<>();
32            uses = new ArrayList<>();
33            expansionDone = false;
34        }
35       
36        /**
37         * Calculate the components present in each expandable connector and apply connections
38         * involving them.
39         */
40        public void elaborate(ConnectionSetManager csm) {
41            boolean ok = true;
42            for (ExpandableSet set : sets()) 
43                set.addNested();
44            for (ExpandableSet set : sets()) 
45                if (!set.expand())
46                    ok = false;
47           
48            if (ok) {
49                expansionDone = true;
50                for (Connection conn : connections) {
51                    conn.connect(csm);
52                }
53                for (InstComponentDecl icd : map.keySet()) {
54                    icd.buildConnectionSets(null, csm, true);
55                    icd.getInstComponentDecls().collectErrors(ErrorCheckType.GENERATED);
56                }
57                for (InstAccess use : uses) {
58                    use.flushAllRecursiveClearFinal();
59                    if (use.myInstComponentDecl().isUnknown()) {
60                        // TODO: Improve error message and move to new problem framework
61                        use.error("Using member of expandable connector is only allowed if the member is connected to in the connection set");
62                    }
63                }
64            }
65        }
66       
67        /**
68         * Add an expandable connector to sets.
69         */
70        public void addConnector(InstComponentDecl conn) {
71            setFor(conn);
72        }
73       
74        /**
75         * Add a use of a member of an expandable connector.
76         */
77        public void addUse(InstAccess use) {
78            uses.add(use);
79        }
80
81        /**
82         * Add information about a connection introducing a new component to an expandable connector.
83         */
84        public void addIntroducingConnection(InstAccess unknown, InstAccess known,
85                FAccess prefix, ConnectionEdge source) {
86            InstAccess expPart = unknown.findExpandableConnectorPart();
87            InstAccess unknownPart = expPart.getNextInstAccess();
88            if (expPart.combinedNdims() > 0) {
89                Indices knownInd = known.indices();
90                Indices expInd = expPart.combinedIndices();
91                Size size = known.size().contract(expInd.ndims(), 0);
92                for (Index i : expInd) {
93                    Index iKnown = knownInd.translate(i);
94                    Index iExp = expInd.translate(i);
95                    InstComponentDecl cellKnown = known.lookupWithIndex(iKnown);
96                    InstComponentDecl cellExp   = expPart.lookupAsPartWithIndex(iExp);
97                    addIntroducingConnectionForCell(unknown, unknownPart, cellKnown, known, cellExp, size);
98                }
99            } else {
100                InstComponentDecl expandable = expPart.findReferencedExpandableConnector();
101                addIntroducingConnectionForCell(unknown, unknownPart, 
102                        known.lookupEvaluatingIndices(), known, expandable, null);
103            }
104            connections.add(new Connection(prefix, source));
105       }
106
107        private void addIntroducingConnectionForCell(
108                InstAccess unknown, InstAccess unknownPart, InstComponentDecl knownComp, 
109                InstAccess known, InstComponentDecl expandable, Size knownSize) {
110            ExpandableSet set = setFor(expandable);
111            set.addMember(knownComp, known, unknown, unknownPart, knownSize);
112        }
113
114        /**
115         * Add information about a connection between two expandable connectors.
116         */
117        public void addSpanningConnection(InstComponentDecl leftComp, InstComponentDecl rightComp,
118                FAccess prefix, ConnectionEdge source) {
119            connectExpandableConnectors(leftComp, rightComp);
120            connections.add(new Connection(prefix, source));
121        }
122
123        /**
124         * Check if elaboration is already done.
125         */
126        public boolean isExpansionDone() {
127            return expansionDone;
128        }
129       
130        private void connectExpandableConnectors(InstComponentDecl leftComp, InstComponentDecl rightComp) {
131            if (!leftComp.isArray()) {
132                setFor(leftComp).mergeFor(rightComp);
133            }
134           
135            SortedSet<InstComponentDecl> rightChildren = rightComp.containedInstComponents();
136            for (InstComponentDecl leftChild : leftComp.containedInstComponents()) {
137                if (leftChild.isExpandableConnector() && rightChildren.contains(leftChild)) {
138                    InstComponentDecl rightChild = rightChildren.tailSet(leftChild).first();
139                    if (rightChild.isExpandableConnector())
140                        connectExpandableConnectors(leftChild, rightChild);
141                }
142            }
143        }
144       
145        /**
146         * Add a new binding to the map and the list of sets to process.
147         */
148        private void bind(InstComponentDecl conn, ExpandableSet set) {
149            map.put(conn, set);
150            sets.add(set);
151        }
152       
153        private ExpandableSet setFor(InstComponentDecl comp) {
154            InstComponentDecl org = comp.duplicateOriginal();
155            ExpandableSet set = map.get(org);
156            if (set == null) {
157                set = new ExpandableSet(org);
158            }
159            if (org != comp) {
160                set.addConnector(comp);
161            }
162            return set;
163        }
164
165        private Iterable<ExpandableSet> sets() {
166            return new GrowableSetIterable(sets);
167        }
168
169        private class Connection {
170           
171            public final FAccess prefix;
172            public final FConnectClause source;
173            private EvaluationValueCache values;
174           
175            public Connection(FAccess prefix, ConnectionEdge source) {
176                this.prefix = prefix;
177                this.source = (FConnectClause) source;
178                values = new EvaluationValueCache(this.source);
179            }
180           
181            public void connect(ConnectionSetManager csm) {
182                source.flushAllRecursiveClearFinal(); // Depends on FConnectClause not resetting is$Final
183                values.apply();
184                source.buildConnectionSets(prefix, csm, true);
185                values.reset();
186            }
187           
188            public String toString() {
189                return source.toString();
190            }
191           
192        }
193       
194        private class ExpandableSet {
195           
196            private Set<InstComponentDecl> connectors;
197            private Set<ExpandableSet> parentSets;
198            private Map<String,ConnectorMember> members;
199            private Map<ConnectorMember,Index> owningMembers;
200            private ExpandableSet replacement = null;
201            private boolean expanded;
202            private boolean nestedDone;
203            private boolean isOk;
204           
205            public ExpandableSet() {
206                connectors = new LinkedHashSet<>();
207                parentSets = new HashSet<>();
208                members = new HashMap<>();
209                owningMembers = new HashMap<>();
210                expanded = false;
211                nestedDone = false;
212                isOk = true;
213            }
214           
215            public ExpandableSet(InstComponentDecl connector) {
216                this();
217                addConnector(connector);
218            }
219           
220            public ExpandableSet(ConnectorMember member, Index i) {
221                this();
222                owningMembers.put(member, i);
223            }
224           
225            /**
226             * Calculate the components present in each expandable connector, if not already done.
227             *
228             * @return  <code>false</code> if any errors were found
229             */
230            public boolean expand() {
231                if (!expanded) {
232                    expanded = true;
233                    for (ExpandableSet parentSet : parentSets()) {
234                        parentSet.expand();
235                    }
236                   
237                    ConnectorMember[] sorted = members.values().toArray(new ConnectorMember[members.size()]);
238                    Arrays.sort(sorted);
239                    for (ConnectorMember member : sorted) {
240                        isOk = member.check() && isOk;
241                    }
242                    if (isOk) { 
243                        for (InstComponentDecl conn : connectors()) {
244                            expandConnector(conn, sorted);
245                        }
246                    }
247                }
248                return isOk;
249            }
250
251            private Iterable<InstComponentDecl> connectors() {
252                return new GrowableSetIterable(connectors);
253            }
254
255            /**
256             * Add all nested expandable connector to their parent's sets.
257             */
258            public void addNested() {
259                if (!nestedDone && !members.isEmpty()) {
260                    nestedDone = true;
261                    for (InstComponentDecl conn : connectors) {
262                        InstComponentDecl p = conn.findExpandableAncestor();
263                        if (p != null) {
264                            InstComponentDecl c = conn.ancestorChild(p, conn);
265                            ExpandableSet set = setFor(p);
266                            set.addDeclared(c.name());
267                            set.addNested();
268                        }
269                    }
270                }
271            }
272           
273            /**
274             * Merge two sets of expandable connectors, keeping this one.
275             */
276            public void merge(ExpandableSet other) {
277                // TODO: Keep a record of who has references to the set, and update references
278                //       on merge instead of using actual(). Maybe using a redirection object?
279                if (other == null || other == this)
280                    return;
281               
282                for (InstComponentDecl conn : other.connectors) {
283                    addConnector(conn);
284                }
285                other.replaceWith(this);
286               
287                parentSets().addAll(other.parentSets());
288               
289                for (ConnectorMember member : other.members.values()) {
290                    ConnectorMember local = members.get(member.name);
291                    if (local == null) {
292                        local = new ConnectorMember(member);
293                        local.addParentSet(this);
294                        members.put(local.name, local);
295                    } else {
296                        local.merge(member);
297                    }
298                    local.removeParentSet(other);
299                }
300               
301                for (Map.Entry<ConnectorMember,Index> entry : other.owningMembers.entrySet()) {
302                    ConnectorMember member = entry.getKey();
303                    Index i = entry.getValue();
304                    owningMembers.put(member, i);
305                    member.replaceSet(i, this);
306                }
307            }
308           
309            /**
310             * Add <code>comp</code> as a connector and merge any set for it.
311             */
312            public void mergeFor(InstComponentDecl comp) {
313                ExpandableSet other = map.get(comp);
314                if (other == null) {
315                    addConnector(comp);
316                } else {
317                    merge(other);
318                }
319            }
320           
321            private ExpandableSet actual() {
322                if (replacement == null) {
323                    return this;
324                } else {
325                    replacement = replacement.actual();
326                    return replacement;
327                }
328            }
329           
330            private void replaceWith(ExpandableSet other) {
331                replacement = other.actual();
332                // Don't process this set
333                expanded = true;
334                nestedDone = true;
335            }
336           
337            /**
338             * Add a member to the connectors of the set, possibly as expandable connector members
339             * that members are recursively added to.
340             */
341            public void addMember(InstComponentDecl knownComp, InstAccess known, 
342                    InstAccess unknown, InstAccess unknownPart, Size sourceSize) {
343                String name = unknownPart.name();
344                ConnectorMember member = members.get(name);
345                if (unknownPart == unknown.getLastInstAccess()) {
346                    FArraySubscripts fas = unknownPart.hasFArraySubscripts() ? unknownPart.getFArraySubscripts() : null;
347                    if (member == null) {
348                        member = new ConnectorMember(name, knownComp, known, fas, sourceSize, unknownPart);
349                        members.put(name, member);
350                    } else {
351                        member.addConnection(knownComp, known, fas, sourceSize, unknownPart);
352                    }
353                } else {
354                    if (member == null) {
355                        // TODO: isn't size/fas/etc needed here?
356                        member = new ConnectorMember(name, unknown);
357                        members.put(name, member);
358                    }
359                    // TODO: what is sourceSize in this case? probably shouldn't just toss it
360                    Indices indices = unknownPart.accessIndices();
361                    for (Index i : indices) {
362                        member.set(i).addMember(knownComp, known, unknown, unknownPart.getNextInstAccess(), null);
363                    }
364                }
365                member.addParentSet(actual());
366            }
367           
368            /**
369             * Add a declared member to the connectors of the set.
370             *
371             * This is only used to include nested expandable connectors.
372             */
373            public void addDeclared(String name) {
374                ConnectorMember member = members.get(name);
375                if (member == null) {
376                    members.put(name, new ConnectorMember(name, true));
377                }
378            }
379           
380            /**
381             * Add a duplicate version of the expandable connector.
382             *
383             * All encountered duplicate versions are expanded.
384             */
385            public void addConnector(InstComponentDecl connector) {
386                connectors.add(connector);
387                bind(connector, this);
388            }
389           
390            /**
391             * Add another set as a parent to this one.
392             *
393             * All parent sets will be expanded before this one.
394             */
395            public void addParentSet(ExpandableSet parentSet) {
396                parentSets.add(parentSet);
397            }
398
399            /**
400             * Remove another set from list of parents.
401             */
402            public void removeParentSet(ExpandableSet parentSet) {
403                parentSets.remove(parentSet);
404            }
405           
406            /**
407             * Get the list of sets that need to be expanded before this one,
408             * updated for replacements.
409             */
410            private Set<ExpandableSet> parentSets() {
411                // TODO: Cluncy, update existing set instead
412                boolean replace = false;
413                for (ExpandableSet parent : parentSets) {
414                    replace |= parent.replacement != null;
415                }
416                if (replace) {
417                    Set<ExpandableSet> replacement = new HashSet<>();
418                    for (ExpandableSet parent : parentSets) {
419                        replacement.add(parent.actual());
420                    }
421                    parentSets = replacement;
422                }
423                return parentSets;
424            }
425           
426            /**
427             * Create a list with the components each connector in this set should have.
428             *
429             * @param members  the members of this set, sorted by name
430             */
431            public void expandConnector(InstComponentDecl parent, ConnectorMember[] members) {
432                List<InstComponentDecl> memberList = new List<InstComponentDecl>();
433                memberList.setParent(parent); // Make sure inherited attributes work at once
434                InstComponentDecl[] templates = new InstComponentDecl[members.length];
435                int i = 0;
436                for (ConnectorMember member : members) {
437                    memberList.add(member.createInstComponent(parent));
438                    templates[i++] = member.template(parent);
439                }
440                // TODO: If there were declared expandable members, we should probably remove
441                //       them from their sets after merging.
442                parent.expandConnector(memberList, templates);
443                i = 0;
444                for (ConnectorMember member : members) {
445                    member.connectExpandableMember(parent.getInstComponentDecl(i++));
446                }
447            }
448           
449            /**
450             * Check if the given expandable set describes a set of connectors that will contain
451             * one of the connectors described by this set (directly or indirectly).
452             */
453            private boolean isOrAncestor(ExpandableSet other) {
454                return other == this || isOrAncestorHelper(other, new HashSet<ExpandableSet>());
455            }
456           
457            private boolean isOrAncestorHelper(ExpandableSet other, Set<ExpandableSet> visited) {
458                /* If we have already been here, we either have a loop among the ancestors,
459                 * or a diamond pattern in the graph. Neither case means that there is a loop
460                 * involving other.
461                 */
462                if (visited.add(this)) {
463                    for (ExpandableSet parent : parentSets) {
464                        if (parent == other || parent.isOrAncestorHelper(other, visited)) {
465                            return true;
466                        }
467                    }
468                }
469                return false;
470            }
471           
472            public String toString() {
473                StringBuilder buf = new StringBuilder("Connectors:");
474                for (InstComponentDecl c : connectors) {
475                    buf.append("\n  ");
476                    buf.append(c.qualifiedName());
477                }
478                buf.append("\nMembers:");
479                for (ConnectorMember m : members.values()) {
480                    buf.append("\n  ");
481                    buf.append(m.name);
482                }
483                return buf.toString();
484            }
485           
486            private class ConnectorMember implements Comparable<ConnectorMember> {
487               
488                public final String name;
489                private Map<Index,ExpandableSet> sets;
490                private java.util.List<Source> sources;
491                private java.util.List<InstAccess> nestledAccesses;
492                private InstComponentDecl template;
493                private Map<InstComponentDecl,InstComponentDecl> templateMap;
494                private FArraySubscripts subscripts;
495                private boolean error;
496                private boolean calculated;
497                private boolean isExpandable;
498               
499                public ConnectorMember(String name, boolean expandable) {
500                    this.name = name;
501                    sources = new ArrayList<Source>(4);
502                    nestledAccesses = new ArrayList<InstAccess>(2);
503                    template = null;
504                    templateMap = null;
505                    subscripts = null;
506                    calculated = false;
507                    error = false;
508                    sets = new HashMap<>();
509                    isExpandable = expandable;
510                }
511               
512                public ConnectorMember(String name, InstComponentDecl targetComp, 
513                        InstAccess target, FArraySubscripts fas, Size targetSize, InstAccess unknownPart) {
514                    this(name, false);
515                    addConnection(targetComp, target, fas, targetSize, unknownPart);
516                }
517               
518                public ConnectorMember(String name, InstAccess unknown) {
519                    this(name, true);
520                    nestledAccesses.add(unknown);
521                }
522               
523                public ConnectorMember(ConnectorMember other) {
524                    this(other.name, false);
525                    merge(other);
526                }
527               
528                public int compareTo(ConnectorMember other) {
529                    return name.compareTo(other.name);
530                }
531               
532                public void addConnection(InstComponentDecl targetComp, 
533                        InstAccess target, FArraySubscripts fas, Size targetSize, InstAccess unknownPart) {
534                    sources.add(new Source(targetComp, target, fas, targetSize));
535                    if (targetComp.isExpandableConnector()) {
536                        Indices indices = unknownPart.accessIndices();
537                        if (indices.ndims() == 0 && target.isArray()) {
538                            indices = target.indices(); // TODO: This is not correct if first part of unknown is an array,
539                                                        // if so, some of the dimensions should be contracted, (use targetSize instead?)
540                        }
541                        for (Index i : indices) {
542                            Index ti = indices.translate(i);
543                           
544                            // TODO: This is not always correct, targetComp may already be specified.
545                            // Only specify if target is slice? Or if target is array?
546                            InstComponentDecl specified = targetComp.specify(ti);
547                           
548                            ExpandableSet otherSet = map.get(specified);
549                            if (otherSet == null) {
550                                set(i).addConnector(specified);
551                            } else {
552                                mergeSet(otherSet, i);
553                            }
554                        }
555                    }
556                }
557               
558                public void merge(ConnectorMember other) {
559                    if (isExpandable || other.isExpandable) {
560                        for (Index i : other.sets.keySet()) {
561                            mergeSet(other.sets.get(i), i);
562                        }
563                        nestledAccesses.addAll(other.nestledAccesses);
564                        isExpandable = true;
565                    }
566                    for (Source s : other.sources) {
567                        sources.add(new Source(s));
568                    }
569                }
570               
571                private void mergeSet(ExpandableSet otherSet, Index i) {
572                    ExpandableSet set = sets.put(i, otherSet);
573                    if (set != null) {
574                        otherSet.merge(set);
575                    }
576                    isExpandable = true;
577                }
578               
579                public ExpandableSet set(Index i) {
580                    ExpandableSet set = sets.get(i);
581                    if (set == null) {
582                        i = i.fix();
583                        set = new ExpandableSet(this, i);
584                        sets.put(i, set);
585                        isExpandable = true;
586                    }
587                    return set.actual();
588                }
589               
590                public void replaceSet(Index i, ExpandableSet newSet) {
591                    sets.put(i, newSet);
592                }
593               
594                public void addParentSet(ExpandableSet parentSet) {
595                    for (ExpandableSet set : sets.values()) {
596                        set.addParentSet(parentSet);
597                    }
598                }
599               
600                public void removeParentSet(ExpandableSet parentSet) {
601                    for (ExpandableSet set : sets.values()) {
602                        set.removeParentSet(parentSet);
603                    }
604                }
605               
606                /**
607                 * Check if all connections to this member are consistent.
608                 *
609                 * @return  <code>false</code> if any errors were found
610                 */
611                public boolean check() {
612                    if (!calculated)
613                        calculateVariable();
614                    return !error;
615                }
616               
617                /**
618                 * Is this an array member?
619                 */
620                public boolean isArray() {
621                    return subscripts() != null && subscripts.ndims() > 0;
622                }
623               
624                public InstComponentDecl createInstComponent(InstComponentDecl parent) {
625                    InstComponentDecl tmpl = template(parent);
626                    InstComponentDecl res;
627                    if (tmpl.name().equals(name) && tmpl.isChildOf(parent)) {
628                        if (subscripts() != null) {
629                            tmpl.setLocalFArraySubscripts(subscripts());
630                        }
631                        res = tmpl;
632                    } else {
633                        SrcComponentDecl cd = tmpl.getSrcComponentDecl();
634                        res = tmpl.myInstClass().newInstComponentDeclCopy(
635                                name, subscripts(), cd, cd.getClassName());
636                    }
637                    return res;
638                    // TODO: handle input/output (or is that really needed?)
639                }
640               
641                public void connectExpandableMember(InstComponentDecl created) {
642                    if (isExpandable) {
643                        for (Source s : sources) {
644                            s.connectExpandableMember(created);
645                        }
646                        for (Index i : created.indices()) {
647                            set(i).mergeFor(created.arrayCell(i));
648                        }
649                    }
650                }
651               
652                private InstComponentDecl template(InstComponentDecl parent) {
653                    if (!calculated) {
654                        calculateVariable();
655                    }
656                    if (templateMap != null) {
657                        InstComponentDecl declared = templateMap.get(parent);
658                        if (declared != null) {
659                            return declared;
660                        }
661                    }
662                    return template;
663                }
664               
665                private FArraySubscripts subscripts() {
666                    if (!calculated)
667                        calculateVariable();
668                    return subscripts;
669                }
670               
671                private void calculateVariable() {
672                    error = false;
673                   
674                    // Check for recursive structure first.
675                    if (isExpandable) {
676                        for (Source src : sources) {
677                            if (!src.checkRecursion(ExpandableSet.this)) {
678                                error = true;
679                            }
680                        }
681                        if (error) {
682                            return;  // We risk infinite recursion if we continue
683                        }
684                    }
685                   
686                    // Collect instances of this member from declarations
687                    ArrayList<InstComponentDecl> declared = new ArrayList<InstComponentDecl>();
688                    Map<InstComponentDecl,InstComponentDecl> declaredMap = new HashMap<>();
689                    for (InstComponentDecl conn : connectors) {
690                        InstLookupResult<InstComponentDecl> res = conn.memberInstComponent(name);
691                        if (res.successful()) {
692                            InstComponentDecl decl = res.target();
693                            declared.add(decl);
694                            declaredMap.put(conn, decl);
695                        }
696                    }
697                   
698                    // Pick a variable to use as template
699                    ASTNode templateErrorNode = null;
700                    if (sources.isEmpty() && declared.isEmpty()) {
701                        error = true;
702                        // TODO: This is no longer compliance error, spec has changed.
703                        for (InstAccess nestledAccess : nestledAccesses)
704                            nestledAccess.compliance("Nested expandable connectors where some of the intermediate expandable connectors are neither connected to or declared are not supported");
705                    } else if (declared.isEmpty()) {
706                        template = sources.get(0).template();
707                        templateErrorNode = sources.get(0).errorNode();
708                    } else {
709                        template = declared.get(0);
710                        templateErrorNode = template;
711                        templateMap = declaredMap;
712                    }
713                   
714                    // Check types against template
715                    if (template != null && !template.checkAsExpandableMemberTemplate(templateErrorNode))
716                        error = true;
717                    for (Source src : sources)
718                        src.checkType(template);
719                    for (InstComponentDecl decl : declared) {
720                        if (!decl.connectableTypes(template)) {
721                            error = true;
722                            // TODO: Improve error message and move to new problem framework
723                            decl.error("Type of declared member of expandable connector does not match declarations in other expandable connectors in same connection set");
724                        }
725                    }
726                   
727                    // Calculate size
728                    SummedSize ss = new SummedSize();
729                    for (InstComponentDecl decl : declared)
730                        ss.updateFromDeclaration(decl);
731                    for (Source src : sources)
732                        src.collectSize(ss);
733                    Size s = ss.size;
734                    if (template != null && template.ndims() > template.localNdims()) {
735                        s = s.contract(0, template.ndims() - template.localNdims());
736                    }
737                   
738                    // Create subscripts for size
739                    if (s != Size.SCALAR && s != null) {
740                        subscripts = s.createFArrayExpSubscripts();
741                    }
742                   
743                    // Check against connections to non-existing members of non-expandable connectors
744                    if (!sources.isEmpty()) {
745                        for (ExpandableSet set : sets.values()) {
746                            if (set.connectors.isEmpty() && !set.members.isEmpty()) {
747                                for (ConnectorMember m : set.members.values()) {
748                                    error = !m.checkNonExisting(template) || error;
749                                }
750                            }
751                        }
752                    }
753                    // TODO: Also check for other confusion with non-expandable vs expandable
754                   
755                    // Check array index types. If there is a declaration they are checked in FExpSubscript.typeCheckAsIndex;
756                    if (declared.isEmpty()) {
757                        Source tmpl = null;
758                        for (Source src : sources) {
759                            if (tmpl == null)
760                                tmpl = src;
761                            if (!src.checkIndexType(tmpl))
762                                break;
763                        }
764                    }
765                    calculated = true;
766                }
767               
768                private boolean checkNonExisting(InstComponentDecl parentTemplate) {
769                    boolean res = true;
770                    InstComponentDecl myTemplate = (parentTemplate != null) ? parentTemplate.memberInstComponent(name).targetOrNull() : null;
771                    if (myTemplate == null) {
772                        for (Source s : sources) {
773                            // TODO: Improve error message and move to new problem framework
774                            s.errorNode().error("Can not connect to non-existing member of non-expandable connector in expandable connector");
775                        }
776                        res = false;
777                    }
778                    for (ExpandableSet set : sets.values()) {
779                        for (ConnectorMember m : set.members.values()) {
780                            res = m.checkNonExisting(myTemplate) && res;
781                        }
782                    }
783                    return res;
784                }
785               
786                public String toString() {
787                    return name + ": " + sources.toString();
788                }
789               
790                private class Source {
791                   
792                    private InstAccess targetAccess;
793                    private InstComponentDecl targetComp;
794                    private FArraySubscripts fas;
795                    private Indices localIndices;
796                   
797                    private boolean errorReported = false;
798                    private Size s;
799                    private boolean[] fixed;
800                   
801                    public Source(InstComponentDecl targetComponent, InstAccess targetAccess, 
802                            FArraySubscripts fas, Size targetSize) {
803                        this.targetAccess = targetAccess;
804                        this.targetComp = targetComponent;
805                        this.fas = fas;
806                        localIndices = (fas == null) ? null : Indices.createFromFas(fas);
807                        calculateSize(targetSize);
808                    }
809                   
810                    public Source(Source other) {
811                        this.targetAccess = other.targetAccess;
812                        this.targetComp   = other.targetComp;
813                        this.fas          = other.fas;
814                        this.localIndices = other.localIndices;
815                        this.s            = other.s;
816                        this.fixed        = other.fixed;
817                    }
818                   
819                    private void calculateSize(Size ts) {
820                        if (ts == null) {
821                            // Target size not given, calculate it
822                            ts = targetAccess.size();
823                        }
824                        if (fas != null) {
825                            MutableSize ms = new MutableSize(fas.ndims());
826                            fixed = new boolean[ms.ndims()];
827                            int tspos = 0;
828                            for (int i = 0; i < fixed.length; i++) {
829                                Subscript sub = fas.subscript(i);
830                                int len = (tspos < ts.ndims()) ? ts.get(tspos) : 1;
831                                if (!sub.calculateExpandableConnectorSize(ms, i, len)) 
832                                    localError();
833                                fixed[i] = sub.isColon();
834                                if (sub.ndims() > 0) 
835                                    tspos++;
836                            }
837                            if (tspos != ts.ndims())
838                                localError();
839                            s = ms;
840                        } else {
841                            s = (ts == Size.SCALAR) ? ts : ts.mutableClone();
842                            fixed = new boolean[s.ndims()];
843                            Arrays.fill(fixed, true);
844                        }
845                    }
846                   
847                    public void collectSize(SummedSize ss) {
848                        if (errorReported)
849                            return;
850                       
851                        // Merge with other sizes in set
852                        if (!ss.merge(s, fixed))
853                            mismatchError();
854                    }
855                   
856                    public void connectExpandableMember(InstComponentDecl member) {
857                        if (targetAccess.isArray()) {
858                            InstAccess targ = targetAccess.getLastInstAccess();
859                            Indices memberInd = (localIndices == null) ?
860                                Indices.create(subscripts.declarationSize()) :
861                                localIndices;
862                            Indices targetInd = targ.indices();
863                            for (Index[] i : new ParallelIterable<Index>(new Index[2], memberInd, targetInd)) {
864                                Index memberI = memberInd.translate(i[0]);
865                                Index targetI = targetInd.translate(i[1]);
866                                InstComponentDecl memberCell = member.arrayCell(memberI.iterator());
867                                InstComponentDecl targetCell = targetComp.arrayCell(targetI.iterator());
868                                setFor(targetCell).mergeFor(memberCell);
869                            }
870                        } else {
871                            if (localIndices != null) {
872                                Index memberI = localIndices.translate(Index.NULL);
873                                member = member.arrayCell(memberI.iterator());
874                            }
875                            setFor(targetComp).mergeFor(member);
876                        }
877                    }
878                   
879                    public void checkType(InstComponentDecl template) {
880                        if (!targetAccess.myInstComponentDecl().connectableTypes(template))
881                            // TODO: Improve error message and move to new problem framework
882                            error("Type of component introduced to external connector does not match other connections to same name in connection set or component declared in connector");
883                    }
884                   
885                    public boolean checkIndexType(Source other) {
886                        if (fas == null || other.fas == null)
887                            return true;
888                        for (int dim = 0; dim < Math.min(fas.ndims(), other.fas.ndims()); dim++) {
889                            if (!fas.subscript(dim).type().scalarType().typeCompatible(
890                                    other.fas.subscript(dim).type().scalarType())) {
891                                // TODO: Improve error message and move to new problem framework
892                                error("Array index type of component introduced to external connector does not match other"
893                                        + " connections to same name in connection set");
894                                return false;
895                            }
896                        }
897                        return true;
898                    }
899                   
900                    public boolean checkRecursion(ExpandableSet parent) {
901                        ExpandableSet ancestor = map.get(targetAccess.myInstComponentDecl());
902                        if (ancestor != null && parent.isOrAncestor(ancestor)) {
903                            // TODO: Move to new problem framework
904                            error("Connect introduces a copy of " + targetAccess + 
905                                  " into a connector that is (possibly indirectly) connected back to " + targetAccess + 
906                                  ". This creates an infinite recursive structure, and is not allowed:\n    " + 
907                                  errorNode());
908                            return false;
909                        }
910                        return true;
911                    }
912                   
913                    private void mismatchError() {
914                        // TODO: Improve error message and move to new problem framework
915                        error("Size introduced for external connector member does not match other connections to same name in connection set or component declared in connector");
916                    }
917                   
918                    private void localError() {
919                        // TODO: Improve error message and move to new problem framework
920                        error("Can not match size of connector to access introducing member in external connector");
921                    }
922                   
923                    private void error(String err) {
924                        error = true;
925                        if (!errorReported) {
926                            errorReported = true;
927                            errorNode().error(err);
928                        }
929                    }
930                   
931                    public InstComponentDecl template() {
932                        return targetComp;
933                    }
934                   
935                    public ASTNode errorNode() {
936                        return targetAccess.getParent();
937                    }
938                   
939                    public String toString() {
940                        return targetAccess.toString() + ((fas != null) ? (" (" + fas + ")") : "");
941                    }
942                   
943                }
944               
945                private class SummedSize {
946                   
947                    public Size size = null;
948                    public boolean[] fixed = null;
949                   
950                    public void updateFromDeclaration(InstComponentDecl icd) {
951                        if (!mergeKnownFixed(icd.size())) {
952                            error = true;
953                            // TODO: Improve error message and move to new problem framework
954                            icd.error("Size of declared member of expandable connector does not match declarations in other expandable connectors in same connection set");
955                        }
956                    }
957   
958                    private boolean mergeKnownFixed(Size s) {
959                        if (s != Size.SCALAR)
960                            s = s.mutableClone();
961                        boolean[] sFixed = new boolean[s.ndims()];
962                        for (int i = 0; i < sFixed.length; i++)
963                            sFixed[i] = s.hasValue(i);
964                        return merge(s, sFixed);
965                    }
966   
967                    public boolean merge(Size s, boolean[] sFixed) {
968                        if (size == null) {
969                            size = s;
970                            fixed = sFixed;
971                        } else if (sFixed.length != fixed.length) {
972                            return false;
973                        } else {
974                            for (int i = 0; i < fixed.length; i++) {
975                                int diff = s.get(i) - size.get(i);
976                                if (sFixed[i]) {
977                                    if (diff == 0) {
978                                        fixed[i] = true;
979                                    } else if (diff < 0) {
980                                        return false;
981                                    }
982                                } 
983                                if (diff > 0) {
984                                    if (fixed[i]) {
985                                        return false;
986                                    } else {
987                                        fixed[i] = sFixed[i];
988                                        ((MutableSize) size).set(i, s, i);
989                                    }
990                                }
991                            }
992                        }
993                        return true;
994                    }
995                   
996                }
997        }
998
999        }
1000       
1001    }
1002   
1003    public void InstComponentDecl.expandConnector(List<InstComponentDecl> members, InstComponentDecl[] templates) {
1004        throw new UnsupportedOperationException();
1005    }
1006   
1007    public void InstExpandableConnectorDecl.expandConnector(List<InstComponentDecl> members, InstComponentDecl[] templates) {
1008        expandedMembers = members;
1009        this.templates = templates;
1010        flushAll();
1011    }
1012   
1013    public void InstReplacingExpandableConnectorDecl.expandConnector(List<InstComponentDecl> members, InstComponentDecl[] templates) {
1014        expandedMembers = members;
1015        this.templates = templates;
1016        flushAll();
1017    }
1018   
1019    public void InstArrayExpandableConnector.expandConnector(List<InstComponentDecl> members, InstComponentDecl[] templates) {
1020        expandedMembers = members;
1021        this.templates = templates;
1022        flushAll();
1023    }
1024   
1025   
1026    /**
1027     * Find the closest ancestor component that is an expandable connector, if any.
1028     */
1029    inh InstComponentDecl InstComponentDecl.findExpandableAncestor();
1030    eq InstComponentDecl.getChild().findExpandableAncestor() = 
1031        (isExpandableConnector() && !isArray()) ? this : findExpandableAncestor();
1032    eq InstClassDecl.getChild().findExpandableAncestor()     = null;
1033    eq InstRoot.getChild().findExpandableAncestor()          = null;
1034    eq Root.getChild().findExpandableAncestor()              = null;
1035   
1036    /**
1037     * Find the ancestor component that is a direct child of the given component.
1038     *
1039     * @param a  the ancestor to find child of
1040     * @param c  the child being considered, always use <code>this</code>
1041     */
1042    inh InstComponentDecl InstComponentDecl.ancestorChild(InstComponentDecl a, InstComponentDecl c);
1043    eq InstComponentDecl.getChild().ancestorChild(InstComponentDecl a, InstComponentDecl c) = 
1044        (this == a) ? c : ancestorChild(a, this);
1045    eq InstClassDecl.getChild().ancestorChild(InstComponentDecl a, InstComponentDecl c)     = null;
1046    eq InstRoot.getChild().ancestorChild(InstComponentDecl a, InstComponentDecl c)          = null;
1047    eq Root.getChild().ancestorChild(InstComponentDecl a, InstComponentDecl c)              = null;
1048   
1049
1050    private static final BinaryOperation<CValue> FExpSubscript.INT_MAX_OP = new BinaryOperation<CValue>() {
1051        public CValue op(CValue a, CValue b) { 
1052            return (a.intValue() >= b.intValue()) ? a : b;
1053        }
1054    };
1055   
1056    public abstract boolean FSubscript.calculateExpandableConnectorSize(MutableSize s, int i, int len);
1057   
1058    public boolean FExpSubscript.calculateExpandableConnectorSize(MutableSize s, int i, int len) {
1059        CValue val = ceval();
1060        if (ndims() > 0) 
1061            val = val.reduce(INT_MAX_OP, CValueInteger.valueOf(1));
1062        s.set(i, val.intValue());
1063        return ndims() == 0 || size().get(0) == len;
1064    }
1065   
1066    public boolean FIntegerSubscript.calculateExpandableConnectorSize(MutableSize s, int i, int len) {
1067        s.set(i, getValue());
1068        return true;
1069    }
1070   
1071    public boolean IntegerSubscript.calculateExpandableConnectorSize(MutableSize s, int i, int len) {
1072        s.set(i, value);
1073        return true;
1074    }
1075   
1076    public boolean FColonSubscript.calculateExpandableConnectorSize(MutableSize s, int i, int len) {
1077        s.set(i, len);
1078        return true;
1079    }
1080   
1081    /**
1082     * Check that this component would be allowed as a member of an expandable connector.
1083     *
1084     * @param errorNode  node to report any errors found on
1085     * @return  <code>true</code> if the component is OK
1086     */
1087    public boolean InstComponentDecl.checkAsExpandableMemberTemplate(ASTNode errorNode) {
1088        for (InstComponentDecl child : getInstComponentDecls()) {
1089            if (child.isExpandableConnector()) {
1090                errorNode.compliance("Expandable connectors containing a non-expandable connector component, that in turn contains an expandable connector, is not supported");
1091                return false;
1092            } else if (!child.checkAsExpandableMemberTemplate(errorNode))
1093                return false;
1094        }
1095        return true;
1096    }
1097   
1098    public boolean InstExpandableConnectorDecl.checkAsExpandableMemberTemplate(ASTNode errorNode) {
1099        return true;
1100    }
1101   
1102    public boolean InstReplacingExpandableConnectorDecl.checkAsExpandableMemberTemplate(ASTNode errorNode) {
1103        return true;
1104    }
1105   
1106    public boolean InstArrayExpandableConnector.checkAsExpandableMemberTemplate(ASTNode errorNode) {
1107        return true;
1108    }
1109   
1110    public void InstAccess.buildConnectionSets(FAccess prefix, ConnectionSetManager csm, boolean connect) {
1111        if (isExpandableConnectorPart())
1112            csm.getExpandable().addUse(this);
1113    }
1114   
1115    public void InstExpandableConnectorDecl.buildConnectionSets(FAccess prefix, ConnectionSetManager csm, boolean connect) {
1116        buildConnectionSetsForExpandableConnector(prefix, csm, connect);
1117    }
1118   
1119    public void InstReplacingExpandableConnectorDecl.buildConnectionSets(FAccess prefix, ConnectionSetManager csm, boolean connect) {
1120        buildConnectionSetsForExpandableConnector(prefix, csm, connect);
1121    }
1122   
1123    public void InstArrayExpandableConnector.buildConnectionSets(FAccess prefix, ConnectionSetManager csm, boolean connect) {
1124        buildConnectionSetsForExpandableConnector(prefix, csm, connect);
1125    }
1126   
1127    public void InstComponentDecl.buildConnectionSetsForExpandableConnector(FAccess prefix, ConnectionSetManager csm, boolean connect) {
1128        if (useInFlattening()) {
1129            if (!isArray()) {
1130                if (csm.isExpandableConnectorsDone()) {
1131                    for (InstComponentDecl icd : getInstComponentDecls()) {
1132                        if (icd.isArray() && !icd.isExpandableConnector()) {
1133                            icd.addExpandableArrayMembersTopLevel(csm);
1134                        }
1135                    }
1136                } else {
1137                    csm.getExpandable().addConnector(this);
1138                }
1139            }
1140            super.buildConnectionSets(prefix, csm, connect);
1141        }
1142    }
1143   
1144    /**
1145     * Add all variables to connection set manager, to get "= 0" equations if they are not connected.
1146     */
1147    public void InstComponentDecl.addExpandableArrayMembersTopLevel(ConnectionSetManager csm) {
1148        for (InstComponentDecl icd : allInstComponentDecls()) {
1149            icd.addExpandableArrayMembers(csm);
1150        }
1151    }
1152   
1153    public void InstPrimitive.addExpandableArrayMembersTopLevel(ConnectionSetManager csm) {
1154        if (!variability().parameterOrLess()) {
1155            for (Index i : indices()) {
1156                csm.addExpandableArrayMember(this, getFAccess(i));
1157            }
1158        }
1159    }
1160   
1161    /**
1162     * Add all variables to connection set manager, to get "= 0" equations if they are not connected.
1163     */
1164    public void InstComponentDecl.addExpandableArrayMembers(ConnectionSetManager csm) {
1165        for (InstComponentDecl icd : allInstComponentDecls()) {
1166            icd.addExpandableArrayMembers(csm);
1167        }
1168    }
1169   
1170    public void InstPrimitive.addExpandableArrayMembers(ConnectionSetManager csm) {
1171        if (!variability().parameterOrLess()) {
1172            csm.addExpandableArrayMember(this, getFAccess(Index.NULL));
1173        }
1174    }
1175   
1176   
1177    syn boolean InstAccess.isExpandableConnectorPart() = false;
1178    eq InstDot.isExpandableConnectorPart() {
1179        InstComponentDecl conn = findReferencedExpandableConnector();
1180        return conn != null && conn != getLastInstAccess().findReferencedExpandableConnector();
1181    }
1182   
1183    syn InstComponentDecl InstAccess.findReferencedExpandableConnector() = null;
1184    eq InstComponentAccess.findReferencedExpandableConnector() {
1185        InstComponentDecl icd = myInstComponentDecl();
1186        return icd.isExpandableConnector() ? icd : null;
1187    }
1188    eq InstComponentArrayAccess.findReferencedExpandableConnector() {
1189        InstComponentDecl icd = lookupArrayElement(myInstComponentDecl());
1190        return (icd != null && icd.isExpandableConnector()) ? icd : null;
1191    }
1192    eq InstDot.findReferencedExpandableConnector() {
1193        for (int i = getNumInstAccess() - 1; i >= 0; i--) {
1194            InstComponentDecl conn = getInstAccess(i).findReferencedExpandableConnector();
1195            if (conn != null)
1196                return conn;
1197        }
1198        return null;
1199    }
1200   
1201    syn InstAccess InstAccess.findExpandableConnectorPart() = null;
1202    eq InstDot.findExpandableConnectorPart() {
1203        for (int i = getNumInstAccess() - 2; i >= 0; i--) 
1204            if (getInstAccess(i).findReferencedExpandableConnector() != null)
1205                return getInstAccess(i);
1206        return null;
1207    }
1208   
1209    // We need to make sure lookups work properly after flush
1210    public void InstAmbiguousAccess.flushAllRecursiveClearFinal() {
1211        super.flushAllRecursiveClearFinal();
1212        rewritten = false;
1213        is$Final = false;
1214    }
1215
1216    public void InstAmbiguousArrayAccess.flushAllRecursiveClearFinal() {
1217        super.flushAllRecursiveClearFinal();
1218        rewritten = false;
1219        is$Final = false;
1220    }
1221
1222}
Note: See TracBrowser for help on using the repository browser.