001/* ASTPtUnionConstructNode represents record construction in the parse tree.
002
003 Copyright (c) 2006-2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027
028 Created : June 2005
029
030 */
031package ptolemy.data.expr;
032
033import java.util.HashSet;
034import java.util.Iterator;
035import java.util.LinkedList;
036import java.util.List;
037import java.util.Map;
038import java.util.Set;
039
040import ptolemy.kernel.util.IllegalActionException;
041
042//////////////////////////////////////////////////////////////////////////
043////ASTPtUnionConstructNode
044
045/**
046 The parse tree created from the expression string consists of a
047 hierarchy of node objects. This class represents union construction using
048 the following syntax: <code>{|foo = "abc"|}</code>. The result of
049 parsing and evaluating this expression is a union token with the label
050 <i>foo</i>, and the corresponding value is a StringToken of value "abc".
051
052 When using an expression to specify a union type, multiple labels
053 are allowed: <code>{|foo = string, bar = int|}</code>, which is a union
054 type with two alternatives: one labeled <i>foo</i> with type string, one
055 labeled <i>bar</i> with type integer.
056
057 FIXME: ambiguity
058
059 @author Xiaojun Liu
060 @version $Id$
061 @since Ptolemy II 5.2
062 @Pt.ProposedRating Yellow (liuxj)
063 @Pt.AcceptedRating Red (cxh)
064 @see ptolemy.data.expr.ASTPtRootNode
065 @see ptolemy.data.expr.PtParser
066 @see ptolemy.data.Token
067 */
068public class ASTPtUnionConstructNode extends ASTPtRootNode {
069    public ASTPtUnionConstructNode(int id) {
070        super(id);
071    }
072
073    public ASTPtUnionConstructNode(PtParser p, int id) {
074        super(p, id);
075    }
076
077    /** Return the list of label names for this union construct.
078     *  The order of the list is not meaningful.
079     *  @return The list of label names.
080     */
081    public List getLabelNames() {
082        return _labelNames;
083    }
084
085    /** Return true if this node is (hierarchically) congruent to the
086     *  given node, under the given renaming of bound identifiers.
087     *  Derived classes should extend this method to add additional
088     *  necessary congruency checks.
089     *  @param node The node to compare to.
090     *  @param renaming A map from String to String that gives a
091     *  renaming from identifiers in this node to identifiers in the
092     *  given node.
093     */
094    @Override
095    public boolean isCongruent(ASTPtRootNode node, Map renaming) {
096        // Note: we don't call super.isCongruent(), which checks for ordered
097        // congruence of the children.
098        // Check to see that they are the same kind of node.
099        if (node._id != _id) {
100            return false;
101        }
102
103        ASTPtRecordConstructNode recordNode = (ASTPtRecordConstructNode) node;
104
105        // Empty records are allowed (Are they?)
106        if (recordNode._fieldNames == null && _labelNames == null) {
107            return true;
108        }
109
110        // But both must be empty
111        if (recordNode._fieldNames == null || _labelNames == null) {
112            return false;
113        }
114
115        // Check that they have the same number of fields.
116        if (recordNode._fieldNames.size() != _labelNames.size()) {
117            return false;
118        }
119
120        // The field names must be the same.
121        // Not use set for unordered comparison.
122        // Note that field names are not renamed!
123        Set nameSet = new HashSet(_labelNames);
124        Set nodeNameSet = new HashSet(
125                ((ASTPtRecordConstructNode) node)._fieldNames);
126
127        if (!nameSet.equals(nodeNameSet)) {
128            return false;
129        }
130
131        // Check that their children are congruent, under renaming.
132        Iterator fieldNames = _labelNames.iterator();
133        Iterator children = _children.iterator();
134
135        while (fieldNames.hasNext()) {
136            String fieldName = (String) fieldNames.next();
137            ASTPtRootNode child = (ASTPtRootNode) children.next();
138            int nodeIndex = recordNode._fieldNames.indexOf(fieldName);
139            ASTPtRootNode nodeChild = (ASTPtRootNode) recordNode._children
140                    .get(nodeIndex);
141
142            if (!child.isCongruent(nodeChild, renaming)) {
143                return false;
144            }
145        }
146
147        return true;
148    }
149
150    /** Traverse this node with the given visitor.
151     */
152    @Override
153    public void visit(ParseTreeVisitor visitor) throws IllegalActionException {
154        visitor.visitUnionConstructNode(this);
155    }
156
157    /** The list of field names for the record.
158     */
159    protected LinkedList _labelNames = new LinkedList();
160}