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.objects;
  27 
  28 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
  29 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
  30 import static jdk.nashorn.internal.runtime.ScriptRuntime.sameValue;
  31 
  32 import java.util.Objects;
  33 import jdk.nashorn.internal.objects.annotations.Property;
  34 import jdk.nashorn.internal.objects.annotations.ScriptClass;
  35 import jdk.nashorn.internal.runtime.JSType;
  36 import jdk.nashorn.internal.runtime.PropertyDescriptor;
  37 import jdk.nashorn.internal.runtime.PropertyMap;
  38 import jdk.nashorn.internal.runtime.ScriptFunction;
  39 import jdk.nashorn.internal.runtime.ScriptObject;
  40 import jdk.nashorn.internal.runtime.ScriptRuntime;
  41 
  42 /**
  43  * Accessor Property descriptor is used to represent attributes an object property
  44  * that either has a getter or a setter.
  45  *
  46  * See ECMA 8.10 The Property Descriptor and Property Identifier Specification Types
  47  *
  48  */
  49 @ScriptClass("AccessorPropertyDescriptor")
  50 public final class AccessorPropertyDescriptor extends ScriptObject implements PropertyDescriptor {
  51     /** is this property configurable? */
  52     @Property
  53     public Object configurable;
  54 
  55     /** is this property enumerable? */
  56     @Property
  57     public Object enumerable;
  58 
  59     /** getter for property */
  60     @Property
  61     public Object get;
  62 
  63     /** setter for property */
  64     @Property
  65     public Object set;
  66 
  67     // initialized by nasgen
  68     private static PropertyMap $nasgenmap$;
  69 
  70     AccessorPropertyDescriptor(final boolean configurable, final boolean enumerable, final Object get, final Object set, final Global global) {
  71         super(global.getObjectPrototype(), $nasgenmap$);
  72         this.configurable = configurable;
  73         this.enumerable   = enumerable;
  74         this.get          = get;
  75         this.set          = set;
  76     }
  77 
  78     @Override
  79     public boolean isConfigurable() {
  80         return JSType.toBoolean(configurable);
  81     }
  82 
  83     @Override
  84     public boolean isEnumerable() {
  85         return JSType.toBoolean(enumerable);
  86     }
  87 
  88     @Override
  89     public boolean isWritable() {
  90         // Not applicable for this. But simplifies flag calculations.
  91         return true;
  92     }
  93 
  94     @Override
  95     public Object getValue() {
  96         throw new UnsupportedOperationException("value");
  97     }
  98 
  99     @Override
 100     public ScriptFunction getGetter() {
 101         return (get instanceof ScriptFunction) ? (ScriptFunction)get : null;
 102     }
 103 
 104     @Override
 105     public ScriptFunction getSetter() {
 106         return (set instanceof ScriptFunction) ? (ScriptFunction)set : null;
 107     }
 108 
 109     @Override
 110     public void setConfigurable(final boolean flag) {
 111         this.configurable = flag;
 112     }
 113 
 114     @Override
 115     public void setEnumerable(final boolean flag) {
 116         this.enumerable = flag;
 117     }
 118 
 119     @Override
 120     public void setWritable(final boolean flag) {
 121         throw new UnsupportedOperationException("set writable");
 122     }
 123 
 124     @Override
 125     public void setValue(final Object value) {
 126         throw new UnsupportedOperationException("set value");
 127     }
 128 
 129     @Override
 130     public void setGetter(final Object getter) {
 131         this.get = getter;
 132     }
 133 
 134     @Override
 135     public void setSetter(final Object setter) {
 136         this.set = setter;
 137     }
 138 
 139     @Override
 140     public PropertyDescriptor fillFrom(final ScriptObject sobj) {
 141         if (sobj.has(CONFIGURABLE)) {
 142             this.configurable = JSType.toBoolean(sobj.get(CONFIGURABLE));
 143         } else {
 144             delete(CONFIGURABLE, false);
 145         }
 146 
 147         if (sobj.has(ENUMERABLE)) {
 148             this.enumerable = JSType.toBoolean(sobj.get(ENUMERABLE));
 149         } else {
 150             delete(ENUMERABLE, false);
 151         }
 152 
 153         if (sobj.has(GET)) {
 154             final Object getter = sobj.get(GET);
 155             if (getter == UNDEFINED || getter instanceof ScriptFunction) {
 156                 this.get = getter;
 157             } else {
 158                 throw typeError("not.a.function", ScriptRuntime.safeToString(getter));
 159             }
 160         } else {
 161             delete(GET, false);
 162         }
 163 
 164         if (sobj.has(SET)) {
 165             final Object setter = sobj.get(SET);
 166             if (setter == UNDEFINED || setter instanceof ScriptFunction) {
 167                 this.set = setter;
 168             } else {
 169                 throw typeError("not.a.function", ScriptRuntime.safeToString(setter));
 170             }
 171         } else {
 172             delete(SET, false);
 173         }
 174 
 175         return this;
 176     }
 177 
 178     @Override
 179     public int type() {
 180         return ACCESSOR;
 181     }
 182 
 183     @Override
 184     public boolean hasAndEquals(final PropertyDescriptor otherDesc) {
 185         if (! (otherDesc instanceof AccessorPropertyDescriptor)) {
 186             return false;
 187         }
 188         final AccessorPropertyDescriptor other = (AccessorPropertyDescriptor)otherDesc;
 189         return (!has(CONFIGURABLE) || sameValue(configurable, other.configurable)) &&
 190                (!has(ENUMERABLE) || sameValue(enumerable, other.enumerable)) &&
 191                (!has(GET) || sameValue(get, other.get)) &&
 192                (!has(SET) || sameValue(set, other.set));
 193     }
 194 
 195     @Override
 196     public boolean equals(final Object obj) {
 197         if (this == obj) {
 198             return true;
 199         }
 200         if (! (obj instanceof AccessorPropertyDescriptor)) {
 201             return false;
 202         }
 203 
 204         final AccessorPropertyDescriptor other = (AccessorPropertyDescriptor)obj;
 205         return sameValue(configurable, other.configurable) &&
 206                sameValue(enumerable, other.enumerable) &&
 207                sameValue(get, other.get) &&
 208                sameValue(set, other.set);
 209     }
 210 
 211     @Override
 212     public int hashCode() {
 213         int hash = 7;
 214         hash = 41 * hash + Objects.hashCode(this.configurable);
 215         hash = 41 * hash + Objects.hashCode(this.enumerable);
 216         hash = 41 * hash + Objects.hashCode(this.get);
 217         hash = 41 * hash + Objects.hashCode(this.set);
 218         return hash;
 219     }
 220 }