1
0
mirror of https://github.com/robertkrimen/otto synced 2025-10-19 19:55:30 +08:00
otto/object.go
Robert Krimen 7ff3e8668e Allow (internal) enumeration through _every_ Object property
For .freeze, .isFrozen, etc.
2013-06-02 15:21:25 -07:00

196 lines
4.5 KiB
Go

package otto
type _object struct {
runtime *_runtime
class string
objectClass *_objectClass
value interface{}
prototype *_object
extensible bool
property map[string]_property
propertyOrder []string
}
func newObject(runtime *_runtime, class string) *_object {
self := &_object{
runtime: runtime,
class: class,
objectClass: _classObject,
property: make(map[string]_property),
extensible: true,
}
return self
}
// 8.12
// 8.12.1
func (self *_object) getOwnProperty(name string) *_property {
return self.objectClass.getOwnProperty(self, name)
}
// 8.12.2
func (self *_object) getProperty(name string) *_property {
return self.objectClass.getProperty(self, name)
}
// 8.12.3
func (self *_object) get(name string) Value {
return self.objectClass.get(self, name)
}
// 8.12.4
func (self *_object) canPut(name string) bool {
return self.objectClass.canPut(self, name)
}
// 8.12.5
func (self *_object) put(name string, value Value, throw bool) {
self.objectClass.put(self, name, value, throw)
}
// 8.12.6
func (self *_object) hasProperty(name string) bool {
return self.objectClass.hasProperty(self, name)
}
func (self *_object) hasOwnProperty(name string) bool {
return self.objectClass.hasOwnProperty(self, name)
}
type _defaultValueHint int
const (
defaultValueNoHint _defaultValueHint = iota
defaultValueHintString
defaultValueHintNumber
)
// 8.12.8
func (self *_object) DefaultValue(hint _defaultValueHint) Value {
if hint == defaultValueNoHint {
if self.class == "Date" {
// Date exception
hint = defaultValueHintString
} else {
hint = defaultValueHintNumber
}
}
methodSequence := []string{"valueOf", "toString"}
if hint == defaultValueHintString {
methodSequence = []string{"toString", "valueOf"}
}
for _, methodName := range methodSequence {
method := self.get(methodName)
if method.isCallable() {
result := method._object().Call(toValue(self))
if result.IsPrimitive() {
return result
}
}
}
panic(newTypeError())
return UndefinedValue()
}
func (self *_object) String() string {
return toString(self.DefaultValue(defaultValueHintString))
}
func (self *_object) defineProperty(name string, value Value, mode _propertyMode, throw bool) bool {
return self.defineOwnProperty(name, _property{value, mode}, throw)
}
// 8.12.9
func (self *_object) defineOwnProperty(name string, descriptor _property, throw bool) bool {
return self.objectClass.defineOwnProperty(self, name, descriptor, throw)
}
func (self *_object) delete(name string, throw bool) bool {
return self.objectClass.delete(self, name, throw)
}
func (self *_object) enumerate(all bool, each func(string)) {
self.objectClass.enumerate(self, all, each)
}
func (self *_object) write(definition ...interface{}) {
mode := _propertyMode(0111)
length := 0
nativeClass_ := "native" + self.class + "_"
for index := 0; index < len(definition); index++ {
value := definition[index]
switch value := value.(type) {
case _propertyMode:
mode = value
case string:
name := value
length = 0
index += 1
REPEAT:
{
value := definition[index]
switch value := value.(type) {
case func(FunctionCall) Value:
{
value := self.runtime.newNativeFunction(value, length, nativeClass_+name)
self.defineProperty(name, toValue(value), mode, false)
}
case *_object:
self.defineProperty(name, toValue(value), mode, false)
case Value:
self.defineProperty(name, value, mode, false)
case int:
length = value
index += 1
goto REPEAT
default:
panic(hereBeDragons())
}
}
}
}
}
func (self *_object) _exists(name string) bool {
_, exists := self.property[name]
return exists
}
func (self *_object) _read(name string) (_property, bool) {
property, exists := self.property[name]
return property, exists
}
func (self *_object) _write(name string, value interface{}, mode _propertyMode) {
if value == nil {
value = UndefinedValue()
}
_, exists := self.property[name]
self.property[name] = _property{value, mode}
if !exists {
self.propertyOrder = append(self.propertyOrder, name)
}
}
func (self *_object) _delete(name string) {
_, exists := self.property[name]
delete(self.property, name)
if exists {
for index, property := range self.propertyOrder {
if name == property {
if index == len(self.propertyOrder)-1 {
self.propertyOrder = self.propertyOrder[:index]
} else {
self.propertyOrder = append(self.propertyOrder[:index], self.propertyOrder[index+1:]...)
}
}
}
}
}