github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/proxy.go (about) 1 package goja 2 3 import ( 4 "fmt" 5 "reflect" 6 7 "github.com/nuvolaris/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. 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 // so that [sb-1] points to the callee 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 { // we can assume accum is empty 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 }