12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052 |
- package goja
- import (
- "fmt"
- "reflect"
- "github.com/dop251/goja/unistring"
- )
- // Proxy is a Go wrapper around ECMAScript Proxy. Calling Runtime.ToValue() on it
- // returns the underlying Proxy. Calling Export() on an ECMAScript Proxy returns a wrapper.
- // Use Runtime.NewProxy() to create one.
- type Proxy struct {
- proxy *proxyObject
- }
- var (
- proxyType = reflect.TypeOf(Proxy{})
- )
- type proxyPropIter struct {
- p *proxyObject
- names []Value
- idx int
- }
- func (i *proxyPropIter) next() (propIterItem, iterNextFunc) {
- for i.idx < len(i.names) {
- name := i.names[i.idx]
- i.idx++
- return propIterItem{name: name}, i.next
- }
- return propIterItem{}, nil
- }
- func (r *Runtime) newProxyObject(target, handler, proto *Object) *proxyObject {
- return r._newProxyObject(target, &jsProxyHandler{handler: handler}, proto)
- }
- func (r *Runtime) _newProxyObject(target *Object, handler proxyHandler, proto *Object) *proxyObject {
- v := &Object{runtime: r}
- p := &proxyObject{}
- v.self = p
- p.val = v
- p.class = classObject
- if proto == nil {
- p.prototype = r.global.ObjectPrototype
- } else {
- p.prototype = proto
- }
- p.extensible = false
- p.init()
- p.target = target
- p.handler = handler
- if call, ok := target.self.assertCallable(); ok {
- p.call = call
- }
- if ctor := target.self.assertConstructor(); ctor != nil {
- p.ctor = ctor
- }
- return p
- }
- func (p Proxy) Revoke() {
- p.proxy.revoke()
- }
- func (p Proxy) Handler() *Object {
- if handler := p.proxy.handler; handler != nil {
- return handler.toObject(p.proxy.val.runtime)
- }
- return nil
- }
- func (p Proxy) Target() *Object {
- return p.proxy.target
- }
- func (p Proxy) toValue(r *Runtime) Value {
- if p.proxy == nil {
- return _null
- }
- proxy := p.proxy.val
- if proxy.runtime != r {
- panic(r.NewTypeError("Illegal runtime transition of a Proxy"))
- }
- return proxy
- }
- type proxyTrap string
- const (
- proxy_trap_getPrototypeOf = "getPrototypeOf"
- proxy_trap_setPrototypeOf = "setPrototypeOf"
- proxy_trap_isExtensible = "isExtensible"
- proxy_trap_preventExtensions = "preventExtensions"
- proxy_trap_getOwnPropertyDescriptor = "getOwnPropertyDescriptor"
- proxy_trap_defineProperty = "defineProperty"
- proxy_trap_has = "has"
- proxy_trap_get = "get"
- proxy_trap_set = "set"
- proxy_trap_deleteProperty = "deleteProperty"
- proxy_trap_ownKeys = "ownKeys"
- proxy_trap_apply = "apply"
- proxy_trap_construct = "construct"
- )
- func (p proxyTrap) String() (name string) {
- return string(p)
- }
- type proxyHandler interface {
- getPrototypeOf(target *Object) (Value, bool)
- setPrototypeOf(target *Object, proto *Object) (bool, bool)
- isExtensible(target *Object) (bool, bool)
- preventExtensions(target *Object) (bool, bool)
- getOwnPropertyDescriptorStr(target *Object, prop unistring.String) (Value, bool)
- getOwnPropertyDescriptorIdx(target *Object, prop valueInt) (Value, bool)
- getOwnPropertyDescriptorSym(target *Object, prop *Symbol) (Value, bool)
- definePropertyStr(target *Object, prop unistring.String, desc PropertyDescriptor) (bool, bool)
- definePropertyIdx(target *Object, prop valueInt, desc PropertyDescriptor) (bool, bool)
- definePropertySym(target *Object, prop *Symbol, desc PropertyDescriptor) (bool, bool)
- hasStr(target *Object, prop unistring.String) (bool, bool)
- hasIdx(target *Object, prop valueInt) (bool, bool)
- hasSym(target *Object, prop *Symbol) (bool, bool)
- getStr(target *Object, prop unistring.String, receiver Value) (Value, bool)
- getIdx(target *Object, prop valueInt, receiver Value) (Value, bool)
- getSym(target *Object, prop *Symbol, receiver Value) (Value, bool)
- setStr(target *Object, prop unistring.String, value Value, receiver Value) (bool, bool)
- setIdx(target *Object, prop valueInt, value Value, receiver Value) (bool, bool)
- setSym(target *Object, prop *Symbol, value Value, receiver Value) (bool, bool)
- deleteStr(target *Object, prop unistring.String) (bool, bool)
- deleteIdx(target *Object, prop valueInt) (bool, bool)
- deleteSym(target *Object, prop *Symbol) (bool, bool)
- ownKeys(target *Object) (*Object, bool)
- apply(target *Object, this Value, args []Value) (Value, bool)
- construct(target *Object, args []Value, newTarget *Object) (Value, bool)
- toObject(*Runtime) *Object
- }
- type jsProxyHandler struct {
- handler *Object
- }
- func (h *jsProxyHandler) toObject(*Runtime) *Object {
- return h.handler
- }
- func (h *jsProxyHandler) proxyCall(trap proxyTrap, args ...Value) (Value, bool) {
- r := h.handler.runtime
- if m := toMethod(r.getVStr(h.handler, unistring.String(trap.String()))); m != nil {
- return m(FunctionCall{
- This: h.handler,
- Arguments: args,
- }), true
- }
- return nil, false
- }
- func (h *jsProxyHandler) boolProxyCall(trap proxyTrap, args ...Value) (bool, bool) {
- if v, ok := h.proxyCall(trap, args...); ok {
- return v.ToBoolean(), true
- }
- return false, false
- }
- func (h *jsProxyHandler) getPrototypeOf(target *Object) (Value, bool) {
- return h.proxyCall(proxy_trap_getPrototypeOf, target)
- }
- func (h *jsProxyHandler) setPrototypeOf(target *Object, proto *Object) (bool, bool) {
- var protoVal Value
- if proto != nil {
- protoVal = proto
- } else {
- protoVal = _null
- }
- return h.boolProxyCall(proxy_trap_setPrototypeOf, target, protoVal)
- }
- func (h *jsProxyHandler) isExtensible(target *Object) (bool, bool) {
- return h.boolProxyCall(proxy_trap_isExtensible, target)
- }
- func (h *jsProxyHandler) preventExtensions(target *Object) (bool, bool) {
- return h.boolProxyCall(proxy_trap_preventExtensions, target)
- }
- func (h *jsProxyHandler) getOwnPropertyDescriptorStr(target *Object, prop unistring.String) (Value, bool) {
- return h.proxyCall(proxy_trap_getOwnPropertyDescriptor, target, stringValueFromRaw(prop))
- }
- func (h *jsProxyHandler) getOwnPropertyDescriptorIdx(target *Object, prop valueInt) (Value, bool) {
- return h.proxyCall(proxy_trap_getOwnPropertyDescriptor, target, prop.toString())
- }
- func (h *jsProxyHandler) getOwnPropertyDescriptorSym(target *Object, prop *Symbol) (Value, bool) {
- return h.proxyCall(proxy_trap_getOwnPropertyDescriptor, target, prop)
- }
- func (h *jsProxyHandler) definePropertyStr(target *Object, prop unistring.String, desc PropertyDescriptor) (bool, bool) {
- return h.boolProxyCall(proxy_trap_defineProperty, target, stringValueFromRaw(prop), desc.toValue(h.handler.runtime))
- }
- func (h *jsProxyHandler) definePropertyIdx(target *Object, prop valueInt, desc PropertyDescriptor) (bool, bool) {
- return h.boolProxyCall(proxy_trap_defineProperty, target, prop.toString(), desc.toValue(h.handler.runtime))
- }
- func (h *jsProxyHandler) definePropertySym(target *Object, prop *Symbol, desc PropertyDescriptor) (bool, bool) {
- return h.boolProxyCall(proxy_trap_defineProperty, target, prop, desc.toValue(h.handler.runtime))
- }
- func (h *jsProxyHandler) hasStr(target *Object, prop unistring.String) (bool, bool) {
- return h.boolProxyCall(proxy_trap_has, target, stringValueFromRaw(prop))
- }
- func (h *jsProxyHandler) hasIdx(target *Object, prop valueInt) (bool, bool) {
- return h.boolProxyCall(proxy_trap_has, target, prop.toString())
- }
- func (h *jsProxyHandler) hasSym(target *Object, prop *Symbol) (bool, bool) {
- return h.boolProxyCall(proxy_trap_has, target, prop)
- }
- func (h *jsProxyHandler) getStr(target *Object, prop unistring.String, receiver Value) (Value, bool) {
- return h.proxyCall(proxy_trap_get, target, stringValueFromRaw(prop), receiver)
- }
- func (h *jsProxyHandler) getIdx(target *Object, prop valueInt, receiver Value) (Value, bool) {
- return h.proxyCall(proxy_trap_get, target, prop.toString(), receiver)
- }
- func (h *jsProxyHandler) getSym(target *Object, prop *Symbol, receiver Value) (Value, bool) {
- return h.proxyCall(proxy_trap_get, target, prop, receiver)
- }
- func (h *jsProxyHandler) setStr(target *Object, prop unistring.String, value Value, receiver Value) (bool, bool) {
- return h.boolProxyCall(proxy_trap_set, target, stringValueFromRaw(prop), value, receiver)
- }
- func (h *jsProxyHandler) setIdx(target *Object, prop valueInt, value Value, receiver Value) (bool, bool) {
- return h.boolProxyCall(proxy_trap_set, target, prop.toString(), value, receiver)
- }
- func (h *jsProxyHandler) setSym(target *Object, prop *Symbol, value Value, receiver Value) (bool, bool) {
- return h.boolProxyCall(proxy_trap_set, target, prop, value, receiver)
- }
- func (h *jsProxyHandler) deleteStr(target *Object, prop unistring.String) (bool, bool) {
- return h.boolProxyCall(proxy_trap_deleteProperty, target, stringValueFromRaw(prop))
- }
- func (h *jsProxyHandler) deleteIdx(target *Object, prop valueInt) (bool, bool) {
- return h.boolProxyCall(proxy_trap_deleteProperty, target, prop.toString())
- }
- func (h *jsProxyHandler) deleteSym(target *Object, prop *Symbol) (bool, bool) {
- return h.boolProxyCall(proxy_trap_deleteProperty, target, prop)
- }
- func (h *jsProxyHandler) ownKeys(target *Object) (*Object, bool) {
- if v, ok := h.proxyCall(proxy_trap_ownKeys, target); ok {
- return h.handler.runtime.toObject(v), true
- }
- return nil, false
- }
- func (h *jsProxyHandler) apply(target *Object, this Value, args []Value) (Value, bool) {
- return h.proxyCall(proxy_trap_apply, target, this, h.handler.runtime.newArrayValues(args))
- }
- func (h *jsProxyHandler) construct(target *Object, args []Value, newTarget *Object) (Value, bool) {
- return h.proxyCall(proxy_trap_construct, target, h.handler.runtime.newArrayValues(args), newTarget)
- }
- type proxyObject struct {
- baseObject
- target *Object
- handler proxyHandler
- call func(FunctionCall) Value
- ctor func(args []Value, newTarget *Object) *Object
- }
- func (p *proxyObject) checkHandler() proxyHandler {
- r := p.val.runtime
- if handler := p.handler; handler != nil {
- return handler
- }
- panic(r.NewTypeError("Proxy already revoked"))
- }
- func (p *proxyObject) proto() *Object {
- target := p.target
- if v, ok := p.checkHandler().getPrototypeOf(target); ok {
- var handlerProto *Object
- if v != _null {
- handlerProto = p.val.runtime.toObject(v)
- }
- if !target.self.isExtensible() && !p.__sameValue(handlerProto, target.self.proto()) {
- panic(p.val.runtime.NewTypeError("'getPrototypeOf' on proxy: proxy target is non-extensible but the trap did not return its actual prototype"))
- }
- return handlerProto
- }
- return target.self.proto()
- }
- func (p *proxyObject) setProto(proto *Object, throw bool) bool {
- target := p.target
- if v, ok := p.checkHandler().setPrototypeOf(target, proto); ok {
- if v {
- if !target.self.isExtensible() && !p.__sameValue(proto, target.self.proto()) {
- panic(p.val.runtime.NewTypeError("'setPrototypeOf' on proxy: trap returned truish for setting a new prototype on the non-extensible proxy target"))
- }
- return true
- } else {
- p.val.runtime.typeErrorResult(throw, "'setPrototypeOf' on proxy: trap returned falsish")
- return false
- }
- }
- return target.self.setProto(proto, throw)
- }
- func (p *proxyObject) isExtensible() bool {
- target := p.target
- if booleanTrapResult, ok := p.checkHandler().isExtensible(p.target); ok {
- if te := target.self.isExtensible(); booleanTrapResult != te {
- panic(p.val.runtime.NewTypeError("'isExtensible' on proxy: trap result does not reflect extensibility of proxy target (which is '%v')", te))
- }
- return booleanTrapResult
- }
- return target.self.isExtensible()
- }
- func (p *proxyObject) preventExtensions(throw bool) bool {
- target := p.target
- if booleanTrapResult, ok := p.checkHandler().preventExtensions(target); ok {
- if !booleanTrapResult {
- p.val.runtime.typeErrorResult(throw, "'preventExtensions' on proxy: trap returned falsish")
- return false
- }
- if te := target.self.isExtensible(); booleanTrapResult && te {
- panic(p.val.runtime.NewTypeError("'preventExtensions' on proxy: trap returned truish but the proxy target is extensible"))
- }
- }
- return target.self.preventExtensions(throw)
- }
- func propToValueProp(v Value) *valueProperty {
- if v == nil {
- return nil
- }
- if v, ok := v.(*valueProperty); ok {
- return v
- }
- return &valueProperty{
- value: v,
- writable: true,
- configurable: true,
- enumerable: true,
- }
- }
- func (p *proxyObject) proxyDefineOwnPropertyPreCheck(trapResult, throw bool) bool {
- if !trapResult {
- p.val.runtime.typeErrorResult(throw, "'defineProperty' on proxy: trap returned falsish")
- return false
- }
- return true
- }
- func (p *proxyObject) proxyDefineOwnPropertyPostCheck(prop Value, target *Object, descr PropertyDescriptor) {
- targetDesc := propToValueProp(prop)
- extensibleTarget := target.self.isExtensible()
- settingConfigFalse := descr.Configurable == FLAG_FALSE
- if targetDesc == nil {
- if !extensibleTarget {
- panic(p.val.runtime.NewTypeError())
- }
- if settingConfigFalse {
- panic(p.val.runtime.NewTypeError())
- }
- } else {
- if !p.__isCompatibleDescriptor(extensibleTarget, &descr, targetDesc) {
- panic(p.val.runtime.NewTypeError())
- }
- if settingConfigFalse && targetDesc.configurable {
- panic(p.val.runtime.NewTypeError())
- }
- if targetDesc.value != nil && !targetDesc.configurable && targetDesc.writable {
- if descr.Writable == FLAG_FALSE {
- panic(p.val.runtime.NewTypeError())
- }
- }
- }
- }
- func (p *proxyObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
- target := p.target
- if booleanTrapResult, ok := p.checkHandler().definePropertyStr(target, name, descr); ok {
- if !p.proxyDefineOwnPropertyPreCheck(booleanTrapResult, throw) {
- return false
- }
- p.proxyDefineOwnPropertyPostCheck(target.self.getOwnPropStr(name), target, descr)
- return true
- }
- return target.self.defineOwnPropertyStr(name, descr, throw)
- }
- func (p *proxyObject) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
- target := p.target
- if booleanTrapResult, ok := p.checkHandler().definePropertyIdx(target, idx, descr); ok {
- if !p.proxyDefineOwnPropertyPreCheck(booleanTrapResult, throw) {
- return false
- }
- p.proxyDefineOwnPropertyPostCheck(target.self.getOwnPropIdx(idx), target, descr)
- return true
- }
- return target.self.defineOwnPropertyIdx(idx, descr, throw)
- }
- func (p *proxyObject) defineOwnPropertySym(s *Symbol, descr PropertyDescriptor, throw bool) bool {
- target := p.target
- if booleanTrapResult, ok := p.checkHandler().definePropertySym(target, s, descr); ok {
- if !p.proxyDefineOwnPropertyPreCheck(booleanTrapResult, throw) {
- return false
- }
- p.proxyDefineOwnPropertyPostCheck(target.self.getOwnPropSym(s), target, descr)
- return true
- }
- return target.self.defineOwnPropertySym(s, descr, throw)
- }
- func (p *proxyObject) proxyHasChecks(targetProp Value, target *Object, name fmt.Stringer) {
- targetDesc := propToValueProp(targetProp)
- if targetDesc != nil {
- if !targetDesc.configurable {
- 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()))
- }
- if !target.self.isExtensible() {
- panic(p.val.runtime.NewTypeError("'has' on proxy: trap returned falsish for property '%s' but the proxy target is not extensible", name.String()))
- }
- }
- }
- func (p *proxyObject) hasPropertyStr(name unistring.String) bool {
- target := p.target
- if b, ok := p.checkHandler().hasStr(target, name); ok {
- if !b {
- p.proxyHasChecks(target.self.getOwnPropStr(name), target, name)
- }
- return b
- }
- return target.self.hasPropertyStr(name)
- }
- func (p *proxyObject) hasPropertyIdx(idx valueInt) bool {
- target := p.target
- if b, ok := p.checkHandler().hasIdx(target, idx); ok {
- if !b {
- p.proxyHasChecks(target.self.getOwnPropIdx(idx), target, idx)
- }
- return b
- }
- return target.self.hasPropertyIdx(idx)
- }
- func (p *proxyObject) hasPropertySym(s *Symbol) bool {
- target := p.target
- if b, ok := p.checkHandler().hasSym(target, s); ok {
- if !b {
- p.proxyHasChecks(target.self.getOwnPropSym(s), target, s)
- }
- return b
- }
- return target.self.hasPropertySym(s)
- }
- func (p *proxyObject) hasOwnPropertyStr(name unistring.String) bool {
- return p.getOwnPropStr(name) != nil
- }
- func (p *proxyObject) hasOwnPropertyIdx(idx valueInt) bool {
- return p.getOwnPropIdx(idx) != nil
- }
- func (p *proxyObject) hasOwnPropertySym(s *Symbol) bool {
- return p.getOwnPropSym(s) != nil
- }
- func (p *proxyObject) proxyGetOwnPropertyDescriptor(targetProp Value, target *Object, trapResult Value, name fmt.Stringer) Value {
- r := p.val.runtime
- targetDesc := propToValueProp(targetProp)
- var trapResultObj *Object
- if trapResult != nil && trapResult != _undefined {
- if obj, ok := trapResult.(*Object); ok {
- trapResultObj = obj
- } else {
- panic(r.NewTypeError("'getOwnPropertyDescriptor' on proxy: trap returned neither object nor undefined for property '%s'", name.String()))
- }
- }
- if trapResultObj == nil {
- if targetDesc == nil {
- return nil
- }
- if !targetDesc.configurable {
- panic(r.NewTypeError())
- }
- if !target.self.isExtensible() {
- panic(r.NewTypeError())
- }
- return nil
- }
- extensibleTarget := target.self.isExtensible()
- resultDesc := r.toPropertyDescriptor(trapResultObj)
- resultDesc.complete()
- if !p.__isCompatibleDescriptor(extensibleTarget, &resultDesc, targetDesc) {
- 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()))
- }
- if resultDesc.Configurable == FLAG_FALSE {
- if targetDesc == nil {
- panic(r.NewTypeError("'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property '%s' which is non-existent in the proxy target", name.String()))
- }
- if targetDesc.configurable {
- panic(r.NewTypeError("'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property '%s' which is configurable in the proxy target", name.String()))
- }
- if resultDesc.Writable == FLAG_FALSE && targetDesc.writable {
- 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()))
- }
- }
- if resultDesc.Writable == FLAG_TRUE && resultDesc.Configurable == FLAG_TRUE &&
- resultDesc.Enumerable == FLAG_TRUE {
- return resultDesc.Value
- }
- return r.toValueProp(trapResultObj)
- }
- func (p *proxyObject) getOwnPropStr(name unistring.String) Value {
- target := p.target
- if v, ok := p.checkHandler().getOwnPropertyDescriptorStr(target, name); ok {
- return p.proxyGetOwnPropertyDescriptor(target.self.getOwnPropStr(name), target, v, name)
- }
- return target.self.getOwnPropStr(name)
- }
- func (p *proxyObject) getOwnPropIdx(idx valueInt) Value {
- target := p.target
- if v, ok := p.checkHandler().getOwnPropertyDescriptorIdx(target, idx); ok {
- return p.proxyGetOwnPropertyDescriptor(target.self.getOwnPropIdx(idx), target, v, idx)
- }
- return target.self.getOwnPropIdx(idx)
- }
- func (p *proxyObject) getOwnPropSym(s *Symbol) Value {
- target := p.target
- if v, ok := p.checkHandler().getOwnPropertyDescriptorSym(target, s); ok {
- return p.proxyGetOwnPropertyDescriptor(target.self.getOwnPropSym(s), target, v, s)
- }
- return target.self.getOwnPropSym(s)
- }
- func (p *proxyObject) proxyGetChecks(targetProp, trapResult Value, name fmt.Stringer) {
- if targetDesc, ok := targetProp.(*valueProperty); ok {
- if !targetDesc.accessor {
- if !targetDesc.writable && !targetDesc.configurable && !trapResult.SameAs(targetDesc.value) {
- 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))
- }
- } else {
- if !targetDesc.configurable && targetDesc.getterFunc == nil && trapResult != _undefined {
- 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))
- }
- }
- }
- }
- func (p *proxyObject) getStr(name unistring.String, receiver Value) Value {
- target := p.target
- if receiver == nil {
- receiver = p.val
- }
- if v, ok := p.checkHandler().getStr(target, name, receiver); ok {
- p.proxyGetChecks(target.self.getOwnPropStr(name), v, name)
- return v
- }
- return target.self.getStr(name, receiver)
- }
- func (p *proxyObject) getIdx(idx valueInt, receiver Value) Value {
- target := p.target
- if receiver == nil {
- receiver = p.val
- }
- if v, ok := p.checkHandler().getIdx(target, idx, receiver); ok {
- p.proxyGetChecks(target.self.getOwnPropIdx(idx), v, idx)
- return v
- }
- return target.self.getIdx(idx, receiver)
- }
- func (p *proxyObject) getSym(s *Symbol, receiver Value) Value {
- target := p.target
- if receiver == nil {
- receiver = p.val
- }
- if v, ok := p.checkHandler().getSym(target, s, receiver); ok {
- p.proxyGetChecks(target.self.getOwnPropSym(s), v, s)
- return v
- }
- return target.self.getSym(s, receiver)
- }
- func (p *proxyObject) proxySetPreCheck(trapResult, throw bool, name fmt.Stringer) bool {
- if !trapResult {
- p.val.runtime.typeErrorResult(throw, "'set' on proxy: trap returned falsish for property '%s'", name.String())
- }
- return trapResult
- }
- func (p *proxyObject) proxySetPostCheck(targetProp, value Value, name fmt.Stringer) {
- if prop, ok := targetProp.(*valueProperty); ok {
- if prop.accessor {
- if !prop.configurable && prop.setterFunc == nil {
- 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()))
- }
- } else if !prop.configurable && !prop.writable && !p.__sameValue(prop.value, value) {
- 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()))
- }
- }
- }
- func (p *proxyObject) proxySetStr(name unistring.String, value, receiver Value, throw bool) bool {
- target := p.target
- if v, ok := p.checkHandler().setStr(target, name, value, receiver); ok {
- if p.proxySetPreCheck(v, throw, name) {
- p.proxySetPostCheck(target.self.getOwnPropStr(name), value, name)
- return true
- }
- return false
- }
- return target.setStr(name, value, receiver, throw)
- }
- func (p *proxyObject) proxySetIdx(idx valueInt, value, receiver Value, throw bool) bool {
- target := p.target
- if v, ok := p.checkHandler().setIdx(target, idx, value, receiver); ok {
- if p.proxySetPreCheck(v, throw, idx) {
- p.proxySetPostCheck(target.self.getOwnPropIdx(idx), value, idx)
- return true
- }
- return false
- }
- return target.setIdx(idx, value, receiver, throw)
- }
- func (p *proxyObject) proxySetSym(s *Symbol, value, receiver Value, throw bool) bool {
- target := p.target
- if v, ok := p.checkHandler().setSym(target, s, value, receiver); ok {
- if p.proxySetPreCheck(v, throw, s) {
- p.proxySetPostCheck(target.self.getOwnPropSym(s), value, s)
- return true
- }
- return false
- }
- return target.setSym(s, value, receiver, throw)
- }
- func (p *proxyObject) setOwnStr(name unistring.String, v Value, throw bool) bool {
- return p.proxySetStr(name, v, p.val, throw)
- }
- func (p *proxyObject) setOwnIdx(idx valueInt, v Value, throw bool) bool {
- return p.proxySetIdx(idx, v, p.val, throw)
- }
- func (p *proxyObject) setOwnSym(s *Symbol, v Value, throw bool) bool {
- return p.proxySetSym(s, v, p.val, throw)
- }
- func (p *proxyObject) setForeignStr(name unistring.String, v, receiver Value, throw bool) (bool, bool) {
- return p.proxySetStr(name, v, receiver, throw), true
- }
- func (p *proxyObject) setForeignIdx(idx valueInt, v, receiver Value, throw bool) (bool, bool) {
- return p.proxySetIdx(idx, v, receiver, throw), true
- }
- func (p *proxyObject) setForeignSym(s *Symbol, v, receiver Value, throw bool) (bool, bool) {
- return p.proxySetSym(s, v, receiver, throw), true
- }
- func (p *proxyObject) proxyDeleteCheck(trapResult bool, targetProp Value, name fmt.Stringer, target *Object, throw bool) {
- if trapResult {
- if targetProp == nil {
- return
- }
- if targetDesc, ok := targetProp.(*valueProperty); ok {
- if !targetDesc.configurable {
- panic(p.val.runtime.NewTypeError("'deleteProperty' on proxy: property '%s' is a non-configurable property but the trap returned truish", name.String()))
- }
- }
- if !target.self.isExtensible() {
- panic(p.val.runtime.NewTypeError("'deleteProperty' on proxy: trap returned truish for property '%s' but the proxy target is non-extensible", name.String()))
- }
- } else {
- p.val.runtime.typeErrorResult(throw, "'deleteProperty' on proxy: trap returned falsish for property '%s'", name.String())
- }
- }
- func (p *proxyObject) deleteStr(name unistring.String, throw bool) bool {
- target := p.target
- if v, ok := p.checkHandler().deleteStr(target, name); ok {
- p.proxyDeleteCheck(v, target.self.getOwnPropStr(name), name, target, throw)
- return v
- }
- return target.self.deleteStr(name, throw)
- }
- func (p *proxyObject) deleteIdx(idx valueInt, throw bool) bool {
- target := p.target
- if v, ok := p.checkHandler().deleteIdx(target, idx); ok {
- p.proxyDeleteCheck(v, target.self.getOwnPropIdx(idx), idx, target, throw)
- return v
- }
- return target.self.deleteIdx(idx, throw)
- }
- func (p *proxyObject) deleteSym(s *Symbol, throw bool) bool {
- target := p.target
- if v, ok := p.checkHandler().deleteSym(target, s); ok {
- p.proxyDeleteCheck(v, target.self.getOwnPropSym(s), s, target, throw)
- return v
- }
- return target.self.deleteSym(s, throw)
- }
- func (p *proxyObject) keys(all bool, _ []Value) []Value {
- if v, ok := p.proxyOwnKeys(); ok {
- if !all {
- k := 0
- for i, key := range v {
- prop := p.val.getOwnProp(key)
- if prop == nil || prop == _undefined {
- continue
- }
- if prop, ok := prop.(*valueProperty); ok && !prop.enumerable {
- continue
- }
- if k != i {
- v[k] = v[i]
- }
- k++
- }
- v = v[:k]
- }
- return v
- }
- return p.target.self.keys(all, nil)
- }
- func (p *proxyObject) proxyOwnKeys() ([]Value, bool) {
- target := p.target
- if v, ok := p.checkHandler().ownKeys(target); ok {
- keys := p.val.runtime.toObject(v)
- var keyList []Value
- keySet := make(map[Value]struct{})
- l := toLength(keys.self.getStr("length", nil))
- for k := int64(0); k < l; k++ {
- item := keys.self.getIdx(valueInt(k), nil)
- if _, ok := item.(valueString); !ok {
- if _, ok := item.(*Symbol); !ok {
- panic(p.val.runtime.NewTypeError("%s is not a valid property name", item.String()))
- }
- }
- if _, exists := keySet[item]; exists {
- panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap returned duplicate entries"))
- }
- keyList = append(keyList, item)
- keySet[item] = struct{}{}
- }
- ext := target.self.isExtensible()
- for item, next := target.self.iterateKeys()(); next != nil; item, next = next() {
- if _, exists := keySet[item.name]; exists {
- delete(keySet, item.name)
- } else {
- if !ext {
- panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap result did not include '%s'", item.name.String()))
- }
- var prop Value
- if item.value == nil {
- prop = target.getOwnProp(item.name)
- } else {
- prop = item.value
- }
- if prop, ok := prop.(*valueProperty); ok && !prop.configurable {
- panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap result did not include non-configurable '%s'", item.name.String()))
- }
- }
- }
- if !ext && len(keyList) > 0 && len(keySet) > 0 {
- panic(p.val.runtime.NewTypeError("'ownKeys' on proxy: trap returned extra keys but proxy target is non-extensible"))
- }
- return keyList, true
- }
- return nil, false
- }
- func (p *proxyObject) iterateStringKeys() iterNextFunc {
- return (&proxyPropIter{
- p: p,
- names: p.stringKeys(true, nil),
- }).next
- }
- func (p *proxyObject) iterateSymbols() iterNextFunc {
- return (&proxyPropIter{
- p: p,
- names: p.symbols(true, nil),
- }).next
- }
- func (p *proxyObject) iterateKeys() iterNextFunc {
- return (&proxyPropIter{
- p: p,
- names: p.keys(true, nil),
- }).next
- }
- func (p *proxyObject) assertCallable() (call func(FunctionCall) Value, ok bool) {
- if p.call != nil {
- return func(call FunctionCall) Value {
- return p.apply(call)
- }, true
- }
- return nil, false
- }
- func (p *proxyObject) assertConstructor() func(args []Value, newTarget *Object) *Object {
- if p.ctor != nil {
- return p.construct
- }
- return nil
- }
- func (p *proxyObject) apply(call FunctionCall) Value {
- if p.call == nil {
- panic(p.val.runtime.NewTypeError("proxy target is not a function"))
- }
- if v, ok := p.checkHandler().apply(p.target, nilSafe(call.This), call.Arguments); ok {
- return v
- }
- return p.call(call)
- }
- func (p *proxyObject) construct(args []Value, newTarget *Object) *Object {
- if p.ctor == nil {
- panic(p.val.runtime.NewTypeError("proxy target is not a constructor"))
- }
- if newTarget == nil {
- newTarget = p.val
- }
- if v, ok := p.checkHandler().construct(p.target, args, newTarget); ok {
- return p.val.runtime.toObject(v)
- }
- return p.ctor(args, newTarget)
- }
- func (p *proxyObject) __isCompatibleDescriptor(extensible bool, desc *PropertyDescriptor, current *valueProperty) bool {
- if current == nil {
- return extensible
- }
- if !current.configurable {
- if desc.Configurable == FLAG_TRUE {
- return false
- }
- if desc.Enumerable != FLAG_NOT_SET && desc.Enumerable.Bool() != current.enumerable {
- return false
- }
- if desc.IsGeneric() {
- return true
- }
- if desc.IsData() != !current.accessor {
- return desc.Configurable != FLAG_FALSE
- }
- if desc.IsData() && !current.accessor {
- if !current.configurable {
- if desc.Writable == FLAG_TRUE && !current.writable {
- return false
- }
- if !current.writable {
- if desc.Value != nil && !desc.Value.SameAs(current.value) {
- return false
- }
- }
- }
- return true
- }
- if desc.IsAccessor() && current.accessor {
- if !current.configurable {
- if desc.Setter != nil && desc.Setter.SameAs(current.setterFunc) {
- return false
- }
- if desc.Getter != nil && desc.Getter.SameAs(current.getterFunc) {
- return false
- }
- }
- }
- }
- return true
- }
- func (p *proxyObject) __sameValue(val1, val2 Value) bool {
- if val1 == nil && val2 == nil {
- return true
- }
- if val1 != nil {
- return val1.SameAs(val2)
- }
- return false
- }
- func (p *proxyObject) filterKeys(vals []Value, all, symbols bool) []Value {
- if !all {
- k := 0
- for i, val := range vals {
- var prop Value
- if symbols {
- if s, ok := val.(*Symbol); ok {
- prop = p.getOwnPropSym(s)
- } else {
- continue
- }
- } else {
- if _, ok := val.(*Symbol); !ok {
- prop = p.getOwnPropStr(val.string())
- } else {
- continue
- }
- }
- if prop == nil {
- continue
- }
- if prop, ok := prop.(*valueProperty); ok && !prop.enumerable {
- continue
- }
- if k != i {
- vals[k] = vals[i]
- }
- k++
- }
- vals = vals[:k]
- } else {
- k := 0
- for i, val := range vals {
- if _, ok := val.(*Symbol); ok != symbols {
- continue
- }
- if k != i {
- vals[k] = vals[i]
- }
- k++
- }
- vals = vals[:k]
- }
- return vals
- }
- func (p *proxyObject) stringKeys(all bool, _ []Value) []Value { // we can assume accum is empty
- var keys []Value
- if vals, ok := p.proxyOwnKeys(); ok {
- keys = vals
- } else {
- keys = p.target.self.stringKeys(true, nil)
- }
- return p.filterKeys(keys, all, false)
- }
- func (p *proxyObject) symbols(all bool, accum []Value) []Value {
- var symbols []Value
- if vals, ok := p.proxyOwnKeys(); ok {
- symbols = vals
- } else {
- symbols = p.target.self.symbols(true, nil)
- }
- symbols = p.filterKeys(symbols, all, true)
- if accum == nil {
- return symbols
- }
- accum = append(accum, symbols...)
- return accum
- }
- func (p *proxyObject) className() string {
- if p.target == nil {
- panic(p.val.runtime.NewTypeError("proxy has been revoked"))
- }
- if p.call != nil || p.ctor != nil {
- return classFunction
- }
- return classObject
- }
- func (p *proxyObject) exportType() reflect.Type {
- return proxyType
- }
- func (p *proxyObject) export(*objectExportCtx) interface{} {
- return Proxy{
- proxy: p,
- }
- }
- func (p *proxyObject) revoke() {
- p.handler = nil
- p.target = nil
- }
|