397 lines
14 KiB
Go
397 lines
14 KiB
Go
package goja
|
|
|
|
import (
|
|
"apigo.cc/ai/ai/goja/unistring"
|
|
)
|
|
|
|
type nativeProxyHandler struct {
|
|
handler *ProxyTrapConfig
|
|
}
|
|
|
|
func (h *nativeProxyHandler) getPrototypeOf(target *Object) (Value, bool) {
|
|
if trap := h.handler.GetPrototypeOf; trap != nil {
|
|
return trap(target), true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) setPrototypeOf(target *Object, proto *Object) (bool, bool) {
|
|
if trap := h.handler.SetPrototypeOf; trap != nil {
|
|
return trap(target, proto), true
|
|
}
|
|
return false, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) isExtensible(target *Object) (bool, bool) {
|
|
if trap := h.handler.IsExtensible; trap != nil {
|
|
return trap(target), true
|
|
}
|
|
return false, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) preventExtensions(target *Object) (bool, bool) {
|
|
if trap := h.handler.PreventExtensions; trap != nil {
|
|
return trap(target), true
|
|
}
|
|
return false, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) getOwnPropertyDescriptorStr(target *Object, prop unistring.String) (Value, bool) {
|
|
if trap := h.handler.GetOwnPropertyDescriptorIdx; trap != nil {
|
|
if idx, ok := strToInt(prop); ok {
|
|
desc := trap(target, idx)
|
|
return desc.toValue(target.runtime), true
|
|
}
|
|
}
|
|
if trap := h.handler.GetOwnPropertyDescriptor; trap != nil {
|
|
desc := trap(target, prop.String())
|
|
return desc.toValue(target.runtime), true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) getOwnPropertyDescriptorIdx(target *Object, prop valueInt) (Value, bool) {
|
|
if trap := h.handler.GetOwnPropertyDescriptorIdx; trap != nil {
|
|
desc := trap(target, toIntStrict(int64(prop)))
|
|
return desc.toValue(target.runtime), true
|
|
}
|
|
if trap := h.handler.GetOwnPropertyDescriptor; trap != nil {
|
|
desc := trap(target, prop.String())
|
|
return desc.toValue(target.runtime), true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) getOwnPropertyDescriptorSym(target *Object, prop *Symbol) (Value, bool) {
|
|
if trap := h.handler.GetOwnPropertyDescriptorSym; trap != nil {
|
|
desc := trap(target, prop)
|
|
return desc.toValue(target.runtime), true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) definePropertyStr(target *Object, prop unistring.String, desc PropertyDescriptor) (bool, bool) {
|
|
if trap := h.handler.DefinePropertyIdx; trap != nil {
|
|
if idx, ok := strToInt(prop); ok {
|
|
return trap(target, idx, desc), true
|
|
}
|
|
}
|
|
if trap := h.handler.DefineProperty; trap != nil {
|
|
return trap(target, prop.String(), desc), true
|
|
}
|
|
return false, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) definePropertyIdx(target *Object, prop valueInt, desc PropertyDescriptor) (bool, bool) {
|
|
if trap := h.handler.DefinePropertyIdx; trap != nil {
|
|
return trap(target, toIntStrict(int64(prop)), desc), true
|
|
}
|
|
if trap := h.handler.DefineProperty; trap != nil {
|
|
return trap(target, prop.String(), desc), true
|
|
}
|
|
return false, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) definePropertySym(target *Object, prop *Symbol, desc PropertyDescriptor) (bool, bool) {
|
|
if trap := h.handler.DefinePropertySym; trap != nil {
|
|
return trap(target, prop, desc), true
|
|
}
|
|
return false, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) hasStr(target *Object, prop unistring.String) (bool, bool) {
|
|
if trap := h.handler.HasIdx; trap != nil {
|
|
if idx, ok := strToInt(prop); ok {
|
|
return trap(target, idx), true
|
|
}
|
|
}
|
|
if trap := h.handler.Has; trap != nil {
|
|
return trap(target, prop.String()), true
|
|
}
|
|
return false, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) hasIdx(target *Object, prop valueInt) (bool, bool) {
|
|
if trap := h.handler.HasIdx; trap != nil {
|
|
return trap(target, toIntStrict(int64(prop))), true
|
|
}
|
|
if trap := h.handler.Has; trap != nil {
|
|
return trap(target, prop.String()), true
|
|
}
|
|
return false, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) hasSym(target *Object, prop *Symbol) (bool, bool) {
|
|
if trap := h.handler.HasSym; trap != nil {
|
|
return trap(target, prop), true
|
|
}
|
|
return false, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) getStr(target *Object, prop unistring.String, receiver Value) (Value, bool) {
|
|
if trap := h.handler.GetIdx; trap != nil {
|
|
if idx, ok := strToInt(prop); ok {
|
|
return trap(target, idx, receiver), true
|
|
}
|
|
}
|
|
if trap := h.handler.Get; trap != nil {
|
|
return trap(target, prop.String(), receiver), true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) getIdx(target *Object, prop valueInt, receiver Value) (Value, bool) {
|
|
if trap := h.handler.GetIdx; trap != nil {
|
|
return trap(target, toIntStrict(int64(prop)), receiver), true
|
|
}
|
|
if trap := h.handler.Get; trap != nil {
|
|
return trap(target, prop.String(), receiver), true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) getSym(target *Object, prop *Symbol, receiver Value) (Value, bool) {
|
|
if trap := h.handler.GetSym; trap != nil {
|
|
return trap(target, prop, receiver), true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) setStr(target *Object, prop unistring.String, value Value, receiver Value) (bool, bool) {
|
|
if trap := h.handler.SetIdx; trap != nil {
|
|
if idx, ok := strToInt(prop); ok {
|
|
return trap(target, idx, value, receiver), true
|
|
}
|
|
}
|
|
if trap := h.handler.Set; trap != nil {
|
|
return trap(target, prop.String(), value, receiver), true
|
|
}
|
|
return false, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) setIdx(target *Object, prop valueInt, value Value, receiver Value) (bool, bool) {
|
|
if trap := h.handler.SetIdx; trap != nil {
|
|
return trap(target, toIntStrict(int64(prop)), value, receiver), true
|
|
}
|
|
if trap := h.handler.Set; trap != nil {
|
|
return trap(target, prop.String(), value, receiver), true
|
|
}
|
|
return false, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) setSym(target *Object, prop *Symbol, value Value, receiver Value) (bool, bool) {
|
|
if trap := h.handler.SetSym; trap != nil {
|
|
return trap(target, prop, value, receiver), true
|
|
}
|
|
return false, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) deleteStr(target *Object, prop unistring.String) (bool, bool) {
|
|
if trap := h.handler.DeletePropertyIdx; trap != nil {
|
|
if idx, ok := strToInt(prop); ok {
|
|
return trap(target, idx), true
|
|
}
|
|
}
|
|
if trap := h.handler.DeleteProperty; trap != nil {
|
|
return trap(target, prop.String()), true
|
|
}
|
|
return false, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) deleteIdx(target *Object, prop valueInt) (bool, bool) {
|
|
if trap := h.handler.DeletePropertyIdx; trap != nil {
|
|
return trap(target, toIntStrict(int64(prop))), true
|
|
}
|
|
if trap := h.handler.DeleteProperty; trap != nil {
|
|
return trap(target, prop.String()), true
|
|
}
|
|
return false, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) deleteSym(target *Object, prop *Symbol) (bool, bool) {
|
|
if trap := h.handler.DeletePropertySym; trap != nil {
|
|
return trap(target, prop), true
|
|
}
|
|
return false, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) ownKeys(target *Object) (*Object, bool) {
|
|
if trap := h.handler.OwnKeys; trap != nil {
|
|
return trap(target), true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) apply(target *Object, this Value, args []Value) (Value, bool) {
|
|
if trap := h.handler.Apply; trap != nil {
|
|
return trap(target, this, args), true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) construct(target *Object, args []Value, newTarget *Object) (Value, bool) {
|
|
if trap := h.handler.Construct; trap != nil {
|
|
return trap(target, args, newTarget), true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (h *nativeProxyHandler) toObject(runtime *Runtime) *Object {
|
|
return runtime.ToValue(h.handler).ToObject(runtime)
|
|
}
|
|
|
|
func (r *Runtime) newNativeProxyHandler(nativeHandler *ProxyTrapConfig) proxyHandler {
|
|
return &nativeProxyHandler{handler: nativeHandler}
|
|
}
|
|
|
|
// ProxyTrapConfig provides a simplified Go-friendly API for implementing Proxy traps.
|
|
// If an *Idx trap is defined it gets called for integer property keys, including negative ones. Note that
|
|
// this only includes string property keys that represent a canonical integer
|
|
// (i.e. "0", "123", but not "00", "01", " 1" or "-0").
|
|
// For efficiency strings representing integers exceeding 2^53 are not checked to see if they are canonical,
|
|
// i.e. the *Idx traps will receive "9007199254740993" as well as "9007199254740994", even though the former is not
|
|
// a canonical representation in ECMAScript (Number("9007199254740993") === 9007199254740992).
|
|
// See https://262.ecma-international.org/#sec-canonicalnumericindexstring
|
|
// If an *Idx trap is not set, the corresponding string one is used.
|
|
type ProxyTrapConfig struct {
|
|
// A trap for Object.getPrototypeOf, Reflect.getPrototypeOf, __proto__, Object.prototype.isPrototypeOf, instanceof
|
|
GetPrototypeOf func(target *Object) (prototype *Object)
|
|
|
|
// A trap for Object.setPrototypeOf, Reflect.setPrototypeOf
|
|
SetPrototypeOf func(target *Object, prototype *Object) (success bool)
|
|
|
|
// A trap for Object.isExtensible, Reflect.isExtensible
|
|
IsExtensible func(target *Object) (success bool)
|
|
|
|
// A trap for Object.preventExtensions, Reflect.preventExtensions
|
|
PreventExtensions func(target *Object) (success bool)
|
|
|
|
// A trap for Object.getOwnPropertyDescriptor, Reflect.getOwnPropertyDescriptor (string properties)
|
|
GetOwnPropertyDescriptor func(target *Object, prop string) (propertyDescriptor PropertyDescriptor)
|
|
|
|
// A trap for Object.getOwnPropertyDescriptor, Reflect.getOwnPropertyDescriptor (integer properties)
|
|
GetOwnPropertyDescriptorIdx func(target *Object, prop int) (propertyDescriptor PropertyDescriptor)
|
|
|
|
// A trap for Object.getOwnPropertyDescriptor, Reflect.getOwnPropertyDescriptor (Symbol properties)
|
|
GetOwnPropertyDescriptorSym func(target *Object, prop *Symbol) (propertyDescriptor PropertyDescriptor)
|
|
|
|
// A trap for Object.defineProperty, Reflect.defineProperty (string properties)
|
|
DefineProperty func(target *Object, key string, propertyDescriptor PropertyDescriptor) (success bool)
|
|
|
|
// A trap for Object.defineProperty, Reflect.defineProperty (integer properties)
|
|
DefinePropertyIdx func(target *Object, key int, propertyDescriptor PropertyDescriptor) (success bool)
|
|
|
|
// A trap for Object.defineProperty, Reflect.defineProperty (Symbol properties)
|
|
DefinePropertySym func(target *Object, key *Symbol, propertyDescriptor PropertyDescriptor) (success bool)
|
|
|
|
// A trap for the in operator, with operator, Reflect.has (string properties)
|
|
Has func(target *Object, property string) (available bool)
|
|
|
|
// A trap for the in operator, with operator, Reflect.has (integer properties)
|
|
HasIdx func(target *Object, property int) (available bool)
|
|
|
|
// A trap for the in operator, with operator, Reflect.has (Symbol properties)
|
|
HasSym func(target *Object, property *Symbol) (available bool)
|
|
|
|
// A trap for getting property values, Reflect.get (string properties)
|
|
Get func(target *Object, property string, receiver Value) (value Value)
|
|
|
|
// A trap for getting property values, Reflect.get (integer properties)
|
|
GetIdx func(target *Object, property int, receiver Value) (value Value)
|
|
|
|
// A trap for getting property values, Reflect.get (Symbol properties)
|
|
GetSym func(target *Object, property *Symbol, receiver Value) (value Value)
|
|
|
|
// A trap for setting property values, Reflect.set (string properties)
|
|
Set func(target *Object, property string, value Value, receiver Value) (success bool)
|
|
|
|
// A trap for setting property values, Reflect.set (integer properties)
|
|
SetIdx func(target *Object, property int, value Value, receiver Value) (success bool)
|
|
|
|
// A trap for setting property values, Reflect.set (Symbol properties)
|
|
SetSym func(target *Object, property *Symbol, value Value, receiver Value) (success bool)
|
|
|
|
// A trap for the delete operator, Reflect.deleteProperty (string properties)
|
|
DeleteProperty func(target *Object, property string) (success bool)
|
|
|
|
// A trap for the delete operator, Reflect.deleteProperty (integer properties)
|
|
DeletePropertyIdx func(target *Object, property int) (success bool)
|
|
|
|
// A trap for the delete operator, Reflect.deleteProperty (Symbol properties)
|
|
DeletePropertySym func(target *Object, property *Symbol) (success bool)
|
|
|
|
// A trap for Object.getOwnPropertyNames, Object.getOwnPropertySymbols, Object.keys, Reflect.ownKeys
|
|
OwnKeys func(target *Object) (object *Object)
|
|
|
|
// A trap for a function call, Function.prototype.apply, Function.prototype.call, Reflect.apply
|
|
Apply func(target *Object, this Value, argumentsList []Value) (value Value)
|
|
|
|
// A trap for the new operator, Reflect.construct
|
|
Construct func(target *Object, argumentsList []Value, newTarget *Object) (value *Object)
|
|
}
|
|
|
|
func (r *Runtime) newProxy(args []Value, proto *Object) *Object {
|
|
if len(args) >= 2 {
|
|
if target, ok := args[0].(*Object); ok {
|
|
if proxyHandler, ok := args[1].(*Object); ok {
|
|
return r.newProxyObject(target, proxyHandler, proto).val
|
|
}
|
|
}
|
|
}
|
|
panic(r.NewTypeError("Cannot create proxy with a non-object as target or handler"))
|
|
}
|
|
|
|
func (r *Runtime) builtin_newProxy(args []Value, newTarget *Object) *Object {
|
|
if newTarget == nil {
|
|
panic(r.needNew("Proxy"))
|
|
}
|
|
return r.newProxy(args, r.getPrototypeFromCtor(newTarget, r.getProxy(), r.global.ObjectPrototype))
|
|
}
|
|
|
|
func (r *Runtime) NewProxy(target *Object, nativeHandler *ProxyTrapConfig) Proxy {
|
|
if p, ok := target.self.(*proxyObject); ok {
|
|
if p.handler == nil {
|
|
panic(r.NewTypeError("Cannot create proxy with a revoked proxy as target"))
|
|
}
|
|
}
|
|
handler := r.newNativeProxyHandler(nativeHandler)
|
|
proxy := r._newProxyObject(target, handler, nil)
|
|
return Proxy{proxy: proxy}
|
|
}
|
|
|
|
func (r *Runtime) builtin_proxy_revocable(call FunctionCall) Value {
|
|
if len(call.Arguments) >= 2 {
|
|
if target, ok := call.Argument(0).(*Object); ok {
|
|
if proxyHandler, ok := call.Argument(1).(*Object); ok {
|
|
proxy := r.newProxyObject(target, proxyHandler, nil)
|
|
revoke := r.newNativeFunc(func(FunctionCall) Value {
|
|
proxy.revoke()
|
|
return _undefined
|
|
}, "", 0)
|
|
ret := r.NewObject()
|
|
ret.self._putProp("proxy", proxy.val, true, true, true)
|
|
ret.self._putProp("revoke", revoke, true, true, true)
|
|
return ret
|
|
}
|
|
}
|
|
}
|
|
panic(r.NewTypeError("Cannot create proxy with a non-object as target or handler"))
|
|
}
|
|
|
|
func (r *Runtime) createProxy(val *Object) objectImpl {
|
|
o := r.newNativeConstructOnly(val, r.builtin_newProxy, nil, "Proxy", 2)
|
|
|
|
o._putProp("revocable", r.newNativeFunc(r.builtin_proxy_revocable, "revocable", 2), true, false, true)
|
|
return o
|
|
}
|
|
|
|
func (r *Runtime) getProxy() *Object {
|
|
ret := r.global.Proxy
|
|
if ret == nil {
|
|
ret = &Object{runtime: r}
|
|
r.global.Proxy = ret
|
|
r.createProxy(ret)
|
|
}
|
|
return ret
|
|
}
|