001/* ASTPtRecordConstructNode represents record construction in the parse tree.
002
003 Copyright (c) 2000-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 : December 2000
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//// ASTPtRecordConstructNode
044
045/**
046 The parse tree created from the expression string consists of a
047 hierarchy of node objects. This class represents record construction using
048 the following syntax: <code>{foo = "abc", bar = 1}</code>. The result of
049 parsing and evaluating this expression is a record token with two fields:
050 a field <i>foo</i> containing a StringToken of value "abc", and a field
051 <i>bar</i> containing a IntToken of value 1.
052
053 @author Xiaojun Liu, Steve Neuendorffer
054 @version $Id$
055 @since Ptolemy II 1.0
056 @Pt.ProposedRating Yellow (liuxj)
057 @Pt.AcceptedRating Red (cxh)
058 @see ptolemy.data.expr.ASTPtRootNode
059 @see ptolemy.data.expr.PtParser
060 @see ptolemy.data.Token
061 */
062public class ASTPtRecordConstructNode extends ASTPtRootNode {
063    public ASTPtRecordConstructNode(int id) {
064        super(id);
065    }
066
067    public ASTPtRecordConstructNode(PtParser p, int id) {
068        super(p, id);
069    }
070
071    /** Return the list of field names for this record construct.
072     *  The order of the list is not meaningful.
073     *  @return the list of field names for this record construct.
074     */
075    public List getFieldNames() {
076        return _fieldNames;
077    }
078
079    /** Return true if this node is (hierarchically) congruent to the
080     *  given node, under the given renaming of bound identifiers.
081     *  Derived classes should extend this method to add additional
082     *  necessary congruency checks.
083     *  @param node The node to compare to.
084     *  @param renaming A map from String to String that gives a
085     *  renaming from identifiers in this node to identifiers in the
086     *  given node.
087     */
088    @Override
089    public boolean isCongruent(ASTPtRootNode node, Map renaming) {
090        // Note: we don't call super.isCongruent(), which checks for ordered
091        // congruence of the children.
092        // Check to see that they are the same kind of node.
093        if (node._id != _id) {
094            return false;
095        }
096
097        ASTPtRecordConstructNode recordNode = (ASTPtRecordConstructNode) node;
098
099        // Empty records are allowed (Are they?)
100        if (recordNode._fieldNames == null && _fieldNames == null) {
101            return true;
102        }
103
104        // But both must be empty
105        if (recordNode._fieldNames == null || _fieldNames == null) {
106            return false;
107        }
108
109        // Check that they have the same number of fields.
110        if (recordNode._fieldNames.size() != _fieldNames.size()) {
111            return false;
112        }
113
114        // The field names must be the same.
115        // Not use set for unordered comparison.
116        // Note that field names are not renamed!
117        Set nameSet = new HashSet(_fieldNames);
118        Set nodeNameSet = new HashSet(
119                ((ASTPtRecordConstructNode) node)._fieldNames);
120
121        if (!nameSet.equals(nodeNameSet)) {
122            return false;
123        }
124
125        // Check that their children are congruent, under renaming.
126        Iterator fieldNames = _fieldNames.iterator();
127        Iterator children = _children.iterator();
128
129        while (fieldNames.hasNext()) {
130            String fieldName = (String) fieldNames.next();
131            ASTPtRootNode child = (ASTPtRootNode) children.next();
132            int nodeIndex = recordNode._fieldNames.indexOf(fieldName);
133            ASTPtRootNode nodeChild = (ASTPtRootNode) recordNode._children
134                    .get(nodeIndex);
135
136            if (!child.isCongruent(nodeChild, renaming)) {
137                return false;
138            }
139        }
140
141        return true;
142    }
143
144    /** Traverse this node with the given visitor.
145     */
146    @Override
147    public void visit(ParseTreeVisitor visitor) throws IllegalActionException {
148        visitor.visitRecordConstructNode(this);
149    }
150
151    /** The list of field names for the record.
152     */
153    protected LinkedList _fieldNames = new LinkedList();
154}