1 package goja
2
3 import (
4 "fmt"
5 "reflect"
6
7 "github.com/dop251/goja/unistring"
8 )
9
10
11
12
13 type Proxy struct {
14 proxy *proxyObject
15 }
16
17 var (
18 proxyType = reflect.TypeOf(Proxy{})
19 )
20
21 type proxyPropIter struct {
22 p *proxyObject
23 names []Value
24 idx int
25 }
26
27 func (i *proxyPropIter) next() (propIterItem, iterNextFunc) {
28 for i.idx < len(i.names) {
29 name := i.names[i.idx]
30 i.idx++
31 return propIterItem{name: name}, i.next
32 }
33 return propIterItem{}, nil
34 }
35
36 func (r *Runtime) newProxyObject(target, handler, proto *Object) *proxyObject {
37 return r._newProxyObject(target, &jsProxyHandler{handler: handler}, proto)
38 }
39
40 func (r *Runtime) _newProxyObject(target *Object, handler proxyHandler, proto *Object) *proxyObject {
41 v := &Object{runtime: r}
42 p := &proxyObject{}
43 v.self = p
44 p.val = v
45 p.class = classObject
46 if proto == nil {
47 p.prototype = r.global.ObjectPrototype
48 } else {
49 p.prototype = proto
50 }
51 p.extensible = false
52 p.init()
53 p.target = target
54 p.handler = handler
55 if call, ok := target.self.assertCallable(); ok {
56 p.call = call
57 }
58 if ctor := target.self.assertConstructor(); ctor != nil {
59 p.ctor = ctor
60 }
61 return p
62 }
63
64 func (p Proxy) Revoke() {
65 p.proxy.revoke()
66 }
67
68 func (p Proxy) Handler() *Object {
69 if handler := p.proxy.handler; handler != nil {
70 return handler.toObject(p.proxy.val.runtime)
71 }
72 return nil
73 }
74
75 func (p Proxy) Target() *Object {
76 return p.proxy.target
77 }
78
79 func (p Proxy) toValue(r *Runtime) Value {
80 if p.proxy == nil {
81 return _null
82 }
83 proxy := p.proxy.val
84 if proxy.runtime != r {
85 panic(r.NewTypeError("Illegal runtime transition of a Proxy"))
86 }
87 return proxy
88 }
89
90 type proxyTrap string
91
92 const (
93 proxy_trap_getPrototypeOf = "getPrototypeOf"
94 proxy_trap_setPrototypeOf = "setPrototypeOf"
95 proxy_trap_isExtensible = "isExtensible"
96 proxy_trap_preventExtensions = "preventExtensions"
97 proxy_trap_getOwnPropertyDescriptor = "getOwnPropertyDescriptor"
98 proxy_trap_defineProperty = "defineProperty"
99 proxy_trap_has = "has"
100 proxy_trap_get = "get"
101 proxy_trap_set = "set"
102 proxy_trap_deleteProperty = "deleteProperty"
103 proxy_trap_ownKeys = "ownKeys"
104 proxy_trap_apply = "apply"
105 proxy_trap_construct = "construct"
106 )
107
108 func (p proxyTrap) String() (name string) {
109 return string(p)
110 }
111
112 type proxyHandler interface {
113 getPrototypeOf(target *Object) (Value, bool)
114 setPrototypeOf(target *Object, proto *Object) (bool, bool)
115 isExtensible(target *Object) (bool, bool)
116 preventExtensions(target *Object) (bool, bool)
117
118 getOwnPropertyDescriptorStr(target *Object, prop unistring.String) (Value, bool)
119 getOwnPropertyDescriptorIdx(target *Object, prop valueInt) (Value, bool)
120 getOwnPropertyDescriptorSym(target *Object, prop *Symbol) (Value, bool)
121
122 definePropertyStr(target *Object, prop unistring.String, desc PropertyDescriptor) (bool, bool)
123 definePropertyIdx(target *Object, prop valueInt, desc PropertyDescriptor) (bool, bool)
124 definePropertySym(target *Object, prop *Symbol, desc PropertyDescriptor) (bool, bool)
125
126 hasStr(target *Object, prop unistring.String) (bool, bool)
127 hasIdx(target *Object, prop valueInt) (bool, bool)
128 hasSym(target *Object, prop *Symbol) (bool, bool)
129
130 getStr(target *Object, prop unistring.String, receiver Value) (Value, bool)
131 getIdx(target *Object, prop valueInt, receiver Value) (Value, bool)
132 getSym(target *Object, prop *Symbol, receiver Value) (Value, bool)
133
134 setStr(target *Object, prop unistring.String, value Value, receiver Value) (bool, bool)
135 setIdx(target *Object, prop valueInt, value Value, receiver Value) (bool, bool)
136 setSym(target *Object, prop *Symbol, value Value, receiver Value) (bool, bool)
137
138 deleteStr(target *Object, prop unistring.String) (bool, bool)
139 deleteIdx(target *Object, prop valueInt) (bool, bool)
140 deleteSym(target *Object, prop *Symbol) (bool, bool)
141
142 ownKeys(target *Object) (*Object, bool)
143 apply(target *Object, this Value, args []Value) (Value, bool)
144 construct(target *Object, args []Value, newTarget *Object) (Value, bool)
145
146 toObject(*Runtime) *Object
147 }
148
149 type jsProxyHandler struct {
150 handler *Object
151 }
152
153 func (h *jsProxyHandler) toObject(*Runtime) *Object {
154 return h.handler
155 }
156
157 func (h *jsProxyHandler) proxyCall(trap proxyTrap, args ...Value) (Value, bool) {
158 r := h.handler.runtime
159
160 if m := toMethod(r.getVStr(h.handler, unistring.String(trap.String()))); m != nil {
161 return m(FunctionCall{
162 This: h.handler,
163 Arguments: args,
164 }), true
165 }
166
167 return nil, false
168 }
169
170 func (h *jsProxyHandler) boolProxyCall(trap proxyTrap, args ...Value) (bool, bool) {
171 if v, ok := h.proxyCall(trap, args...); ok {
172 return v.ToBoolean(), true
173 }
174 return false, false
175 }
176
177 func (h *jsProxyHandler) getPrototypeOf(target *Object) (Value, bool) {
178 return h.proxyCall(proxy_trap_getPrototypeOf, target)
179 }
180
181 func (h *jsProxyHandler) setPrototypeOf(target *Object, proto *Object) (bool, bool) {
182 var protoVal Value
183 if proto != nil {
184 protoVal = proto
185 } else {
186 protoVal = _null
187 }
188 return h.boolProxyCall(proxy_trap_setPrototypeOf, target, protoVal)
189 }
190
191 func (h *jsProxyHandler) isExtensible(target *Object) (bool, bool) {
192 return h.boolProxyCall(proxy_trap_isExtensible, target)
193 }
194
195 func (h *jsProxyHandler) preventExtensions(target *Object) (bool, bool) {
196 return h.boolProxyCall(proxy_trap_preventExtensions, target)
197 }
198
199 func (h *jsProxyHandler) getOwnPropertyDescriptorStr(target *Object, prop unistring.String) (Value, bool) {
200 return h.proxyCall(proxy_trap_getOwnPropertyDescriptor, target, stringValueFromRaw(prop))
201 }
202
203 func (h *jsProxyHandler) getOwnPropertyDescriptorIdx(target *Object, prop valueInt) (Value, bool) {
204 return h.proxyCall(proxy_trap_getOwnPropertyDescriptor, target, prop.toString())
205 }
206
207 func (h *jsProxyHandler) getOwnPropertyDescriptorSym(target *Object, prop *Symbol) (Value, bool) {
208 return h.proxyCall(proxy_trap_getOwnPropertyDescriptor, target, prop)
209 }
210
211 func (h *jsProxyHandler) definePropertyStr(target *Object, prop unistring.String, desc PropertyDescriptor) (bool, bool) {
212 return h.boolProxyCall(proxy_trap_defineProperty, target, stringValueFromRaw(prop), desc.toValue(h.handler.runtime))
213 }
214
215 func (h *jsProxyHandler) definePropertyIdx(target *Object, prop valueInt, desc PropertyDescriptor) (bool, bool) {
216 return h.boolProxyCall(proxy_trap_defineProperty, target, prop.toString(), desc.toValue(h.handler.runtime))
217 }
218
219 func (h *jsProxyHandler) definePropertySym(target *Object, prop *Symbol, desc PropertyDescriptor) (bool, bool) {
220 return h.boolProxyCall(proxy_trap_defineProperty, target, prop, desc.toValue(h.handler.runtime))
221 }
222
223 func (h *jsProxyHandler) hasStr(target *Object, prop unistring.String) (bool, bool) {
224 return h.boolProxyCall(proxy_trap_has, target, stringValueFromRaw(prop))
225 }
226
227 func (h *jsProxyHandler) hasIdx(target *Object, prop valueInt) (bool, bool) {
228 return h.boolProxyCall(proxy_trap_has, target, prop.toString())
229 }
230
231 func (h *jsProxyHandler) hasSym(target *Object, prop *Symbol) (bool, bool) {
232 return h.boolProxyCall(proxy_trap_has, target, prop)
233 }
234
235 func (h *jsProxyHandler) getStr(target *Object, prop unistring.String, receiver Value) (Value, bool) {
236 return h.proxyCall(proxy_trap_get, target, stringValueFromRaw(prop), receiver)
237 }
238
239 func (h *jsProxyHandler) getIdx(target *Object, prop valueInt, receiver Value) (Value, bool) {
240 return h.proxyCall(proxy_trap_get, target, prop.toString(), receiver)
241 }
242
243 func (h *jsProxyHandler) getSym(target *Object, prop *Symbol, receiver Value) (Value, bool) {
244 return h.proxyCall(proxy_trap_get, target, prop, receiver)
245 }
246
247 func (h *jsProxyHandler) setStr(target *Object, prop unistring.String, value Value, receiver Value) (bool, bool) {
248 return h.boolProxyCall(proxy_trap_set, target, stringValueFromRaw(prop), value, receiver)
249 }
250
251 func (h *jsProxyHandler) setIdx(target *Object, prop valueInt, value Value, receiver Value) (bool, bool) {
252 return h.boolProxyCall(proxy_trap_set, target, prop.toString(), value, receiver)
253 }
254
255 func (h *jsProxyHandler) setSym(target *Object, prop *Symbol, value Value, receiver Value) (bool, bool) {
256 return h.boolProxyCall(proxy_trap_set, target, prop, value, receiver)
257 }
258
259 func (h *jsProxyHandler) deleteStr(target *Object, prop unistring.String) (bool, bool) {
260 return h.boolProxyCall(proxy_trap_deleteProperty, target, stringValueFromRaw(prop))
261 }
262
263 func (h *jsProxyHandler) deleteIdx(target *Object, prop valueInt) (bool, bool) {
264 return h.boolProxyCall(proxy_trap_deleteProperty, target, prop.toString())
265 }
266
267 func (h *jsProxyHandler) deleteSym(target *Object, prop *Symbol) (bool, bool) {
268 return h.boolProxyCall(proxy_trap_deleteProperty, target, prop)
269 }
270
271 func (h *jsProxyHandler) ownKeys(target *Object) (*Object, bool) {
272 if v, ok := h.proxyCall(proxy_trap_ownKeys, target); ok {
273 return h.handler.runtime.toObject(v), true
274 }
275 return nil, false
276 }
277
278 func (h *jsProxyHandler) apply(target *Object, this Value, args []Value) (Value, bool) {
279 return h.proxyCall(proxy_trap_apply, target, this, h.handler.runtime.newArrayValues(args))
280 }
281
282 func (h *jsProxyHandler) construct(target *Object, args []Value, newTarget *Object) (Value, bool) {
283 return h.proxyCall(proxy_trap_construct, target, h.handler.runtime.newArrayValues(args), newTarget)
284 }
285
286 type proxyObject struct {
287 baseObject
288 target *Object
289 handler proxyHandler
290 call func(FunctionCall) Value
291 ctor func(args []Value, newTarget *Object) *Object
292 }
293
294 func (p *proxyObject) checkHandler() proxyHandler {
295 r := p.val.runtime
296 if handler := p.handler; handler != nil {
297 return handler
298 }
299 panic(r.NewTypeError("Proxy already revoked"))
300 }
301
302 func (p *proxyObject) proto() *Object {
303 target := p.target
304 if v, ok := p.checkHandler().getPrototypeOf(target); ok {
305 var handlerProto *Object
306 if v != _null {
307 handlerProto = p.val.runtime.toObject(v)
308 }
309 if !target.self.isExtensible() && !p.__sameValue(handlerProto, target.self.proto()) {
310 panic(p.val.runtime.NewTypeError("'getPrototypeOf' on proxy: proxy target is non-extensible but the trap did not return its actual prototype"))
311 }
312 return handlerProto
313 }
314
315 return target.self.proto()
316 }
317
318 func (p *proxyObject) setProto(proto *Object, throw bool) bool {
319 target := p.target
320 if v, ok := p.checkHandler().setPrototypeOf(target, proto); ok {
321 if v {
322 if !target.self.isExtensible() && !p.__sameValue(proto, target.self.proto()) {
323 panic(p.val.runtime.NewTypeError("'setPrototypeOf' on proxy: trap returned truish for setting a new prototype on the non-extensible proxy target"))
324 }
325 return true
326 } else {
327 p.val.runtime.typeErrorResult(throw, "'setPrototypeOf' on proxy: trap returned falsish")
328 return false
329 }
330 }
331
332 return target.self.setProto(proto, throw)
333 }
334
335 func (p *proxyObject) isExtensible() bool {
336 target := p.target
337 if booleanTrapResult, ok := p.checkHandler().isExtensible(p.target); ok {
338 if te := target.self.isExtensible(); booleanTrapResult != te {
339 panic(p.val.runtime.NewTypeError("'isExtensible' on proxy: trap result does not reflect extensibility of proxy target (which is '%v')", te))
340 }
341 return booleanTrapResult
342 }
343
344 return target.self.isExtensible()
345 }
346
347 func (p *proxyObject) preventExtensions(throw bool) bool {
348 target := p.target
349 if booleanTrapResult, ok := p.checkHandler().preventExtensions(target); ok {
350 if !booleanTrapResult {
351 p.val.runtime.typeErrorResult(throw, "'preventExtensions' on proxy: trap returned falsish")
352 return false
353 }
354 if te := target.self.isExtensible(); booleanTrapResult && te {
355 panic(p.val.runtime.NewTypeError("'preventExtensions' on proxy: trap returned truish but the proxy target is extensible"))
356 }
357 }
358
359 return target.self.preventExtensions(throw)
360 }
361
362 func propToValueProp(v Value) *valueProperty {
363 if v == nil {
364 return nil
365 }
366 if v, ok := v.(*valueProperty); ok {
367 return v
368 }
369 return &valueProperty{
370 value: v,
371 writable: true,
372 configurable: true,
373 enumerable: true,
374 }
375 }
376
377 func (p *proxyObject) proxyDefineOwnPropertyPreCheck(trapResult, throw bool) bool {
378 if !trapResult {
379 p.val.runtime.typeErrorResult(throw, "'defineProperty' on proxy: trap returned falsish")
380 return false
381 }
382 return true
383 }
384
385 func (p *proxyObject) proxyDefineOwnPropertyPostCheck(prop Value, target *Object, descr PropertyDescriptor) {
386 targetDesc := propToValueProp(prop)
387 extensibleTarget := target.self.isExtensible()
388 settingConfigFalse := descr.Configurable == FLAG_FALSE
389 if targetDesc == nil {
390 if !extensibleTarget {
391 panic(p.val.runtime.NewTypeError())
392 }
393 if settingConfigFalse {
394 panic(p.val.runtime.NewTypeError())
395 }
396 } else {
397 if !p.__isCompatibleDescriptor(extensibleTarget, &descr, targetDesc) {
398 panic(p.val.runtime.NewTypeError())
399 }
400 if settingConfigFalse && targetDesc.configurable {
401 panic(p.val.runtime.NewTypeError())
402 }
403 if targetDesc.value != nil && !targetDesc.configurable && targetDesc.writable {
404 if descr.Writable == FLAG_FALSE {
405 panic(p.val.runtime.NewTypeError())
406 }
407 }
408 }
409 }
410
411 func (p *proxyObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
412 target := p.target
413 if booleanTrapResult, ok := p.checkHandler().definePropertyStr(target, name, descr); ok {
414 if !p.proxyDefineOwnPropertyPreCheck(booleanTrapResult, throw) {
415 return false
416 }
417 p.proxyDefineOwnPropertyPostCheck(target.self.getOwnPropStr(name), target, descr)
418 return true
419 }
420 return target.self.defineOwnPropertyStr(name, descr, throw)
421 }
422
423 func (p *proxyObject) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
424 target := p.target
425 if booleanTrapResult, ok := p.checkHandler().definePropertyIdx(target, idx, descr); ok {
426 if !p.proxyDefineOwnPropertyPreCheck(booleanTrapResult, throw) {
427 return false
428 }
429 p.proxyDefineOwnPropertyPostCheck(target.self.getOwnPropIdx(idx), target, descr)
430 return true
431 }
432
433 return target.self.defineOwnPropertyIdx(idx, descr, throw)
434 }
435
436 func (p *proxyObject) defineOwnPropertySym(s *Symbol, descr PropertyDescriptor, throw bool) bool {
437 target := p.target
438 if booleanTrapResult, ok := p.checkHandler().definePropertySym(target, s, descr); ok {
439 if !p.proxyDefineOwnPropertyPreCheck(booleanTrapResult, throw) {
440 return false
441 }
442 p.proxyDefineOwnPropertyPostCheck(target.self.getOwnPropSym(s), target, descr)
443 return true
444 }
445
446 return target.self.defineOwnPropertySym(s, descr, throw)
447 }
448
449 func (p *proxyObject) proxyHasChecks(targetProp Value, target *Object, name fmt.Stringer) {
450 targetDesc := propToValueProp(targetProp)
451 if targetDesc != nil {
452 if !targetDesc.configurable {
453 panic(p.val.runtime.NewTypeError("'has' on proxy: trap returned falsish for property '%s' which exists in the proxy target as non-configurable", name.String()))
454 }
455 if !target.self.isExtensible() {
456 panic(p.val.runtime.NewTypeError("'has' on proxy: trap returned falsish for property '%s' but the proxy target is not extensible", name.String()))
457 }
458 }
459 }
460
461 func (p *proxyObject) hasPropertyStr(name unistring.String) bool {
462 target := p.target
463 if b, ok := p.checkHandler().hasStr(target, name); ok {
464 if !b {
465 p.proxyHasChecks(target.self.getOwnPropStr(name), target, name)
466 }
467 return b
468 }
469
470 return target.self.hasPropertyStr(name)
471 }
472
473 func (p *proxyObject) hasPropertyIdx(idx valueInt) bool {
474 target := p.target
475 if b, ok := p.checkHandler().hasIdx(target, idx); ok {
476 if !b {
477 p.proxyHasChecks(target.self.getOwnPropIdx(idx), target, idx)
478 }
479 return b
480 }
481
482 return target.self.hasPropertyIdx(idx)
483 }
484
485 func (p *proxyObject) hasPropertySym(s *Symbol) bool {
486 target := p.target
487 if b, ok := p.checkHandler().hasSym(target, s); ok {
488 if !b {
489 p.proxyHasChecks(target.self.getOwnPropSym(s), target, s)
490 }
491 return b
492 }
493
494 return target.self.hasPropertySym(s)
495 }
496
497 func (p *proxyObject) hasOwnPropertyStr(name unistring.String) bool {
498 return p.getOwnPropStr(name) != nil
499 }
500
501 func (p *proxyObject) hasOwnPropertyIdx(idx valueInt) bool {
502 return p.getOwnPropIdx(idx) != nil
503 }
504
505 func (p *proxyObject) hasOwnPropertySym(s *Symbol) bool {
506 return p.getOwnPropSym(s) != nil
507 }
508
509 func (p *proxyObject) proxyGetOwnPropertyDescriptor(targetProp Value, target *Object, trapResult Value, name fmt.Stringer) Value {
510 r := p.val.runtime
511 targetDesc := propToValueProp(targetProp)
512 var trapResultObj *Object
513 if trapResult != nil && trapResult != _undefined {
514 if obj, ok := trapResult.(*Object); ok {
515 trapResultObj = obj
516 } else {
517 panic(r.NewTypeError("'getOwnPropertyDescriptor' on proxy: trap returned neither object nor undefined for property '%s'", name.String()))
518 }
519 }
520 if trapResultObj == nil {
521 if targetDesc == nil {
522 return nil
523 }
524 if !targetDesc.configurable {
525 panic(r.NewTypeError())
526 }
527 if !target.self.isExtensible() {
528 panic(r.NewTypeError())
529 }
530 return nil
531 }
532 extensibleTarget := target.self.isExtensible()
533 resultDesc := r.toPropertyDescriptor(trapResultObj)
534 resultDesc.complete()
535 if !p.__isCompatibleDescriptor(extensibleTarget, &resultDesc, targetDesc) {
536 panic(r.NewTypeError("'getOwnPropertyDescriptor' on proxy: trap returned descriptor for property '%s' that is incompatible with the existing property in the proxy target", name.String()))
537 }
538
539 if resultDesc.Configurable == FLAG_FALSE {
540 if targetDesc == nil {
541 panic(r.NewTypeError("'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property '%s' which is non-existent in the proxy target", name.String()))
542 }
543
544 if targetDesc.configurable {
545 panic(r.NewTypeError("'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property '%s' which is configurable in the proxy target", name.String()))
546 }
547
548 if resultDesc.Writable == FLAG_FALSE && targetDesc.writable {
549 panic(r.NewTypeError("'getOwnPropertyDescriptor' on proxy: trap reported non-configurable and writable for property '%s' which is non-configurable, non-writable in the proxy target", name.String()))
550 }
551 }
552
553 if resultDesc.Writable == FLAG_TRUE && resultDesc.Configurable == FLAG_TRUE &&
554 resultDesc.Enumerable == FLAG_TRUE {
555 return resultDesc.Value
556 }
557 return r.toValueProp(trapResultObj)
558 }
559
560 func (p *proxyObject) getOwnPropStr(name unistring.String) Value {
561 target := p.target
562 if v, ok := p.checkHandler().getOwnPropertyDescriptorStr(target, name); ok {
563 return p.proxyGetOwnPropertyDescriptor(target.self.getOwnPropStr(name), target, v, name)
564 }
565
566 return target.self.getOwnPropStr(name)
567 }
568
569 func (p *proxyObject) getOwnPropIdx(idx valueInt) Value {
570 target := p.target
571 if v, ok := p.checkHandler().getOwnPropertyDescriptorIdx(target, idx); ok {
572 return p.proxyGetOwnPropertyDescriptor(target.self.getOwnPropIdx(idx), target, v, idx)
573 }
574
575 return target.self.getOwnPropIdx(idx)
576 }
577
578 func (p *proxyObject) getOwnPropSym(s *Symbol) Value {
579 target := p.target
580 if v, ok := p.checkHandler().getOwnPropertyDescriptorSym(target, s); ok {
581 return p.proxyGetOwnPropertyDescriptor(target.self.getOwnPropSym(s), target, v, s)
582 }
583
584 return target.self.getOwnPropSym(s)
585 }
586
587 func (p *proxyObject) proxyGetChecks(targetProp, trapResult Value, name fmt.Stringer) {
588 if targetDesc, ok := targetProp.(*valueProperty); ok {
589 if !targetDesc.accessor {
590 if !targetDesc.writable && !targetDesc.configurable && !trapResult.SameAs(targetDesc.value) {
591 panic(p.val.runtime.NewTypeError("'get' on proxy: property '%s' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected '%s' but got '%s')", name.String(), nilSafe(targetDesc.value), ret))
592 }
593 } else {
594 if !targetDesc.configurable && targetDesc.getterFunc == nil && trapResult != _undefined {
595 panic(p.val.runtime.NewTypeError("'get' on proxy: property '%s' is a non-configurable accessor property on the proxy target and does not have a getter function, but the trap did not return 'undefined' (got '%s')", name.String(), ret))
596 }
597 }
598 }
599 }
600
601 func (p *proxyObject) getStr(name unistring.String, receiver Value) Value {
602 target := p.target
603 if receiver == nil {
604 receiver = p.val
605 }
606 if v, ok := p.checkHandler().getStr(target, name, receiver); ok {
607 p.proxyGetChecks(target.self.getOwnPropStr(name), v, name)
608 return v
609 }
610 return target.self.getStr(name, receiver)
611 }
612
613 func (p *proxyObject) getIdx(idx valueInt, receiver Value) Value {
614 target := p.target
615 if receiver == nil {
616 receiver = p.val
617 }
618 if v, ok := p.checkHandler().getIdx(target, idx, receiver); ok {
619 p.proxyGetChecks(target.self.getOwnPropIdx(idx), v, idx)
620 return v
621 }
622 return target.self.getIdx(idx, receiver)
623 }
624
625 func (p *proxyObject) getSym(s *Symbol, receiver Value) Value {
626 target := p.target
627 if receiver == nil {
628 receiver = p.val
629 }
630 if v, ok := p.checkHandler().getSym(target, s, receiver); ok {
631 p.proxyGetChecks(target.self.getOwnPropSym(s), v, s)
632 return v
633 }
634
635 return target.self.getSym(s, receiver)
636 }
637
638 func (p *proxyObject) proxySetPreCheck(trapResult, throw bool, name fmt.Stringer) bool {
639 if !trapResult {
640 p.val.runtime.typeErrorResult(throw, "'set' on proxy: trap returned falsish for property '%s'", name.String())
641 }
642 return trapResult
643 }
644
645 func (p *proxyObject) proxySetPostCheck(targetProp, value Value, name fmt.Stringer) {
646 if prop, ok := targetProp.(*valueProperty); ok {
647 if prop.accessor {
648 if !prop.configurable && prop.setterFunc == nil {
649 panic(p.val.runtime.NewTypeError("'set' on proxy: trap returned truish for property '%s' which exists in the proxy target as a non-configurable and non-writable accessor property without a setter", name.String()))
650 }
651 } else if !prop.configurable && !prop.writable && !p.__sameValue(prop.value, value) {
652 panic(p.val.runtime.NewTypeError("'set' on proxy: trap returned truish for property '%s' which exists in the proxy target as a non-configurable and non-writable data property with a different value", name.String()))
653 }
654 }
655 }
656
657 func (p *proxyObject) proxySetStr(name unistring.String, value, receiver Value, throw bool) bool {
658 target := p.target
659 if v, ok := p.checkHandler().setStr(target, name, value, receiver); ok {
660 if p.proxySetPreCheck(v, throw, name) {
661 p.proxySetPostCheck(target.self.getOwnPropStr(name), value, name)
662 return true
663 }
664 return false
665 }
666 return target.setStr(name, value, receiver, throw)
667 }
668
669 func (p *proxyObject) proxySetIdx(idx valueInt, value, receiver Value, throw bool) bool {
670 target := p.target
671 if v, ok := p.checkHandler().setIdx(target, idx, value, receiver); ok {
672 if p.proxySetPreCheck(v, throw, idx) {
673 p.proxySetPostCheck(target.self.getOwnPropIdx(idx), value, idx)
674 return true
675 }
676 return false
677 }
678 return target.setIdx(idx, value, receiver, throw)
679 }
680
681 func (p *proxyObject) proxySetSym(s *Symbol, value, receiver Value, throw bool) bool {
682 target := p.target
683 if v, ok := p.checkHandler().setSym(target, s, value, receiver); ok {
684 if p.proxySetPreCheck(v, throw, s) {
685 p.proxySetPostCheck(target.self.getOwnPropSym(s), value, s)
686 return true
687 }
688 return false
689 }
690 return target.setSym(s, value, receiver, throw)
691 }
692
693 func (p *proxyObject) setOwnStr(name unistring.String, v Value, throw bool) bool {
694 return p.proxySetStr(name, v, p.val, throw)
695 }
696
697 func (p *proxyObject) setOwnIdx(idx valueInt, v Value, throw bool) bool {
698 return p.proxySetIdx(idx, v, p.val, throw)
699 }
700
701 func (p *proxyObject) setOwnSym(s *Symbol, v Value, throw bool) bool {
702 return p.proxySetSym(s, v, p.val, throw)
703 }
704
705 func (p *proxyObject) setForeignStr(name unistring.String, v, receiver Value, throw bool) (bool, bool) {
706 return p.proxySetStr(name, v, receiver, throw), true
707 }
708
709 func (p *proxyObject) setForeignIdx(idx valueInt, v, receiver Value, throw bool) (bool, bool) {
710 return p.proxySetIdx(idx, v, receiver, throw), true
711 }
712
713 func (p *proxyObject) setForeignSym(s *Symbol, v, receiver Value, throw bool) (bool, bool) {
714 return p.proxySetSym(s, v, receiver, throw), true
715 }
716
717 func (p *proxyObject) proxyDeleteCheck(trapResult bool, targetProp Value, name fmt.Stringer, target *Object, throw bool) {
718 if trapResult {
719 if targetProp == nil {
720 return
721 }
722 if targetDesc, ok := targetProp.(*valueProperty); ok {
723 if !targetDesc.configurable {
724 panic(p.val.runtime.NewTypeError("'deleteProperty' on proxy: property '%s' is a non-configurable property but the trap returned truish", name.String()))
725 }
726 }
727 if !target.self.isExtensible() {
728 panic(p.val.runtime.NewTypeError("'deleteProperty' on proxy: trap returned truish for property '%s' but the proxy target is non-extensible", name.String()))
729 }
730 } else {
731 p.val.runtime.typeErrorResult(throw, "'deleteProperty' on proxy: trap returned falsish for property '%s'", name.String())
732 }
733 }
734
735 func (p *proxyObject) deleteStr(name unistring.String, throw bool) bool {
736 target := p.target
737 if v, ok := p.checkHandler().deleteStr(target, name); ok {
738 p.proxyDeleteCheck(v, target.self.getOwnPropStr(name), name, target, throw)
739 return v
740 }
741
742 return target.self.deleteStr(name, throw)
743 }
744
745 func (p *proxyObject) deleteIdx(idx valueInt, throw bool) bool {
746 target := p.target
747 if v, ok := p.checkHandler().deleteIdx(target, idx); ok {
748 p.proxyDeleteCheck(v, target.self.getOwnPropIdx(idx), idx, target, throw)
749 return v
750 }
751
752 return target.self.deleteIdx(idx, throw)
753 }
754
755 func (p *proxyObject) deleteSym(s *Symbol, throw bool) bool {
756 target := p.target
757 if v, ok := p.checkHandler().deleteSym(target, s); ok {
758 p.proxyDeleteCheck(v, target.self.getOwnPropSym(s), s, target, throw)
759 return v
760 }
761
762 return target.self.deleteSym(s, throw)
763 }
764
765 func (p *proxyObject) keys(all bool, _ []Value) []Value {
766 if v, ok := p.proxyOwnKeys(); ok {
767 if !all {
768 k := 0
769 for i, key := range v {
770 prop := p.val.getOwnProp(key)
771 if prop == nil || prop == _undefined {
772 continue
773 }
774 if prop, ok := prop.(*valueProperty); ok && !prop.enumerable {
775 continue
776 }
777 if k != i {
778 v[k] = v[i]
779 }
780 k++
781 }
782 v = v[:k]
783 }
784 return v
785 }
786 return p.target.self.keys(all, nil)
787 }
788
789 func (p *proxyObject) proxyOwnKeys() ([]Value, bool) {
790 target := p.target
791 if v, ok := p.checkHandler().ownKeys(target); ok {
792 keys := p.val.runtime.toObject(v)
793 var keyList []Value
794 keySet := make(map[Value]struct{})
795 l := toLength(keys.self.getStr("length", nil))
796 for k := int64(0); k < l; k++ {
797 item := keys.self.getIdx(valueInt(k), nil)
798 if _, ok := item.(String); !ok {
799 if _, ok := item.(*Symbol); !ok {
800 panic(p.val.runtime.NewTypeError("%s is not a valid property name", item.String()))
801 }
802 }
803 if _, exists := keySet[item]; exists {
804 panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap returned duplicate entries"))
805 }
806 keyList = append(keyList, item)
807 keySet[item] = struct{}{}
808 }
809 ext := target.self.isExtensible()
810 for item, next := target.self.iterateKeys()(); next != nil; item, next = next() {
811 if _, exists := keySet[item.name]; exists {
812 delete(keySet, item.name)
813 } else {
814 if !ext {
815 panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap result did not include '%s'", item.name.String()))
816 }
817 var prop Value
818 if item.value == nil {
819 prop = target.getOwnProp(item.name)
820 } else {
821 prop = item.value
822 }
823 if prop, ok := prop.(*valueProperty); ok && !prop.configurable {
824 panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap result did not include non-configurable '%s'", item.name.String()))
825 }
826 }
827 }
828 if !ext && len(keyList) > 0 && len(keySet) > 0 {
829 panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap returned extra keys but proxy target is non-extensible"))
830 }
831
832 return keyList, true
833 }
834
835 return nil, false
836 }
837
838 func (p *proxyObject) iterateStringKeys() iterNextFunc {
839 return (&proxyPropIter{
840 p: p,
841 names: p.stringKeys(true, nil),
842 }).next
843 }
844
845 func (p *proxyObject) iterateSymbols() iterNextFunc {
846 return (&proxyPropIter{
847 p: p,
848 names: p.symbols(true, nil),
849 }).next
850 }
851
852 func (p *proxyObject) iterateKeys() iterNextFunc {
853 return (&proxyPropIter{
854 p: p,
855 names: p.keys(true, nil),
856 }).next
857 }
858
859 func (p *proxyObject) assertCallable() (call func(FunctionCall) Value, ok bool) {
860 if p.call != nil {
861 return func(call FunctionCall) Value {
862 return p.apply(call)
863 }, true
864 }
865 return nil, false
866 }
867
868 func (p *proxyObject) vmCall(vm *vm, n int) {
869 vm.pushCtx()
870 vm.prg = nil
871 vm.sb = vm.sp - n
872 ret := p.apply(FunctionCall{This: vm.stack[vm.sp-n-2], Arguments: vm.stack[vm.sp-n : vm.sp]})
873 if ret == nil {
874 ret = _undefined
875 }
876 vm.stack[vm.sp-n-2] = ret
877 vm.popCtx()
878 vm.sp -= n + 1
879 vm.pc++
880 }
881
882 func (p *proxyObject) assertConstructor() func(args []Value, newTarget *Object) *Object {
883 if p.ctor != nil {
884 return p.construct
885 }
886 return nil
887 }
888
889 func (p *proxyObject) apply(call FunctionCall) Value {
890 if p.call == nil {
891 panic(p.val.runtime.NewTypeError("proxy target is not a function"))
892 }
893 if v, ok := p.checkHandler().apply(p.target, nilSafe(call.This), call.Arguments); ok {
894 return v
895 }
896 return p.call(call)
897 }
898
899 func (p *proxyObject) construct(args []Value, newTarget *Object) *Object {
900 if p.ctor == nil {
901 panic(p.val.runtime.NewTypeError("proxy target is not a constructor"))
902 }
903 if newTarget == nil {
904 newTarget = p.val
905 }
906 if v, ok := p.checkHandler().construct(p.target, args, newTarget); ok {
907 return p.val.runtime.toObject(v)
908 }
909 return p.ctor(args, newTarget)
910 }
911
912 func (p *proxyObject) __isCompatibleDescriptor(extensible bool, desc *PropertyDescriptor, current *valueProperty) bool {
913 if current == nil {
914 return extensible
915 }
916
917 if !current.configurable {
918 if desc.Configurable == FLAG_TRUE {
919 return false
920 }
921
922 if desc.Enumerable != FLAG_NOT_SET && desc.Enumerable.Bool() != current.enumerable {
923 return false
924 }
925
926 if desc.IsGeneric() {
927 return true
928 }
929
930 if desc.IsData() != !current.accessor {
931 return desc.Configurable != FLAG_FALSE
932 }
933
934 if desc.IsData() && !current.accessor {
935 if !current.configurable {
936 if desc.Writable == FLAG_TRUE && !current.writable {
937 return false
938 }
939 if !current.writable {
940 if desc.Value != nil && !desc.Value.SameAs(current.value) {
941 return false
942 }
943 }
944 }
945 return true
946 }
947 if desc.IsAccessor() && current.accessor {
948 if !current.configurable {
949 if desc.Setter != nil && desc.Setter.SameAs(current.setterFunc) {
950 return false
951 }
952 if desc.Getter != nil && desc.Getter.SameAs(current.getterFunc) {
953 return false
954 }
955 }
956 }
957 }
958 return true
959 }
960
961 func (p *proxyObject) __sameValue(val1, val2 Value) bool {
962 if val1 == nil && val2 == nil {
963 return true
964 }
965 if val1 != nil {
966 return val1.SameAs(val2)
967 }
968 return false
969 }
970
971 func (p *proxyObject) filterKeys(vals []Value, all, symbols bool) []Value {
972 if !all {
973 k := 0
974 for i, val := range vals {
975 var prop Value
976 if symbols {
977 if s, ok := val.(*Symbol); ok {
978 prop = p.getOwnPropSym(s)
979 } else {
980 continue
981 }
982 } else {
983 if _, ok := val.(*Symbol); !ok {
984 prop = p.getOwnPropStr(val.string())
985 } else {
986 continue
987 }
988 }
989 if prop == nil {
990 continue
991 }
992 if prop, ok := prop.(*valueProperty); ok && !prop.enumerable {
993 continue
994 }
995 if k != i {
996 vals[k] = vals[i]
997 }
998 k++
999 }
1000 vals = vals[:k]
1001 } else {
1002 k := 0
1003 for i, val := range vals {
1004 if _, ok := val.(*Symbol); ok != symbols {
1005 continue
1006 }
1007 if k != i {
1008 vals[k] = vals[i]
1009 }
1010 k++
1011 }
1012 vals = vals[:k]
1013 }
1014 return vals
1015 }
1016
1017 func (p *proxyObject) stringKeys(all bool, _ []Value) []Value {
1018 var keys []Value
1019 if vals, ok := p.proxyOwnKeys(); ok {
1020 keys = vals
1021 } else {
1022 keys = p.target.self.stringKeys(true, nil)
1023 }
1024
1025 return p.filterKeys(keys, all, false)
1026 }
1027
1028 func (p *proxyObject) symbols(all bool, accum []Value) []Value {
1029 var symbols []Value
1030 if vals, ok := p.proxyOwnKeys(); ok {
1031 symbols = vals
1032 } else {
1033 symbols = p.target.self.symbols(true, nil)
1034 }
1035 symbols = p.filterKeys(symbols, all, true)
1036 if accum == nil {
1037 return symbols
1038 }
1039 accum = append(accum, symbols...)
1040 return accum
1041 }
1042
1043 func (p *proxyObject) className() string {
1044 if p.target == nil {
1045 panic(p.val.runtime.NewTypeError("proxy has been revoked"))
1046 }
1047 if p.call != nil || p.ctor != nil {
1048 return classFunction
1049 }
1050 return classObject
1051 }
1052
1053 func (p *proxyObject) typeOf() String {
1054 if p.call == nil {
1055 return stringObjectC
1056 }
1057
1058 return stringFunction
1059 }
1060
1061 func (p *proxyObject) exportType() reflect.Type {
1062 return proxyType
1063 }
1064
1065 func (p *proxyObject) export(*objectExportCtx) interface{} {
1066 return Proxy{
1067 proxy: p,
1068 }
1069 }
1070
1071 func (p *proxyObject) revoke() {
1072 p.handler = nil
1073 p.target = nil
1074 }
1075
View as plain text