1
0
mirror of https://github.com/robertkrimen/otto synced 2025-10-12 20:27:30 +08:00
otto/builtin_object.go
Robert Krimen c55510cb36 Inline context initialization & improve _object.value
* Context setup is now done via _newContext.
* _newContext is a function that resides in inline.go. _newContext is very flat,
resulting in almost no function calls (a 180 from the earlier status quo).
* inline.go is a Go source file that is built by Perl (via inline).
* Lots of crufty functions removed (along with all of their TODO & FIXME).
* In addition, before, the underlying value of _object.value was a pointer to
something. This made for extra work, since the type of _object.value is interface{},
which is already something of a pointer. Now, the underlying value of _object.value
in Function, Date, RegExp, ..., is a struct value.
* type_function.go was streamlined, removing superfluous struct fields and methods.
* There is now less "digging" to get to the actual value of a function, which is important
when makings lots of calls.

Before (without inline):

    PASS
    BenchmarkNew        2000           1067871 ns/op
    ok      github.com/robertkrimen/otto    3.336s
    PASS
    BenchmarkNew        2000           1077644 ns/op
    ok      github.com/robertkrimen/otto    3.367s

After (with inline):

    PASS
    BenchmarkNew       10000            364418 ns/op
    ok      github.com/robertkrimen/otto    4.616s
    PASS
    BenchmarkNew       10000            307241 ns/op
    ok      github.com/robertkrimen/otto    4.051s

This (partially) fixes #22
2013-06-09 18:28:18 -07:00

282 lines
6.8 KiB
Go

