1 /*
   2  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.nashorn.internal.ir;
  27 
  28 import jdk.nashorn.internal.ir.annotations.Immutable;
  29 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
  30 
  31 /**
  32  * IR representation of an object literal property.
  33  */
  34 @Immutable
  35 public final class PropertyNode extends Node {
  36     private static final long serialVersionUID = 1L;
  37 
  38     /** Property key. */
  39     private final PropertyKey key;
  40 
  41     /** Property value. */
  42     private final Expression value;
  43 
  44     /** Property getter. */
  45     private final FunctionNode getter;
  46 
  47     /** Property getter. */
  48     private final FunctionNode setter;
  49 
  50     /**
  51      * Constructor
  52      *
  53      * @param token   token
  54      * @param finish  finish
  55      * @param key     the key of this property
  56      * @param value   the value of this property
  57      * @param getter  getter function body
  58      * @param setter  setter function body
  59      */
  60     public PropertyNode(final long token, final int finish, final PropertyKey key, final Expression value, final FunctionNode getter, final FunctionNode setter) {
  61         super(token, finish);
  62         this.key    = key;
  63         this.value  = value;
  64         this.getter = getter;
  65         this.setter = setter;
  66     }
  67 
  68     private PropertyNode(final PropertyNode propertyNode, final PropertyKey key, final Expression value, final FunctionNode getter, final FunctionNode setter) {
  69         super(propertyNode);
  70         this.key    = key;
  71         this.value  = value;
  72         this.getter = getter;
  73         this.setter = setter;
  74     }
  75 
  76     /**
  77      * Get the name of the property key
  78      * @return key name
  79      */
  80     public String getKeyName() {
  81         return key.getPropertyName();
  82     }
  83 
  84     @Override
  85     public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
  86         if (visitor.enterPropertyNode(this)) {
  87             return visitor.leavePropertyNode(
  88                 setKey((PropertyKey)((Node)key).accept(visitor)).
  89                 setValue(value == null ? null : (Expression)value.accept(visitor)).
  90                 setGetter(getter == null ? null : (FunctionNode)getter.accept(visitor)).
  91                 setSetter(setter == null ? null : (FunctionNode)setter.accept(visitor)));
  92         }
  93 
  94         return this;
  95     }
  96 
  97     @Override
  98     public void toString(final StringBuilder sb, final boolean printType) {
  99         if (value instanceof FunctionNode && ((FunctionNode)value).getIdent() != null) {
 100             value.toString(sb);
 101         }
 102 
 103         if (value != null) {
 104             ((Node)key).toString(sb, printType);
 105             sb.append(": ");
 106             value.toString(sb, printType);
 107         }
 108 
 109         if (getter != null) {
 110             sb.append(' ');
 111             getter.toString(sb, printType);
 112         }
 113 
 114         if (setter != null) {
 115             sb.append(' ');
 116             setter.toString(sb, printType);
 117         }
 118     }
 119 
 120     /**
 121      * Get the getter for this property
 122      * @return getter or null if none exists
 123      */
 124     public FunctionNode getGetter() {
 125         return getter;
 126     }
 127 
 128     /**
 129      * Set the getter of this property, null if none
 130      * @param getter getter
 131      * @return same node or new node if state changed
 132      */
 133     public PropertyNode setGetter(final FunctionNode getter) {
 134         if (this.getter == getter) {
 135             return this;
 136         }
 137         return new PropertyNode(this, key, value, getter, setter);
 138     }
 139 
 140     /**
 141      * Return the key for this property node
 142      * @return the key
 143      */
 144     public Expression getKey() {
 145         return (Expression)key;
 146     }
 147 
 148     private PropertyNode setKey(final PropertyKey key) {
 149         if (this.key == key) {
 150             return this;
 151         }
 152         return new PropertyNode(this, key, value, getter, setter);
 153     }
 154 
 155     /**
 156      * Get the setter for this property
 157      * @return setter or null if none exists
 158      */
 159     public FunctionNode getSetter() {
 160         return setter;
 161     }
 162 
 163     /**
 164      * Set the setter for this property, null if none
 165      * @param setter setter
 166      * @return same node or new node if state changed
 167      */
 168     public PropertyNode setSetter(final FunctionNode setter) {
 169         if (this.setter == setter) {
 170             return this;
 171         }
 172         return new PropertyNode(this, key, value, getter, setter);
 173     }
 174 
 175     /**
 176      * Get the value of this property
 177      * @return property value
 178      */
 179     public Expression getValue() {
 180         return value;
 181     }
 182 
 183     /**
 184      * Set the value of this property
 185      * @param value new value
 186      * @return same node or new node if state changed
 187      */
 188     public PropertyNode setValue(final Expression value) {
 189         if (this.value == value) {
 190             return this;
 191         }
 192         return new PropertyNode(this, key, value, getter, setter);
 193    }
 194 }