1 package goja
2
3 import (
4 "reflect"
5
6 "github.com/dop251/goja/unistring"
7 )
8
9 type objectGoMapReflect struct {
10 objectGoReflect
11
12 keyType, valueType reflect.Type
13 }
14
15 func (o *objectGoMapReflect) init() {
16 o.objectGoReflect.init()
17 o.keyType = o.fieldsValue.Type().Key()
18 o.valueType = o.fieldsValue.Type().Elem()
19 }
20
21 func (o *objectGoMapReflect) toKey(n Value, throw bool) reflect.Value {
22 key := reflect.New(o.keyType).Elem()
23 err := o.val.runtime.toReflectValue(n, key, &objectExportCtx{})
24 if err != nil {
25 o.val.runtime.typeErrorResult(throw, "map key conversion error: %v", err)
26 return reflect.Value{}
27 }
28 return key
29 }
30
31 func (o *objectGoMapReflect) strToKey(name string, throw bool) reflect.Value {
32 if o.keyType.Kind() == reflect.String {
33 return reflect.ValueOf(name).Convert(o.keyType)
34 }
35 return o.toKey(newStringValue(name), throw)
36 }
37
38 func (o *objectGoMapReflect) _getKey(key reflect.Value) Value {
39 if !key.IsValid() {
40 return nil
41 }
42 if v := o.fieldsValue.MapIndex(key); v.IsValid() {
43 rv := v
44 if rv.Kind() == reflect.Interface {
45 rv = rv.Elem()
46 }
47 return o.val.runtime.toValue(v.Interface(), rv)
48 }
49
50 return nil
51 }
52
53 func (o *objectGoMapReflect) _get(n Value) Value {
54 return o._getKey(o.toKey(n, false))
55 }
56
57 func (o *objectGoMapReflect) _getStr(name string) Value {
58 return o._getKey(o.strToKey(name, false))
59 }
60
61 func (o *objectGoMapReflect) getStr(name unistring.String, receiver Value) Value {
62 if v := o._getStr(name.String()); v != nil {
63 return v
64 }
65 return o.objectGoReflect.getStr(name, receiver)
66 }
67
68 func (o *objectGoMapReflect) getIdx(idx valueInt, receiver Value) Value {
69 if v := o._get(idx); v != nil {
70 return v
71 }
72 return o.objectGoReflect.getIdx(idx, receiver)
73 }
74
75 func (o *objectGoMapReflect) getOwnPropStr(name unistring.String) Value {
76 if v := o._getStr(name.String()); v != nil {
77 return &valueProperty{
78 value: v,
79 writable: true,
80 enumerable: true,
81 }
82 }
83 return o.objectGoReflect.getOwnPropStr(name)
84 }
85
86 func (o *objectGoMapReflect) getOwnPropIdx(idx valueInt) Value {
87 if v := o._get(idx); v != nil {
88 return &valueProperty{
89 value: v,
90 writable: true,
91 enumerable: true,
92 }
93 }
94 return o.objectGoReflect.getOwnPropStr(idx.string())
95 }
96
97 func (o *objectGoMapReflect) toValue(val Value, throw bool) (reflect.Value, bool) {
98 v := reflect.New(o.valueType).Elem()
99 err := o.val.runtime.toReflectValue(val, v, &objectExportCtx{})
100 if err != nil {
101 o.val.runtime.typeErrorResult(throw, "map value conversion error: %v", err)
102 return reflect.Value{}, false
103 }
104
105 return v, true
106 }
107
108 func (o *objectGoMapReflect) _put(key reflect.Value, val Value, throw bool) bool {
109 if key.IsValid() {
110 if o.extensible || o.fieldsValue.MapIndex(key).IsValid() {
111 v, ok := o.toValue(val, throw)
112 if !ok {
113 return false
114 }
115 o.fieldsValue.SetMapIndex(key, v)
116 } else {
117 o.val.runtime.typeErrorResult(throw, "Cannot set property %s, object is not extensible", key.String())
118 return false
119 }
120 return true
121 }
122 return false
123 }
124
125 func (o *objectGoMapReflect) setOwnStr(name unistring.String, val Value, throw bool) bool {
126 n := name.String()
127 key := o.strToKey(n, false)
128 if !key.IsValid() || !o.fieldsValue.MapIndex(key).IsValid() {
129 if proto := o.prototype; proto != nil {
130
131 if res, ok := proto.self.setForeignStr(name, val, o.val, throw); ok {
132 return res
133 }
134 }
135
136 if !o.extensible {
137 o.val.runtime.typeErrorResult(throw, "Cannot add property %s, object is not extensible", n)
138 return false
139 } else {
140 if throw && !key.IsValid() {
141 o.strToKey(n, true)
142 return false
143 }
144 }
145 }
146 o._put(key, val, throw)
147 return true
148 }
149
150 func (o *objectGoMapReflect) setOwnIdx(idx valueInt, val Value, throw bool) bool {
151 key := o.toKey(idx, false)
152 if !key.IsValid() || !o.fieldsValue.MapIndex(key).IsValid() {
153 if proto := o.prototype; proto != nil {
154
155 if res, ok := proto.self.setForeignIdx(idx, val, o.val, throw); ok {
156 return res
157 }
158 }
159
160 if !o.extensible {
161 o.val.runtime.typeErrorResult(throw, "Cannot add property %d, object is not extensible", idx)
162 return false
163 } else {
164 if throw && !key.IsValid() {
165 o.toKey(idx, true)
166 return false
167 }
168 }
169 }
170 o._put(key, val, throw)
171 return true
172 }
173
174 func (o *objectGoMapReflect) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
175 return o._setForeignStr(name, trueValIfPresent(o.hasOwnPropertyStr(name)), val, receiver, throw)
176 }
177
178 func (o *objectGoMapReflect) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
179 return o._setForeignIdx(idx, trueValIfPresent(o.hasOwnPropertyIdx(idx)), val, receiver, throw)
180 }
181
182 func (o *objectGoMapReflect) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
183 if !o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) {
184 return false
185 }
186
187 return o._put(o.strToKey(name.String(), throw), descr.Value, throw)
188 }
189
190 func (o *objectGoMapReflect) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
191 if !o.val.runtime.checkHostObjectPropertyDescr(idx.string(), descr, throw) {
192 return false
193 }
194
195 return o._put(o.toKey(idx, throw), descr.Value, throw)
196 }
197
198 func (o *objectGoMapReflect) hasOwnPropertyStr(name unistring.String) bool {
199 key := o.strToKey(name.String(), false)
200 if key.IsValid() && o.fieldsValue.MapIndex(key).IsValid() {
201 return true
202 }
203 return false
204 }
205
206 func (o *objectGoMapReflect) hasOwnPropertyIdx(idx valueInt) bool {
207 key := o.toKey(idx, false)
208 if key.IsValid() && o.fieldsValue.MapIndex(key).IsValid() {
209 return true
210 }
211 return false
212 }
213
214 func (o *objectGoMapReflect) deleteStr(name unistring.String, throw bool) bool {
215 key := o.strToKey(name.String(), throw)
216 if !key.IsValid() {
217 return false
218 }
219 o.fieldsValue.SetMapIndex(key, reflect.Value{})
220 return true
221 }
222
223 func (o *objectGoMapReflect) deleteIdx(idx valueInt, throw bool) bool {
224 key := o.toKey(idx, throw)
225 if !key.IsValid() {
226 return false
227 }
228 o.fieldsValue.SetMapIndex(key, reflect.Value{})
229 return true
230 }
231
232 type gomapReflectPropIter struct {
233 o *objectGoMapReflect
234 keys []reflect.Value
235 idx int
236 }
237
238 func (i *gomapReflectPropIter) next() (propIterItem, iterNextFunc) {
239 for i.idx < len(i.keys) {
240 key := i.keys[i.idx]
241 v := i.o.fieldsValue.MapIndex(key)
242 i.idx++
243 if v.IsValid() {
244 return propIterItem{name: newStringValue(key.String()), enumerable: _ENUM_TRUE}, i.next
245 }
246 }
247
248 return propIterItem{}, nil
249 }
250
251 func (o *objectGoMapReflect) iterateStringKeys() iterNextFunc {
252 return (&gomapReflectPropIter{
253 o: o,
254 keys: o.fieldsValue.MapKeys(),
255 }).next
256 }
257
258 func (o *objectGoMapReflect) stringKeys(_ bool, accum []Value) []Value {
259
260 for _, key := range o.fieldsValue.MapKeys() {
261 accum = append(accum, newStringValue(key.String()))
262 }
263
264 return accum
265 }
266
View as plain text