package otto
import (
"fmt"
)
// Object
func builtinObject(call FunctionCall) Value {
value := call.Argument(0)
switch value._valueType {
case valueUndefined, valueNull:
return toValue(call.runtime.newObject())
}
return toValue(call.runtime.toObject(value))
}
func builtinNewObject(self *_object, _ Value, argumentList []Value) Value {
value := valueOfArrayIndex(argumentList, 0)
switch value._valueType {
case valueNull, valueUndefined:
case valueNumber, valueString, valueBoolean:
return toValue(self.runtime.toObject(value))
case valueObject:
return value
default:
}
return toValue(self.runtime.newObject())
}
func builtinObject_valueOf(call FunctionCall) Value {
return toValue(call.thisObject())
}
func builtinObject_hasOwnProperty(call FunctionCall) Value {
propertyName := toString(call.Argument(0))
thisObject := call.thisObject()
return toValue(thisObject.hasOwnProperty(propertyName))
}
func builtinObject_isPrototypeOf(call FunctionCall) Value {
value := call.Argument(0)
if !value.IsObject() {
return FalseValue()
}
prototype := call.toObject(value).prototype
thisObject := call.thisObject()
for prototype != nil {
if thisObject == prototype {
return TrueValue()
}
prototype = prototype.prototype
}
return FalseValue()
}
func builtinObject_propertyIsEnumerable(call FunctionCall) Value {
propertyName := toString(call.Argument(0))
thisObject := call.thisObject()
property := thisObject.getOwnProperty(propertyName)
if property != nil && property.enumerable() {
return TrueValue()
}
return FalseValue()
}
func builtinObject_toString(call FunctionCall) Value {
result := ""
if call.This.IsUndefined() {
result = "[object Undefined]"
} else if call.This.IsNull() {
result = "[object Null]"
} else {
result = fmt.Sprintf("[object %s]", call.thisObject().class)
}
return toValue(result)
}
func builtinObject_toLocaleString(call FunctionCall) Value {
toString := call.thisObject().get("toString")
if !toString.isCallable() {
panic(newTypeError())
}
return toString.call(call.This)
}
func builtinObject_getPrototypeOf(call FunctionCall) Value {
objectValue := call.Argument(0)
object := objectValue._object()
if object == nil {
panic(newTypeError())
}
if object.prototype == nil {
return NullValue()
}
return toValue(object.prototype)
}
func builtinObject_getOwnPropertyDescriptor(call FunctionCall) Value {
objectValue := call.Argument(0)
object := objectValue._object()
if object == nil {
panic(newTypeError())
}
name := toString(call.Argument(1))
descriptor := object.getOwnProperty(name)
if descriptor == nil {
return UndefinedValue()
}
return toValue(call.runtime.fromPropertyDescriptor(*descriptor))
}
func builtinObject_defineProperty(call FunctionCall) Value {
objectValue := call.Argument(0)
object := objectValue._object()
if object == nil {
panic(newTypeError())
}
name := toString(call.Argument(1))
descriptor := toPropertyDescriptor(call.Argument(2))
object.defineOwnProperty(name, descriptor, true)
return objectValue
}
func builtinObject_defineProperties(call FunctionCall) Value {
objectValue := call.Argument(0)
object := objectValue._object()
if object == nil {
panic(newTypeError())
}
properties := call.runtime.toObject(call.Argument(1))
properties.enumerate(true, func(name string) {
descriptor := toPropertyDescriptor(properties.get(name))
object.defineOwnProperty(name, descriptor, true)
})
return objectValue
}
func builtinObject_create(call FunctionCall) Value {
prototypeValue := call.Argument(0)
prototype := prototypeValue._object()
if prototype == nil {
panic(newTypeError())
}
object := call.runtime.newObject()
propertiesValue := call.Argument(1)
if propertiesValue.IsDefined() {
properties := call.runtime.toObject(propertiesValue)
properties.enumerate(true, func(name string) {
descriptor := toPropertyDescriptor(properties.get(name))
object.defineOwnProperty(name, descriptor, true)
})
}
return toValue(object)
}
func builtinObject_isExtensible(call FunctionCall) Value {
object := call.Argument(0)
if object := object._object(); object != nil {
return toValue(object.extensible)
}
panic(newTypeError())
}
func builtinObject_preventExtensions(call FunctionCall) Value {
object := call.Argument(0)
if object := object._object(); object != nil {
object.extensible = false
} else {
panic(newTypeError())
}
return object
}
func builtinObject_isSealed(call FunctionCall) Value {
object := call.Argument(0)
if object := object._object(); object != nil {
if object.extensible {
return toValue(false)
}
result := true
object.enumerate(true, func(name string) {
property := object.getProperty(name)
if property.configurable() {
result = false
}
})
return toValue(result)
}
panic(newTypeError())
}
func builtinObject_seal(call FunctionCall) Value {
object := call.Argument(0)
if object := object._object(); object != nil {
object.enumerate(true, func(name string) {
if property := object.getOwnProperty(name); nil != property && property.configurable() {
property.configureOff()
object.defineOwnProperty(name, *property, true)
}
})
object.extensible = false
} else {
panic(newTypeError())
}
return object
}
func builtinObject_isFrozen(call FunctionCall) Value {
object := call.Argument(0)
if object := object._object(); object != nil {
if object.extensible {
return toValue(false)
}
result := true
object.enumerate(true, func(name string) {
property := object.getProperty(name)
if property.configurable() || property.writable() {
result = false
}
})
return toValue(result)
}
panic(newTypeError())
}
func builtinObject_freeze(call FunctionCall) Value {
object := call.Argument(0)
if object := object._object(); object != nil {
object.enumerate(true, func(name string) {
if property, update := object.getOwnProperty(name), false; nil != property {
if property.isDataDescriptor() && property.writable() {
property.writeOff()
update = true
}
if property.configurable() {
property.configureOff()
update = true
}
if update {
object.defineOwnProperty(name, *property, true)
}
}
})
object.extensible = false
} else {
panic(newTypeError())
}
return object
}
func builtinObject_keys(call FunctionCall) Value {
if object, keys := call.Argument(0)._object(), []Value(nil); nil != object {
object.enumerate(false, func(name string) {
keys = append(keys, toValue(name))
})
return toValue(call.runtime.newArrayOf(keys))
}
panic(newTypeError())
}
func builtinObject_getOwnPropertyNames(call FunctionCall) Value {
if object, propertyNames := call.Argument(0)._object(), []Value(nil); nil != object {
object.enumerate(true, func(name string) {
if object.hasOwnProperty(name) {
propertyNames = append(propertyNames, toValue(name))
}
})
return toValue(call.runtime.newArrayOf(propertyNames))
}
panic(newTypeError())
}