2024-02-24 21:00:04 +00:00
|
|
|
package otto
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
)
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
type objectClass struct {
|
|
|
|
getOwnProperty func(*object, string) *property
|
|
|
|
getProperty func(*object, string) *property
|
|
|
|
get func(*object, string) Value
|
|
|
|
canPut func(*object, string) bool
|
|
|
|
put func(*object, string, Value, bool)
|
|
|
|
hasProperty func(*object, string) bool
|
|
|
|
hasOwnProperty func(*object, string) bool
|
|
|
|
defineOwnProperty func(*object, string, property, bool) bool
|
|
|
|
delete func(*object, string, bool) bool
|
|
|
|
enumerate func(*object, bool, func(string) bool)
|
|
|
|
clone func(*object, *object, *cloner) *object
|
|
|
|
marshalJSON func(*object) json.Marshaler
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
func objectEnumerate(obj *object, all bool, each func(string) bool) {
|
|
|
|
for _, name := range obj.propertyOrder {
|
|
|
|
if all || obj.property[name].enumerable() {
|
2024-02-24 21:00:04 +00:00
|
|
|
if !each(name) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
var classObject,
|
|
|
|
classArray,
|
|
|
|
classString,
|
|
|
|
classArguments,
|
|
|
|
classGoStruct,
|
|
|
|
classGoMap,
|
|
|
|
classGoArray,
|
|
|
|
classGoSlice *objectClass
|
2024-02-24 21:00:04 +00:00
|
|
|
|
|
|
|
func init() {
|
2024-04-04 14:46:14 +00:00
|
|
|
classObject = &objectClass{
|
2024-02-24 21:00:04 +00:00
|
|
|
objectGetOwnProperty,
|
|
|
|
objectGetProperty,
|
|
|
|
objectGet,
|
|
|
|
objectCanPut,
|
|
|
|
objectPut,
|
|
|
|
objectHasProperty,
|
|
|
|
objectHasOwnProperty,
|
|
|
|
objectDefineOwnProperty,
|
|
|
|
objectDelete,
|
|
|
|
objectEnumerate,
|
|
|
|
objectClone,
|
|
|
|
nil,
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
classArray = &objectClass{
|
2024-02-24 21:00:04 +00:00
|
|
|
objectGetOwnProperty,
|
|
|
|
objectGetProperty,
|
|
|
|
objectGet,
|
|
|
|
objectCanPut,
|
|
|
|
objectPut,
|
|
|
|
objectHasProperty,
|
|
|
|
objectHasOwnProperty,
|
|
|
|
arrayDefineOwnProperty,
|
|
|
|
objectDelete,
|
|
|
|
objectEnumerate,
|
|
|
|
objectClone,
|
|
|
|
nil,
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
classString = &objectClass{
|
2024-02-24 21:00:04 +00:00
|
|
|
stringGetOwnProperty,
|
|
|
|
objectGetProperty,
|
|
|
|
objectGet,
|
|
|
|
objectCanPut,
|
|
|
|
objectPut,
|
|
|
|
objectHasProperty,
|
|
|
|
objectHasOwnProperty,
|
|
|
|
objectDefineOwnProperty,
|
|
|
|
objectDelete,
|
|
|
|
stringEnumerate,
|
|
|
|
objectClone,
|
|
|
|
nil,
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
classArguments = &objectClass{
|
2024-02-24 21:00:04 +00:00
|
|
|
argumentsGetOwnProperty,
|
|
|
|
objectGetProperty,
|
|
|
|
argumentsGet,
|
|
|
|
objectCanPut,
|
|
|
|
objectPut,
|
|
|
|
objectHasProperty,
|
|
|
|
objectHasOwnProperty,
|
|
|
|
argumentsDefineOwnProperty,
|
|
|
|
argumentsDelete,
|
|
|
|
objectEnumerate,
|
|
|
|
objectClone,
|
|
|
|
nil,
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
classGoStruct = &objectClass{
|
2024-02-24 21:00:04 +00:00
|
|
|
goStructGetOwnProperty,
|
|
|
|
objectGetProperty,
|
|
|
|
objectGet,
|
|
|
|
goStructCanPut,
|
|
|
|
goStructPut,
|
|
|
|
objectHasProperty,
|
|
|
|
objectHasOwnProperty,
|
|
|
|
objectDefineOwnProperty,
|
|
|
|
objectDelete,
|
|
|
|
goStructEnumerate,
|
|
|
|
objectClone,
|
|
|
|
goStructMarshalJSON,
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
classGoMap = &objectClass{
|
2024-02-24 21:00:04 +00:00
|
|
|
goMapGetOwnProperty,
|
|
|
|
objectGetProperty,
|
|
|
|
objectGet,
|
|
|
|
objectCanPut,
|
|
|
|
objectPut,
|
|
|
|
objectHasProperty,
|
|
|
|
objectHasOwnProperty,
|
|
|
|
goMapDefineOwnProperty,
|
|
|
|
goMapDelete,
|
|
|
|
goMapEnumerate,
|
|
|
|
objectClone,
|
|
|
|
nil,
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
classGoArray = &objectClass{
|
2024-02-24 21:00:04 +00:00
|
|
|
goArrayGetOwnProperty,
|
|
|
|
objectGetProperty,
|
|
|
|
objectGet,
|
|
|
|
objectCanPut,
|
|
|
|
objectPut,
|
|
|
|
objectHasProperty,
|
|
|
|
objectHasOwnProperty,
|
|
|
|
goArrayDefineOwnProperty,
|
|
|
|
goArrayDelete,
|
|
|
|
goArrayEnumerate,
|
|
|
|
objectClone,
|
|
|
|
nil,
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
classGoSlice = &objectClass{
|
2024-02-24 21:00:04 +00:00
|
|
|
goSliceGetOwnProperty,
|
|
|
|
objectGetProperty,
|
|
|
|
objectGet,
|
|
|
|
objectCanPut,
|
|
|
|
objectPut,
|
|
|
|
objectHasProperty,
|
|
|
|
objectHasOwnProperty,
|
|
|
|
goSliceDefineOwnProperty,
|
|
|
|
goSliceDelete,
|
|
|
|
goSliceEnumerate,
|
|
|
|
objectClone,
|
|
|
|
nil,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allons-y
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
// 8.12.1.
|
|
|
|
func objectGetOwnProperty(obj *object, name string) *property {
|
|
|
|
// Return a _copy_ of the prop
|
|
|
|
prop, exists := obj.readProperty(name)
|
2024-02-24 21:00:04 +00:00
|
|
|
if !exists {
|
|
|
|
return nil
|
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
return &prop
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
// 8.12.2.
|
|
|
|
func objectGetProperty(obj *object, name string) *property {
|
|
|
|
prop := obj.getOwnProperty(name)
|
|
|
|
if prop != nil {
|
|
|
|
return prop
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
if obj.prototype != nil {
|
|
|
|
return obj.prototype.getProperty(name)
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
// 8.12.3.
|
|
|
|
func objectGet(obj *object, name string) Value {
|
|
|
|
if prop := obj.getProperty(name); prop != nil {
|
|
|
|
return prop.get(obj)
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
return Value{}
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
// 8.12.4.
|
|
|
|
func objectCanPut(obj *object, name string) bool {
|
|
|
|
canPut, _, _ := objectCanPutDetails(obj, name)
|
2024-02-24 21:00:04 +00:00
|
|
|
return canPut
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
func objectCanPutDetails(obj *object, name string) (canPut bool, prop *property, setter *object) { //nolint: nonamedreturns
|
|
|
|
prop = obj.getOwnProperty(name)
|
|
|
|
if prop != nil {
|
|
|
|
switch propertyValue := prop.value.(type) {
|
2024-02-24 21:00:04 +00:00
|
|
|
case Value:
|
2024-04-04 14:46:14 +00:00
|
|
|
return prop.writable(), prop, nil
|
|
|
|
case propertyGetSet:
|
2024-02-24 21:00:04 +00:00
|
|
|
setter = propertyValue[1]
|
2024-04-04 14:46:14 +00:00
|
|
|
return setter != nil, prop, setter
|
2024-02-24 21:00:04 +00:00
|
|
|
default:
|
2024-04-04 14:46:14 +00:00
|
|
|
panic(obj.runtime.panicTypeError("unexpected type %T to Object.CanPutDetails", prop.value))
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
if obj.prototype == nil {
|
|
|
|
return obj.extensible, nil, nil
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
prop = obj.prototype.getProperty(name)
|
|
|
|
if prop == nil {
|
|
|
|
return obj.extensible, nil, nil
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
switch propertyValue := prop.value.(type) {
|
2024-02-24 21:00:04 +00:00
|
|
|
case Value:
|
2024-04-04 14:46:14 +00:00
|
|
|
if !obj.extensible {
|
2024-02-24 21:00:04 +00:00
|
|
|
return false, nil, nil
|
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
return prop.writable(), nil, nil
|
|
|
|
case propertyGetSet:
|
2024-02-24 21:00:04 +00:00
|
|
|
setter = propertyValue[1]
|
2024-04-04 14:46:14 +00:00
|
|
|
return setter != nil, prop, setter
|
2024-02-24 21:00:04 +00:00
|
|
|
default:
|
2024-04-04 14:46:14 +00:00
|
|
|
panic(obj.runtime.panicTypeError("unexpected type %T to Object.CanPutDetails", prop.value))
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
// 8.12.5.
|
|
|
|
func objectPut(obj *object, name string, value Value, throw bool) {
|
2024-02-24 21:00:04 +00:00
|
|
|
if true {
|
|
|
|
// Shortcut...
|
|
|
|
//
|
|
|
|
// So, right now, every class is using objectCanPut and every class
|
|
|
|
// is using objectPut.
|
|
|
|
//
|
|
|
|
// If that were to no longer be the case, we would have to have
|
|
|
|
// something to detect that here, so that we do not use an
|
|
|
|
// incompatible canPut routine
|
2024-04-04 14:46:14 +00:00
|
|
|
canPut, prop, setter := objectCanPutDetails(obj, name)
|
|
|
|
switch {
|
|
|
|
case !canPut:
|
|
|
|
obj.runtime.typeErrorResult(throw)
|
|
|
|
case setter != nil:
|
|
|
|
setter.call(toValue(obj), []Value{value}, false, nativeFrame)
|
|
|
|
case prop != nil:
|
|
|
|
prop.value = value
|
|
|
|
obj.defineOwnProperty(name, *prop, throw)
|
|
|
|
default:
|
|
|
|
obj.defineProperty(name, value, 0o111, throw)
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// The long way...
|
|
|
|
//
|
|
|
|
// Right now, code should never get here, see above
|
2024-04-04 14:46:14 +00:00
|
|
|
if !obj.canPut(name) {
|
|
|
|
obj.runtime.typeErrorResult(throw)
|
2024-02-24 21:00:04 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
prop := obj.getOwnProperty(name)
|
|
|
|
if prop == nil {
|
|
|
|
prop = obj.getProperty(name)
|
|
|
|
if prop != nil {
|
|
|
|
if getSet, isAccessor := prop.value.(propertyGetSet); isAccessor {
|
|
|
|
getSet[1].call(toValue(obj), []Value{value}, false, nativeFrame)
|
2024-02-24 21:00:04 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
obj.defineProperty(name, value, 0o111, throw)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch propertyValue := prop.value.(type) {
|
|
|
|
case Value:
|
|
|
|
prop.value = value
|
|
|
|
obj.defineOwnProperty(name, *prop, throw)
|
|
|
|
case propertyGetSet:
|
|
|
|
if propertyValue[1] != nil {
|
|
|
|
propertyValue[1].call(toValue(obj), []Value{value}, false, nativeFrame)
|
|
|
|
return
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
if throw {
|
|
|
|
panic(obj.runtime.panicTypeError("Object.Put nil second parameter to propertyGetSet"))
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
panic(obj.runtime.panicTypeError("Object.Put unexpected type %T", prop.value))
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
// 8.12.6.
|
|
|
|
func objectHasProperty(obj *object, name string) bool {
|
|
|
|
return obj.getProperty(name) != nil
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
func objectHasOwnProperty(obj *object, name string) bool {
|
|
|
|
return obj.getOwnProperty(name) != nil
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
// 8.12.9.
|
|
|
|
func objectDefineOwnProperty(obj *object, name string, descriptor property, throw bool) bool {
|
|
|
|
reject := func(reason string) bool {
|
|
|
|
if throw {
|
|
|
|
panic(obj.runtime.panicTypeError("Object.DefineOwnProperty: %s", reason))
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
return false
|
|
|
|
}
|
2024-02-24 21:00:04 +00:00
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
prop, exists := obj.readProperty(name)
|
|
|
|
if !exists {
|
|
|
|
if !obj.extensible {
|
|
|
|
return reject("not exists and not extensible")
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
if newGetSet, isAccessor := descriptor.value.(propertyGetSet); isAccessor {
|
|
|
|
if newGetSet[0] == &nilGetSetObject {
|
2024-02-24 21:00:04 +00:00
|
|
|
newGetSet[0] = nil
|
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
if newGetSet[1] == &nilGetSetObject {
|
2024-02-24 21:00:04 +00:00
|
|
|
newGetSet[1] = nil
|
|
|
|
}
|
|
|
|
descriptor.value = newGetSet
|
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
obj.writeProperty(name, descriptor.value, descriptor.mode)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if descriptor.isEmpty() {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO Per 8.12.9.6 - We should shortcut here (returning true) if
|
|
|
|
// the current and new (define) properties are the same
|
|
|
|
|
|
|
|
configurable := prop.configurable()
|
|
|
|
if !configurable {
|
|
|
|
if descriptor.configurable() {
|
|
|
|
return reject("property and descriptor not configurable")
|
|
|
|
}
|
|
|
|
// Test that, if enumerable is set on the property descriptor, then it should
|
|
|
|
// be the same as the existing property
|
|
|
|
if descriptor.enumerateSet() && descriptor.enumerable() != prop.enumerable() {
|
|
|
|
return reject("property not configurable and enumerable miss match")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
value, isDataDescriptor := prop.value.(Value)
|
|
|
|
getSet, _ := prop.value.(propertyGetSet)
|
|
|
|
switch {
|
|
|
|
case descriptor.isGenericDescriptor():
|
|
|
|
// GenericDescriptor
|
|
|
|
case isDataDescriptor != descriptor.isDataDescriptor():
|
|
|
|
// DataDescriptor <=> AccessorDescriptor
|
|
|
|
if !configurable {
|
|
|
|
return reject("property descriptor not configurable")
|
|
|
|
}
|
|
|
|
case isDataDescriptor && descriptor.isDataDescriptor():
|
|
|
|
// DataDescriptor <=> DataDescriptor
|
|
|
|
if !configurable {
|
|
|
|
if !prop.writable() && descriptor.writable() {
|
|
|
|
return reject("property not configurable or writeable and descriptor not writeable")
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
if !prop.writable() {
|
|
|
|
if descriptor.value != nil && !sameValue(value, descriptor.value.(Value)) {
|
|
|
|
return reject("property not configurable or writeable and descriptor not the same")
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
default:
|
|
|
|
// AccessorDescriptor <=> AccessorDescriptor
|
|
|
|
newGetSet, _ := descriptor.value.(propertyGetSet)
|
|
|
|
presentGet, presentSet := true, true
|
|
|
|
if newGetSet[0] == &nilGetSetObject {
|
|
|
|
// Present, but nil
|
|
|
|
newGetSet[0] = nil
|
|
|
|
} else if newGetSet[0] == nil {
|
|
|
|
// Missing, not even nil
|
|
|
|
newGetSet[0] = getSet[0]
|
|
|
|
presentGet = false
|
|
|
|
}
|
|
|
|
if newGetSet[1] == &nilGetSetObject {
|
|
|
|
// Present, but nil
|
|
|
|
newGetSet[1] = nil
|
|
|
|
} else if newGetSet[1] == nil {
|
|
|
|
// Missing, not even nil
|
|
|
|
newGetSet[1] = getSet[1]
|
|
|
|
presentSet = false
|
|
|
|
}
|
|
|
|
if !configurable {
|
|
|
|
if (presentGet && (getSet[0] != newGetSet[0])) || (presentSet && (getSet[1] != newGetSet[1])) {
|
|
|
|
return reject("access descriptor not configurable")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
descriptor.value = newGetSet
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
|
|
|
|
// This section will preserve attributes of
|
|
|
|
// the original property, if necessary
|
|
|
|
value1 := descriptor.value
|
|
|
|
if value1 == nil {
|
|
|
|
value1 = prop.value
|
|
|
|
} else if newGetSet, isAccessor := descriptor.value.(propertyGetSet); isAccessor {
|
|
|
|
if newGetSet[0] == &nilGetSetObject {
|
|
|
|
newGetSet[0] = nil
|
|
|
|
}
|
|
|
|
if newGetSet[1] == &nilGetSetObject {
|
|
|
|
newGetSet[1] = nil
|
|
|
|
}
|
|
|
|
value1 = newGetSet
|
|
|
|
}
|
|
|
|
mode1 := descriptor.mode
|
|
|
|
if mode1&0o222 != 0 {
|
|
|
|
// TODO Factor this out into somewhere testable
|
|
|
|
// (Maybe put into switch ...)
|
|
|
|
mode0 := prop.mode
|
|
|
|
if mode1&0o200 != 0 {
|
|
|
|
if descriptor.isDataDescriptor() {
|
|
|
|
mode1 &= ^0o200 // Turn off "writable" missing
|
|
|
|
mode1 |= (mode0 & 0o100)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if mode1&0o20 != 0 {
|
|
|
|
mode1 |= (mode0 & 0o10)
|
|
|
|
}
|
|
|
|
if mode1&0o2 != 0 {
|
|
|
|
mode1 |= (mode0 & 0o1)
|
|
|
|
}
|
|
|
|
mode1 &= 0o311 // 0311 to preserve the non-setting on "writable"
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
obj.writeProperty(name, value1, mode1)
|
|
|
|
|
|
|
|
return true
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
func objectDelete(obj *object, name string, throw bool) bool {
|
|
|
|
prop := obj.getOwnProperty(name)
|
|
|
|
if prop == nil {
|
2024-02-24 21:00:04 +00:00
|
|
|
return true
|
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
if prop.configurable() {
|
|
|
|
obj.deleteProperty(name)
|
2024-02-24 21:00:04 +00:00
|
|
|
return true
|
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
return obj.runtime.typeErrorResult(throw)
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
|
2024-04-04 14:46:14 +00:00
|
|
|
func objectClone(in *object, out *object, clone *cloner) *object {
|
2024-02-24 21:00:04 +00:00
|
|
|
*out = *in
|
|
|
|
|
|
|
|
out.runtime = clone.runtime
|
|
|
|
if out.prototype != nil {
|
|
|
|
out.prototype = clone.object(in.prototype)
|
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
out.property = make(map[string]property, len(in.property))
|
2024-02-24 21:00:04 +00:00
|
|
|
out.propertyOrder = make([]string, len(in.propertyOrder))
|
|
|
|
copy(out.propertyOrder, in.propertyOrder)
|
2024-04-04 14:46:14 +00:00
|
|
|
for index, prop := range in.property {
|
|
|
|
out.property[index] = clone.property(prop)
|
2024-02-24 21:00:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch value := in.value.(type) {
|
2024-04-04 14:46:14 +00:00
|
|
|
case nativeFunctionObject:
|
2024-02-24 21:00:04 +00:00
|
|
|
out.value = value
|
2024-04-04 14:46:14 +00:00
|
|
|
case bindFunctionObject:
|
|
|
|
out.value = bindFunctionObject{
|
2024-02-24 21:00:04 +00:00
|
|
|
target: clone.object(value.target),
|
|
|
|
this: clone.value(value.this),
|
|
|
|
argumentList: clone.valueArray(value.argumentList),
|
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
case nodeFunctionObject:
|
|
|
|
out.value = nodeFunctionObject{
|
2024-02-24 21:00:04 +00:00
|
|
|
node: value.node,
|
|
|
|
stash: clone.stash(value.stash),
|
|
|
|
}
|
2024-04-04 14:46:14 +00:00
|
|
|
case argumentsObject:
|
2024-02-24 21:00:04 +00:00
|
|
|
out.value = value.clone(clone)
|
|
|
|
}
|
|
|
|
|
|
|
|
return out
|
|
|
|
}
|