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