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 
AccessorPropertyDescriptor(final boolean configurable, final boolean enumerable, final Object get, final Object set, final Global global)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
isConfigurable()79     public boolean isConfigurable() {
80         return JSType.toBoolean(configurable);
81     }
82 
83     @Override
isEnumerable()84     public boolean isEnumerable() {
85         return JSType.toBoolean(enumerable);
86     }
87 
88     @Override
isWritable()89     public boolean isWritable() {
90         // Not applicable for this. But simplifies flag calculations.
91         return true;
92     }
93 
94     @Override
getValue()95     public Object getValue() {
96         throw new UnsupportedOperationException("value");
97     }
98 
99     @Override
getGetter()100     public ScriptFunction getGetter() {
101         return (get instanceof ScriptFunction) ? (ScriptFunction)get : null;
102     }
103 
104     @Override
getSetter()105     public ScriptFunction getSetter() {
106         return (set instanceof ScriptFunction) ? (ScriptFunction)set : null;
107     }
108 
109     @Override
setConfigurable(final boolean flag)110     public void setConfigurable(final boolean flag) {
111         this.configurable = flag;
112     }
113 
114     @Override
setEnumerable(final boolean flag)115     public void setEnumerable(final boolean flag) {
116         this.enumerable = flag;
117     }
118 
119     @Override
setWritable(final boolean flag)120     public void setWritable(final boolean flag) {
121         throw new UnsupportedOperationException("set writable");
122     }
123 
124     @Override
setValue(final Object value)125     public void setValue(final Object value) {
126         throw new UnsupportedOperationException("set value");
127     }
128 
129     @Override
setGetter(final Object getter)130     public void setGetter(final Object getter) {
131         this.get = getter;
132     }
133 
134     @Override
setSetter(final Object setter)135     public void setSetter(final Object setter) {
136         this.set = setter;
137     }
138 
139     @Override
fillFrom(final ScriptObject sobj)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
type()179     public int type() {
180         return ACCESSOR;
181     }
182 
183     @Override
hasAndEquals(final PropertyDescriptor otherDesc)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
equals(final Object obj)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
toString()212     public String toString() {
213         return '[' + getClass().getSimpleName() + " {configurable=" + configurable + " enumerable=" + enumerable + " getter=" + get + " setter=" + set + "}]";
214     }
215 
216     @Override
hashCode()217     public int hashCode() {
218         int hash = 7;
219         hash = 41 * hash + Objects.hashCode(this.configurable);
220         hash = 41 * hash + Objects.hashCode(this.enumerable);
221         hash = 41 * hash + Objects.hashCode(this.get);
222         hash = 41 * hash + Objects.hashCode(this.set);
223         return hash;
224     }
225 }
226