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 Expression 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     /** static property flag */
  51     private final boolean isStatic;
  52 
  53     /** Computed property flag */
  54     private final boolean computed;
  55 
  56     /**
  57      * Constructor
  58      *
  59      * @param token   token
  60      * @param finish  finish
  61      * @param key     the key of this property
  62      * @param value   the value of this property
  63      * @param getter  getter function body
  64      * @param setter  setter function body
  65      * @param isStatic is this a static property?
  66      * @param computed is this a computed property?
  67      */
  68     public PropertyNode(final long token, final int finish, final Expression key, final Expression value, final FunctionNode getter, final FunctionNode setter, final boolean isStatic, final boolean computed) {
  69         super(token, finish);
  70         this.key    = key;
  71         this.value  = value;
  72         this.getter = getter;
  73         this.setter = setter;
  74         this.isStatic = isStatic;
  75         this.computed = computed;
  76     }
  77 
  78     private PropertyNode(final PropertyNode propertyNode, final Expression key, final Expression value, final FunctionNode getter, final FunctionNode setter, final boolean isStatic, final boolean computed) {
  79         super(propertyNode);
  80         this.key    = key;
  81         this.value  = value;
  82         this.getter = getter;
  83         this.setter = setter;
  84         this.isStatic = isStatic;
  85         this.computed = computed;
  86     }
  87 
  88     /**
  89      * Get the name of the property key
  90      * @return key name
  91      */
  92     public String getKeyName() {
  93         return key instanceof PropertyKey ? ((PropertyKey) key).getPropertyName() : null;
  94     }
  95 
  96     @Override
  97     public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
  98         if (visitor.enterPropertyNode(this)) {
  99             return visitor.leavePropertyNode(
 100                 setKey((Expression) key.accept(visitor)).
 101                 setValue(value == null ? null : (Expression)value.accept(visitor)).
 102                 setGetter(getter == null ? null : (FunctionNode)getter.accept(visitor)).
 103                 setSetter(setter == null ? null : (FunctionNode)setter.accept(visitor)));
 104         }
 105 
 106         return this;
 107     }
 108 
 109     @Override
 110     public void toString(final StringBuilder sb, final boolean printType) {
 111         if (value instanceof FunctionNode && ((FunctionNode)value).getIdent() != null) {
 112             value.toString(sb);
 113         }
 114 
 115         if (value != null) {
 116             ((Node)key).toString(sb, printType);
 117             sb.append(": ");
 118             value.toString(sb, printType);
 119         }
 120 
 121         if (getter != null) {
 122             sb.append(' ');
 123             getter.toString(sb, printType);
 124         }
 125 
 126         if (setter != null) {
 127             sb.append(' ');
 128             setter.toString(sb, printType);
 129         }
 130     }
 131 
 132     /**
 133      * Get the getter for this property
 134      * @return getter or null if none exists
 135      */
 136     public FunctionNode getGetter() {
 137         return getter;
 138     }
 139 
 140     /**
 141      * Set the getter of this property, null if none
 142      * @param getter getter
 143      * @return same node or new node if state changed
 144      */
 145     public PropertyNode setGetter(final FunctionNode getter) {
 146         if (this.getter == getter) {
 147             return this;
 148         }
 149         return new PropertyNode(this, key, value, getter, setter, isStatic, computed);
 150     }
 151 
 152     /**
 153      * Return the key for this property node
 154      * @return the key
 155      */
 156     public Expression getKey() {
 157         return key;
 158     }
 159 
 160     private PropertyNode setKey(final Expression key) {
 161         if (this.key == key) {
 162             return this;
 163         }
 164         return new PropertyNode(this, key, value, getter, setter, isStatic, computed);
 165     }
 166 
 167     /**
 168      * Get the setter for this property
 169      * @return setter or null if none exists
 170      */
 171     public FunctionNode getSetter() {
 172         return setter;
 173     }
 174 
 175     /**
 176      * Set the setter for this property, null if none
 177      * @param setter setter
 178      * @return same node or new node if state changed
 179      */
 180     public PropertyNode setSetter(final FunctionNode setter) {
 181         if (this.setter == setter) {
 182             return this;
 183         }
 184         return new PropertyNode(this, key, value, getter, setter, isStatic, computed);
 185     }
 186 
 187     /**
 188      * Get the value of this property
 189      * @return property value
 190      */
 191     public Expression getValue() {
 192         return value;
 193     }
 194 
 195     /**
 196      * Set the value of this property
 197      * @param value new value
 198      * @return same node or new node if state changed
 199      */
 200     public PropertyNode setValue(final Expression value) {
 201         if (this.value == value) {
 202             return this;
 203         }
 204         return new PropertyNode(this, key, value, getter, setter, isStatic, computed);
 205     }
 206 
 207     /**
 208      * Returns true if this is a static property.
 209      *
 210      * @return true if static flag is set
 211      */
 212     public boolean isStatic() {
 213         return isStatic;
 214     }
 215 
 216     /**
 217      * Returns true if this is a computed property.
 218      *
 219      * @return true if the computed flag is set
 220      */
 221     public boolean isComputed() {
 222         return computed;
 223     }
 224 }