mirror of
https://github.com/robertkrimen/otto
synced 2025-10-12 20:27:30 +08:00
150 lines
3.4 KiB
Go
150 lines
3.4 KiB
Go
package otto
|
|
|
|
// property
|
|
|
|
type _propertyMode int
|
|
|
|
const (
|
|
propertyMode_write _propertyMode = 0100
|
|
propertyMode_enumerate = 0010
|
|
propertyMode_configure = 0001
|
|
)
|
|
|
|
type _propertyGetSet [2]*_object
|
|
|
|
type _property struct {
|
|
value interface{}
|
|
mode _propertyMode
|
|
}
|
|
|
|
func (self _property) writable() bool {
|
|
return self.mode & 0700 == 0100
|
|
}
|
|
|
|
func (self _property) enumerable() bool {
|
|
return self.mode & 0070 == 0010
|
|
}
|
|
|
|
func (self _property) configurable() bool {
|
|
return self.mode & 0007 == 0001
|
|
}
|
|
|
|
func (self _property) copy() *_property {
|
|
property := self
|
|
return &property
|
|
}
|
|
|
|
func (self _property) isAccessorDescriptor() bool {
|
|
setGet, test := self.value.(_propertyGetSet)
|
|
return test && setGet[0] != nil || setGet[1] != nil
|
|
}
|
|
|
|
func (self _property) isDataDescriptor() bool {
|
|
value, test := self.value.(Value)
|
|
return self.mode & 0700 != 0200 || (test && !value.isEmpty())
|
|
}
|
|
|
|
func (self _property) isGenericDescriptor() bool {
|
|
return !(self.isDataDescriptor() || self.isAccessorDescriptor())
|
|
}
|
|
|
|
func (self _property) isEmpty() bool {
|
|
return self.mode == 0222 && self.isGenericDescriptor()
|
|
}
|
|
|
|
// _enumerableValue, _enumerableTrue, _enumerableFalse?
|
|
// .enumerableValue() .enumerableExists()
|
|
|
|
func toPropertyDescriptor(value Value) (descriptor _property) {
|
|
objectDescriptor := value._object()
|
|
if objectDescriptor == nil {
|
|
panic(newTypeError())
|
|
}
|
|
|
|
{
|
|
mode := _propertyMode(0)
|
|
if objectDescriptor.hasProperty("enumerable") {
|
|
if objectDescriptor.get("enumerable").toBoolean() {
|
|
mode |= 0010
|
|
}
|
|
} else {
|
|
mode |= 0020
|
|
}
|
|
|
|
if objectDescriptor.hasProperty("configurable") {
|
|
if objectDescriptor.get("configurable").toBoolean() {
|
|
mode |= 0001
|
|
}
|
|
} else {
|
|
mode |= 0002
|
|
}
|
|
|
|
if objectDescriptor.hasProperty("writable") {
|
|
if objectDescriptor.get("writable").toBoolean() {
|
|
mode |= 0100
|
|
}
|
|
} else {
|
|
mode |= 0200
|
|
}
|
|
descriptor.mode = mode
|
|
}
|
|
|
|
|
|
var getter, setter *_object
|
|
getterSetter := false
|
|
|
|
if objectDescriptor.hasProperty("get") {
|
|
value := objectDescriptor.get("get")
|
|
if value.IsDefined() {
|
|
if !value.isCallable() {
|
|
panic(newTypeError())
|
|
}
|
|
getter = value._object()
|
|
getterSetter = getterSetter || getter != nil
|
|
}
|
|
}
|
|
|
|
if objectDescriptor.hasProperty("set") {
|
|
value := objectDescriptor.get("set")
|
|
if value.IsDefined() {
|
|
if !value.isCallable() {
|
|
panic(newTypeError())
|
|
}
|
|
setter = value._object()
|
|
getterSetter = getterSetter || setter != nil
|
|
}
|
|
}
|
|
|
|
if (getterSetter) {
|
|
// If writable is set on the descriptor, ...
|
|
if descriptor.mode & 0200 != 0 {
|
|
panic(newTypeError())
|
|
}
|
|
descriptor.value = _propertyGetSet{getter, setter}
|
|
}
|
|
|
|
if objectDescriptor.hasProperty("value") {
|
|
if (getterSetter) {
|
|
panic(newTypeError())
|
|
}
|
|
descriptor.value = objectDescriptor.get("value")
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (self *_runtime) fromPropertyDescriptor(descriptor _property) *_object {
|
|
object := self.newObject()
|
|
if descriptor.isDataDescriptor() {
|
|
object.stash.set("value", descriptor.value.(Value), 0111)
|
|
object.stash.set("writable", toValue(descriptor.writable()), 0111)
|
|
} else if descriptor.isAccessorDescriptor() {
|
|
getSet := descriptor.value.(_propertyGetSet)
|
|
object.stash.set("get", toValue(getSet[0]), 0111)
|
|
object.stash.set("set", toValue(getSet[1]), 0111)
|
|
}
|
|
object.stash.set("enumerable", toValue(descriptor.enumerable()), 0111)
|
|
object.stash.set("configurable", toValue(descriptor.configurable()), 0111)
|
|
return object
|
|
}
|