aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/robertkrimen/otto/object_class.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/robertkrimen/otto/object_class.go')
-rw-r--r--vendor/github.com/robertkrimen/otto/object_class.go493
1 files changed, 493 insertions, 0 deletions
diff --git a/vendor/github.com/robertkrimen/otto/object_class.go b/vendor/github.com/robertkrimen/otto/object_class.go
new file mode 100644
index 000000000..d18b9cede
--- /dev/null
+++ b/vendor/github.com/robertkrimen/otto/object_class.go
@@ -0,0 +1,493 @@
+package otto
+
+import (
+ "encoding/json"
+)
+
+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, *_clone) *_object
+ marshalJSON func(*_object) json.Marshaler
+}
+
+func objectEnumerate(self *_object, all bool, each func(string) bool) {
+ for _, name := range self.propertyOrder {
+ if all || self.property[name].enumerable() {
+ if !each(name) {
+ return
+ }
+ }
+ }
+}
+
+var (
+ _classObject,
+ _classArray,
+ _classString,
+ _classArguments,
+ _classGoStruct,
+ _classGoMap,
+ _classGoArray,
+ _classGoSlice,
+ _ *_objectClass
+)
+
+func init() {
+ _classObject = &_objectClass{
+ objectGetOwnProperty,
+ objectGetProperty,
+ objectGet,
+ objectCanPut,
+ objectPut,
+ objectHasProperty,
+ objectHasOwnProperty,
+ objectDefineOwnProperty,
+ objectDelete,
+ objectEnumerate,
+ objectClone,
+ nil,
+ }
+
+ _classArray = &_objectClass{
+ objectGetOwnProperty,
+ objectGetProperty,
+ objectGet,
+ objectCanPut,
+ objectPut,
+ objectHasProperty,
+ objectHasOwnProperty,
+ arrayDefineOwnProperty,
+ objectDelete,
+ objectEnumerate,
+ objectClone,
+ nil,
+ }
+
+ _classString = &_objectClass{
+ stringGetOwnProperty,
+ objectGetProperty,
+ objectGet,
+ objectCanPut,
+ objectPut,
+ objectHasProperty,
+ objectHasOwnProperty,
+ objectDefineOwnProperty,
+ objectDelete,
+ stringEnumerate,
+ objectClone,
+ nil,
+ }
+
+ _classArguments = &_objectClass{
+ argumentsGetOwnProperty,
+ objectGetProperty,
+ argumentsGet,
+ objectCanPut,
+ objectPut,
+ objectHasProperty,
+ objectHasOwnProperty,
+ argumentsDefineOwnProperty,
+ argumentsDelete,
+ objectEnumerate,
+ objectClone,
+ nil,
+ }
+
+ _classGoStruct = &_objectClass{
+ goStructGetOwnProperty,
+ objectGetProperty,
+ objectGet,
+ goStructCanPut,
+ goStructPut,
+ objectHasProperty,
+ objectHasOwnProperty,
+ objectDefineOwnProperty,
+ objectDelete,
+ goStructEnumerate,
+ objectClone,
+ goStructMarshalJSON,
+ }
+
+ _classGoMap = &_objectClass{
+ goMapGetOwnProperty,
+ objectGetProperty,
+ objectGet,
+ objectCanPut,
+ objectPut,
+ objectHasProperty,
+ objectHasOwnProperty,
+ goMapDefineOwnProperty,
+ goMapDelete,
+ goMapEnumerate,
+ objectClone,
+ nil,
+ }
+
+ _classGoArray = &_objectClass{
+ goArrayGetOwnProperty,
+ objectGetProperty,
+ objectGet,
+ objectCanPut,
+ objectPut,
+ objectHasProperty,
+ objectHasOwnProperty,
+ goArrayDefineOwnProperty,
+ goArrayDelete,
+ goArrayEnumerate,
+ objectClone,
+ nil,
+ }
+
+ _classGoSlice = &_objectClass{
+ goSliceGetOwnProperty,
+ objectGetProperty,
+ objectGet,
+ objectCanPut,
+ objectPut,
+ objectHasProperty,
+ objectHasOwnProperty,
+ goSliceDefineOwnProperty,
+ goSliceDelete,
+ goSliceEnumerate,
+ objectClone,
+ nil,
+ }
+}
+
+// Allons-y
+
+// 8.12.1
+func objectGetOwnProperty(self *_object, name string) *_property {
+ // Return a _copy_ of the property
+ property, exists := self._read(name)
+ if !exists {
+ return nil
+ }
+ return &property
+}
+
+// 8.12.2
+func objectGetProperty(self *_object, name string) *_property {
+ property := self.getOwnProperty(name)
+ if property != nil {
+ return property
+ }
+ if self.prototype != nil {
+ return self.prototype.getProperty(name)
+ }
+ return nil
+}
+
+// 8.12.3
+func objectGet(self *_object, name string) Value {
+ property := self.getProperty(name)
+ if property != nil {
+ return property.get(self)
+ }
+ return Value{}
+}
+
+// 8.12.4
+func objectCanPut(self *_object, name string) bool {
+ canPut, _, _ := _objectCanPut(self, name)
+ return canPut
+}
+
+func _objectCanPut(self *_object, name string) (canPut bool, property *_property, setter *_object) {
+ property = self.getOwnProperty(name)
+ if property != nil {
+ switch propertyValue := property.value.(type) {
+ case Value:
+ canPut = property.writable()
+ return
+ case _propertyGetSet:
+ setter = propertyValue[1]
+ canPut = setter != nil
+ return
+ default:
+ panic(self.runtime.panicTypeError())
+ }
+ }
+
+ if self.prototype == nil {
+ return self.extensible, nil, nil
+ }
+
+ property = self.prototype.getProperty(name)
+ if property == nil {
+ return self.extensible, nil, nil
+ }
+
+ switch propertyValue := property.value.(type) {
+ case Value:
+ if !self.extensible {
+ return false, nil, nil
+ }
+ return property.writable(), nil, nil
+ case _propertyGetSet:
+ setter = propertyValue[1]
+ canPut = setter != nil
+ return
+ default:
+ panic(self.runtime.panicTypeError())
+ }
+}
+
+// 8.12.5
+func objectPut(self *_object, name string, value Value, throw bool) {
+
+ 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
+ canPut, property, setter := _objectCanPut(self, name)
+ if !canPut {
+ self.runtime.typeErrorResult(throw)
+ } else if setter != nil {
+ setter.call(toValue(self), []Value{value}, false, nativeFrame)
+ } else if property != nil {
+ property.value = value
+ self.defineOwnProperty(name, *property, throw)
+ } else {
+ self.defineProperty(name, value, 0111, throw)
+ }
+ return
+ }
+
+ // The long way...
+ //
+ // Right now, code should never get here, see above
+ if !self.canPut(name) {
+ self.runtime.typeErrorResult(throw)
+ return
+ }
+
+ property := self.getOwnProperty(name)
+ if property == nil {
+ property = self.getProperty(name)
+ if property != nil {
+ if getSet, isAccessor := property.value.(_propertyGetSet); isAccessor {
+ getSet[1].call(toValue(self), []Value{value}, false, nativeFrame)
+ return
+ }
+ }
+ self.defineProperty(name, value, 0111, throw)
+ } else {
+ switch propertyValue := property.value.(type) {
+ case Value:
+ property.value = value
+ self.defineOwnProperty(name, *property, throw)
+ case _propertyGetSet:
+ if propertyValue[1] != nil {
+ propertyValue[1].call(toValue(self), []Value{value}, false, nativeFrame)
+ return
+ }
+ if throw {
+ panic(self.runtime.panicTypeError())
+ }
+ default:
+ panic(self.runtime.panicTypeError())
+ }
+ }
+}
+
+// 8.12.6
+func objectHasProperty(self *_object, name string) bool {
+ return self.getProperty(name) != nil
+}
+
+func objectHasOwnProperty(self *_object, name string) bool {
+ return self.getOwnProperty(name) != nil
+}
+
+// 8.12.9
+func objectDefineOwnProperty(self *_object, name string, descriptor _property, throw bool) bool {
+ property, exists := self._read(name)
+ {
+ if !exists {
+ if !self.extensible {
+ goto Reject
+ }
+ if newGetSet, isAccessor := descriptor.value.(_propertyGetSet); isAccessor {
+ if newGetSet[0] == &_nilGetSetObject {
+ newGetSet[0] = nil
+ }
+ if newGetSet[1] == &_nilGetSetObject {
+ newGetSet[1] = nil
+ }
+ descriptor.value = newGetSet
+ }
+ self._write(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 := property.configurable()
+ if !configurable {
+ if descriptor.configurable() {
+ goto Reject
+ }
+ // 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() != property.enumerable() {
+ goto Reject
+ }
+ }
+ value, isDataDescriptor := property.value.(Value)
+ getSet, _ := property.value.(_propertyGetSet)
+ if descriptor.isGenericDescriptor() {
+ // GenericDescriptor
+ } else if isDataDescriptor != descriptor.isDataDescriptor() {
+ // DataDescriptor <=> AccessorDescriptor
+ if !configurable {
+ goto Reject
+ }
+ } else if isDataDescriptor && descriptor.isDataDescriptor() {
+ // DataDescriptor <=> DataDescriptor
+ if !configurable {
+ if !property.writable() && descriptor.writable() {
+ goto Reject
+ }
+ if !property.writable() {
+ if descriptor.value != nil && !sameValue(value, descriptor.value.(Value)) {
+ goto Reject
+ }
+ }
+ }
+ } else {
+ // 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])) {
+ goto Reject
+ }
+ }
+ descriptor.value = newGetSet
+ }
+ {
+ // This section will preserve attributes of
+ // the original property, if necessary
+ value1 := descriptor.value
+ if value1 == nil {
+ value1 = property.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&0222 != 0 {
+ // TODO Factor this out into somewhere testable
+ // (Maybe put into switch ...)
+ mode0 := property.mode
+ if mode1&0200 != 0 {
+ if descriptor.isDataDescriptor() {
+ mode1 &= ^0200 // Turn off "writable" missing
+ mode1 |= (mode0 & 0100)
+ }
+ }
+ if mode1&020 != 0 {
+ mode1 |= (mode0 & 010)
+ }
+ if mode1&02 != 0 {
+ mode1 |= (mode0 & 01)
+ }
+ mode1 &= 0311 // 0311 to preserve the non-setting on "writable"
+ }
+ self._write(name, value1, mode1)
+ }
+ return true
+ }
+Reject:
+ if throw {
+ panic(self.runtime.panicTypeError())
+ }
+ return false
+}
+
+func objectDelete(self *_object, name string, throw bool) bool {
+ property_ := self.getOwnProperty(name)
+ if property_ == nil {
+ return true
+ }
+ if property_.configurable() {
+ self._delete(name)
+ return true
+ }
+ return self.runtime.typeErrorResult(throw)
+}
+
+func objectClone(in *_object, out *_object, clone *_clone) *_object {
+ *out = *in
+
+ out.runtime = clone.runtime
+ if out.prototype != nil {
+ out.prototype = clone.object(in.prototype)
+ }
+ out.property = make(map[string]_property, len(in.property))
+ out.propertyOrder = make([]string, len(in.propertyOrder))
+ copy(out.propertyOrder, in.propertyOrder)
+ for index, property := range in.property {
+ out.property[index] = clone.property(property)
+ }
+
+ switch value := in.value.(type) {
+ case _nativeFunctionObject:
+ out.value = value
+ case _bindFunctionObject:
+ out.value = _bindFunctionObject{
+ target: clone.object(value.target),
+ this: clone.value(value.this),
+ argumentList: clone.valueArray(value.argumentList),
+ }
+ case _nodeFunctionObject:
+ out.value = _nodeFunctionObject{
+ node: value.node,
+ stash: clone.stash(value.stash),
+ }
+ case _argumentsObject:
+ out.value = value.clone(clone)
+ }
+
+ return out
+}