forked from robertkrimen/otto
/
property.go
149 lines (124 loc) · 3.45 KB
/
property.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
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") {
descriptor.value = UndefinedValue() // FIXME Is this the right place for this?
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
}