fbca982d8ce881f5316271d19bdef8401d72f250
[platform/upstream/v8.git] / src / proxy.js
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 (function(global, utils) {
6
7 "use strict";
8
9 %CheckIsBootstrapping();
10
11 // ----------------------------------------------------------------------------
12 // Imports
13
14 var GlobalFunction = global.Function;
15 var GlobalObject = global.Object;
16
17 var ToNameArray;
18
19 utils.Import(function(from) {
20   ToNameArray = from.ToNameArray;
21 });
22
23 //----------------------------------------------------------------------------
24
25 function ProxyCreate(handler, proto) {
26   if (!IS_SPEC_OBJECT(handler))
27     throw MakeTypeError(kProxyHandlerNonObject, "create")
28   if (IS_UNDEFINED(proto))
29     proto = null
30   else if (!(IS_SPEC_OBJECT(proto) || IS_NULL(proto)))
31     throw MakeTypeError(kProxyProtoNonObject)
32   return %CreateJSProxy(handler, proto)
33 }
34
35 function ProxyCreateFunction(handler, callTrap, constructTrap) {
36   if (!IS_SPEC_OBJECT(handler))
37     throw MakeTypeError(kProxyHandlerNonObject, "createFunction")
38   if (!IS_CALLABLE(callTrap))
39     throw MakeTypeError(kProxyTrapFunctionExpected, "call")
40   if (IS_UNDEFINED(constructTrap)) {
41     constructTrap = DerivedConstructTrap(callTrap)
42   } else if (IS_CALLABLE(constructTrap)) {
43     // Make sure the trap receives 'undefined' as this.
44     var construct = constructTrap
45     constructTrap = function() {
46       return %Apply(construct, UNDEFINED, arguments, 0, %_ArgumentsLength());
47     }
48   } else {
49     throw MakeTypeError(kProxyTrapFunctionExpected, "construct")
50   }
51   return %CreateJSFunctionProxy(
52     handler, callTrap, constructTrap, GlobalFunction.prototype)
53 }
54
55 // -------------------------------------------------------------------
56 // Proxy Builtins
57
58 function DerivedConstructTrap(callTrap) {
59   return function() {
60     var proto = this.prototype
61     if (!IS_SPEC_OBJECT(proto)) proto = GlobalObject.prototype
62     var obj = { __proto__: proto };
63     var result = %Apply(callTrap, obj, arguments, 0, %_ArgumentsLength());
64     return IS_SPEC_OBJECT(result) ? result : obj
65   }
66 }
67
68 function DelegateCallAndConstruct(callTrap, constructTrap) {
69   return function() {
70     return %Apply(%_IsConstructCall() ? constructTrap : callTrap,
71                   this, arguments, 0, %_ArgumentsLength())
72   }
73 }
74
75 function DerivedGetTrap(receiver, name) {
76   var desc = this.getPropertyDescriptor(name)
77   if (IS_UNDEFINED(desc)) { return desc }
78   if ('value' in desc) {
79     return desc.value
80   } else {
81     if (IS_UNDEFINED(desc.get)) { return desc.get }
82     // The proposal says: desc.get.call(receiver)
83     return %_CallFunction(receiver, desc.get)
84   }
85 }
86
87 function DerivedSetTrap(receiver, name, val) {
88   var desc = this.getOwnPropertyDescriptor(name)
89   if (desc) {
90     if ('writable' in desc) {
91       if (desc.writable) {
92         desc.value = val
93         this.defineProperty(name, desc)
94         return true
95       } else {
96         return false
97       }
98     } else { // accessor
99       if (desc.set) {
100         // The proposal says: desc.set.call(receiver, val)
101         %_CallFunction(receiver, val, desc.set)
102         return true
103       } else {
104         return false
105       }
106     }
107   }
108   desc = this.getPropertyDescriptor(name)
109   if (desc) {
110     if ('writable' in desc) {
111       if (desc.writable) {
112         // fall through
113       } else {
114         return false
115       }
116     } else { // accessor
117       if (desc.set) {
118         // The proposal says: desc.set.call(receiver, val)
119         %_CallFunction(receiver, val, desc.set)
120         return true
121       } else {
122         return false
123       }
124     }
125   }
126   this.defineProperty(name, {
127     value: val,
128     writable: true,
129     enumerable: true,
130     configurable: true});
131   return true;
132 }
133
134 function DerivedHasTrap(name) {
135   return !!this.getPropertyDescriptor(name)
136 }
137
138 function DerivedHasOwnTrap(name) {
139   return !!this.getOwnPropertyDescriptor(name)
140 }
141
142 function DerivedKeysTrap() {
143   var names = this.getOwnPropertyNames()
144   var enumerableNames = []
145   for (var i = 0, count = 0; i < names.length; ++i) {
146     var name = names[i]
147     if (IS_SYMBOL(name)) continue
148     var desc = this.getOwnPropertyDescriptor(TO_STRING_INLINE(name))
149     if (!IS_UNDEFINED(desc) && desc.enumerable) {
150       enumerableNames[count++] = names[i]
151     }
152   }
153   return enumerableNames
154 }
155
156 function DerivedEnumerateTrap() {
157   var names = this.getPropertyNames()
158   var enumerableNames = []
159   for (var i = 0, count = 0; i < names.length; ++i) {
160     var name = names[i]
161     if (IS_SYMBOL(name)) continue
162     var desc = this.getPropertyDescriptor(TO_STRING_INLINE(name))
163     if (!IS_UNDEFINED(desc)) {
164       if (!desc.configurable) {
165         throw MakeTypeError(kProxyPropNotConfigurable,
166                             this, name, "getPropertyDescriptor")
167       }
168       if (desc.enumerable) enumerableNames[count++] = names[i]
169     }
170   }
171   return enumerableNames
172 }
173
174 function ProxyEnumerate(proxy) {
175   var handler = %GetHandler(proxy)
176   if (IS_UNDEFINED(handler.enumerate)) {
177     return %Apply(DerivedEnumerateTrap, handler, [], 0, 0)
178   } else {
179     return ToNameArray(handler.enumerate(), "enumerate", false)
180   }
181 }
182
183 //-------------------------------------------------------------------
184
185 var Proxy = new GlobalObject();
186 %AddNamedProperty(global, "Proxy", Proxy, DONT_ENUM);
187
188 //Set up non-enumerable properties of the Proxy object.
189 utils.InstallFunctions(Proxy, DONT_ENUM, [
190   "create", ProxyCreate,
191   "createFunction", ProxyCreateFunction
192 ])
193
194 // -------------------------------------------------------------------
195 // Exports
196
197 utils.Export(function(to) {
198   to.ProxyDelegateCallAndConstruct = DelegateCallAndConstruct;
199   to.ProxyDerivedHasOwnTrap = DerivedHasOwnTrap;
200   to.ProxyDerivedKeysTrap = DerivedKeysTrap;
201 });
202
203 %InstallToContext([
204   "derived_get_trap", DerivedGetTrap,
205   "derived_has_trap", DerivedHasTrap,
206   "derived_set_trap", DerivedSetTrap,
207   "proxy_enumerate", ProxyEnumerate,
208 ]);
209
210 })