1 package goja
2
3 import (
4 "fmt"
5 "go/ast"
6 "reflect"
7 "strings"
8
9 "github.com/dop251/goja/parser"
10 "github.com/dop251/goja/unistring"
11 )
12
13
14
15 type JsonEncodable interface {
16 JsonEncodable() interface{}
17 }
18
19
20 type FieldNameMapper interface {
21
22
23 FieldName(t reflect.Type, f reflect.StructField) string
24
25
26
27 MethodName(t reflect.Type, m reflect.Method) string
28 }
29
30 type tagFieldNameMapper struct {
31 tagName string
32 uncapMethods bool
33 }
34
35 func (tfm tagFieldNameMapper) FieldName(_ reflect.Type, f reflect.StructField) string {
36 tag := f.Tag.Get(tfm.tagName)
37 if idx := strings.IndexByte(tag, ','); idx != -1 {
38 tag = tag[:idx]
39 }
40 if parser.IsIdentifier(tag) {
41 return tag
42 }
43 return ""
44 }
45
46 func uncapitalize(s string) string {
47 return strings.ToLower(s[0:1]) + s[1:]
48 }
49
50 func (tfm tagFieldNameMapper) MethodName(_ reflect.Type, m reflect.Method) string {
51 if tfm.uncapMethods {
52 return uncapitalize(m.Name)
53 }
54 return m.Name
55 }
56
57 type uncapFieldNameMapper struct {
58 }
59
60 func (u uncapFieldNameMapper) FieldName(_ reflect.Type, f reflect.StructField) string {
61 return uncapitalize(f.Name)
62 }
63
64 func (u uncapFieldNameMapper) MethodName(_ reflect.Type, m reflect.Method) string {
65 return uncapitalize(m.Name)
66 }
67
68 type reflectFieldInfo struct {
69 Index []int
70 Anonymous bool
71 }
72
73 type reflectFieldsInfo struct {
74 Fields map[string]reflectFieldInfo
75 Names []string
76 }
77
78 type reflectMethodsInfo struct {
79 Methods map[string]int
80 Names []string
81 }
82
83 type reflectValueWrapper interface {
84 esValue() Value
85 reflectValue() reflect.Value
86 setReflectValue(reflect.Value)
87 }
88
89 func isContainer(k reflect.Kind) bool {
90 switch k {
91 case reflect.Struct, reflect.Slice, reflect.Array:
92 return true
93 }
94 return false
95 }
96
97 func copyReflectValueWrapper(w reflectValueWrapper) {
98 v := w.reflectValue()
99 c := reflect.New(v.Type()).Elem()
100 c.Set(v)
101 w.setReflectValue(c)
102 }
103
104 type objectGoReflect struct {
105 baseObject
106 origValue, fieldsValue reflect.Value
107
108 fieldsInfo *reflectFieldsInfo
109 methodsInfo *reflectMethodsInfo
110
111 methodsValue reflect.Value
112
113 valueCache map[string]reflectValueWrapper
114
115 toString, valueOf func() Value
116
117 toJson func() interface{}
118 }
119
120 func (o *objectGoReflect) init() {
121 o.baseObject.init()
122 switch o.fieldsValue.Kind() {
123 case reflect.Bool:
124 o.class = classBoolean
125 o.prototype = o.val.runtime.getBooleanPrototype()
126 o.toString = o._toStringBool
127 o.valueOf = o._valueOfBool
128 case reflect.String:
129 o.class = classString
130 o.prototype = o.val.runtime.getStringPrototype()
131 o.toString = o._toStringString
132 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
133 o.class = classNumber
134 o.prototype = o.val.runtime.getNumberPrototype()
135 o.valueOf = o._valueOfInt
136 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
137 o.class = classNumber
138 o.prototype = o.val.runtime.getNumberPrototype()
139 o.valueOf = o._valueOfUint
140 case reflect.Float32, reflect.Float64:
141 o.class = classNumber
142 o.prototype = o.val.runtime.getNumberPrototype()
143 o.valueOf = o._valueOfFloat
144 default:
145 o.class = classObject
146 o.prototype = o.val.runtime.global.ObjectPrototype
147 }
148
149 if o.fieldsValue.Kind() == reflect.Struct {
150 o.fieldsInfo = o.val.runtime.fieldsInfo(o.fieldsValue.Type())
151 }
152
153 var methodsType reflect.Type
154
155
156 if o.fieldsValue.Kind() != reflect.Interface {
157 methodsType = reflect.PtrTo(o.fieldsValue.Type())
158 } else {
159 methodsType = o.fieldsValue.Type()
160 }
161
162 o.methodsInfo = o.val.runtime.methodsInfo(methodsType)
163
164
165
166 if !o.origValue.CanAddr() && (isContainer(o.origValue.Kind()) || len(o.methodsInfo.Names) > 0) {
167 value := reflect.New(o.origValue.Type()).Elem()
168 value.Set(o.origValue)
169 o.origValue = value
170 if value.Kind() != reflect.Ptr {
171 o.fieldsValue = value
172 }
173 }
174
175 o.extensible = true
176
177 switch o.origValue.Interface().(type) {
178 case fmt.Stringer:
179 o.toString = o._toStringStringer
180 case error:
181 o.toString = o._toStringError
182 }
183
184 if len(o.methodsInfo.Names) > 0 && o.fieldsValue.Kind() != reflect.Interface {
185 o.methodsValue = o.fieldsValue.Addr()
186 } else {
187 o.methodsValue = o.fieldsValue
188 }
189
190 if j, ok := o.origValue.Interface().(JsonEncodable); ok {
191 o.toJson = j.JsonEncodable
192 }
193 }
194
195 func (o *objectGoReflect) getStr(name unistring.String, receiver Value) Value {
196 if v := o._get(name.String()); v != nil {
197 return v
198 }
199 return o.baseObject.getStr(name, receiver)
200 }
201
202 func (o *objectGoReflect) _getField(jsName string) reflect.Value {
203 if o.fieldsInfo != nil {
204 if info, exists := o.fieldsInfo.Fields[jsName]; exists {
205 return o.fieldsValue.FieldByIndex(info.Index)
206 }
207 }
208
209 return reflect.Value{}
210 }
211
212 func (o *objectGoReflect) _getMethod(jsName string) reflect.Value {
213 if o.methodsInfo != nil {
214 if idx, exists := o.methodsInfo.Methods[jsName]; exists {
215 return o.methodsValue.Method(idx)
216 }
217 }
218
219 return reflect.Value{}
220 }
221
222 func (o *objectGoReflect) elemToValue(ev reflect.Value) (Value, reflectValueWrapper) {
223 if isContainer(ev.Kind()) {
224 ret := o.val.runtime.toValue(ev.Interface(), ev)
225 if obj, ok := ret.(*Object); ok {
226 if w, ok := obj.self.(reflectValueWrapper); ok {
227 return ret, w
228 }
229 }
230 return ret, nil
231 }
232
233 if ev.Kind() == reflect.Interface {
234 ev = ev.Elem()
235 }
236
237 if ev.Kind() == reflect.Invalid {
238 return _null, nil
239 }
240
241 return o.val.runtime.toValue(ev.Interface(), ev), nil
242 }
243
244 func (o *objectGoReflect) _getFieldValue(name string) Value {
245 if v := o.valueCache[name]; v != nil {
246 return v.esValue()
247 }
248 if v := o._getField(name); v.IsValid() {
249 res, w := o.elemToValue(v)
250 if w != nil {
251 if o.valueCache == nil {
252 o.valueCache = make(map[string]reflectValueWrapper)
253 }
254 o.valueCache[name] = w
255 }
256 return res
257 }
258 return nil
259 }
260
261 func (o *objectGoReflect) _get(name string) Value {
262 if o.fieldsValue.Kind() == reflect.Struct {
263 if ret := o._getFieldValue(name); ret != nil {
264 return ret
265 }
266 }
267
268 if v := o._getMethod(name); v.IsValid() {
269 return o.val.runtime.toValue(v.Interface(), v)
270 }
271
272 return nil
273 }
274
275 func (o *objectGoReflect) getOwnPropStr(name unistring.String) Value {
276 n := name.String()
277 if o.fieldsValue.Kind() == reflect.Struct {
278 if v := o._getFieldValue(n); v != nil {
279 return &valueProperty{
280 value: v,
281 writable: true,
282 enumerable: true,
283 }
284 }
285 }
286
287 if v := o._getMethod(n); v.IsValid() {
288 return &valueProperty{
289 value: o.val.runtime.toValue(v.Interface(), v),
290 enumerable: true,
291 }
292 }
293
294 return o.baseObject.getOwnPropStr(name)
295 }
296
297 func (o *objectGoReflect) setOwnStr(name unistring.String, val Value, throw bool) bool {
298 has, ok := o._put(name.String(), val, throw)
299 if !has {
300 if res, ok := o._setForeignStr(name, nil, val, o.val, throw); !ok {
301 o.val.runtime.typeErrorResult(throw, "Cannot assign to property %s of a host object", name)
302 return false
303 } else {
304 return res
305 }
306 }
307 return ok
308 }
309
310 func (o *objectGoReflect) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
311 return o._setForeignStr(name, trueValIfPresent(o._has(name.String())), val, receiver, throw)
312 }
313
314 func (o *objectGoReflect) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
315 return o._setForeignIdx(idx, nil, val, receiver, throw)
316 }
317
318 func (o *objectGoReflect) _put(name string, val Value, throw bool) (has, ok bool) {
319 if o.fieldsValue.Kind() == reflect.Struct {
320 if v := o._getField(name); v.IsValid() {
321 cached := o.valueCache[name]
322 if cached != nil {
323 copyReflectValueWrapper(cached)
324 }
325
326 err := o.val.runtime.toReflectValue(val, v, &objectExportCtx{})
327 if err != nil {
328 if cached != nil {
329 cached.setReflectValue(v)
330 }
331 o.val.runtime.typeErrorResult(throw, "Go struct conversion error: %v", err)
332 return true, false
333 }
334 if cached != nil {
335 delete(o.valueCache, name)
336 }
337 return true, true
338 }
339 }
340 return false, false
341 }
342
343 func (o *objectGoReflect) _putProp(name unistring.String, value Value, writable, enumerable, configurable bool) Value {
344 if _, ok := o._put(name.String(), value, false); ok {
345 return value
346 }
347 return o.baseObject._putProp(name, value, writable, enumerable, configurable)
348 }
349
350 func (r *Runtime) checkHostObjectPropertyDescr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
351 if descr.Getter != nil || descr.Setter != nil {
352 r.typeErrorResult(throw, "Host objects do not support accessor properties")
353 return false
354 }
355 if descr.Writable == FLAG_FALSE {
356 r.typeErrorResult(throw, "Host object field %s cannot be made read-only", name)
357 return false
358 }
359 if descr.Configurable == FLAG_TRUE {
360 r.typeErrorResult(throw, "Host object field %s cannot be made configurable", name)
361 return false
362 }
363 return true
364 }
365
366 func (o *objectGoReflect) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
367 if o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) {
368 n := name.String()
369 if has, ok := o._put(n, descr.Value, throw); !has {
370 o.val.runtime.typeErrorResult(throw, "Cannot define property '%s' on a host object", n)
371 return false
372 } else {
373 return ok
374 }
375 }
376 return false
377 }
378
379 func (o *objectGoReflect) _has(name string) bool {
380 if o.fieldsValue.Kind() == reflect.Struct {
381 if v := o._getField(name); v.IsValid() {
382 return true
383 }
384 }
385 if v := o._getMethod(name); v.IsValid() {
386 return true
387 }
388 return false
389 }
390
391 func (o *objectGoReflect) hasOwnPropertyStr(name unistring.String) bool {
392 return o._has(name.String()) || o.baseObject.hasOwnPropertyStr(name)
393 }
394
395 func (o *objectGoReflect) _valueOfInt() Value {
396 return intToValue(o.fieldsValue.Int())
397 }
398
399 func (o *objectGoReflect) _valueOfUint() Value {
400 return intToValue(int64(o.fieldsValue.Uint()))
401 }
402
403 func (o *objectGoReflect) _valueOfBool() Value {
404 if o.fieldsValue.Bool() {
405 return valueTrue
406 } else {
407 return valueFalse
408 }
409 }
410
411 func (o *objectGoReflect) _valueOfFloat() Value {
412 return floatToValue(o.fieldsValue.Float())
413 }
414
415 func (o *objectGoReflect) _toStringStringer() Value {
416 return newStringValue(o.origValue.Interface().(fmt.Stringer).String())
417 }
418
419 func (o *objectGoReflect) _toStringString() Value {
420 return newStringValue(o.fieldsValue.String())
421 }
422
423 func (o *objectGoReflect) _toStringBool() Value {
424 if o.fieldsValue.Bool() {
425 return stringTrue
426 } else {
427 return stringFalse
428 }
429 }
430
431 func (o *objectGoReflect) _toStringError() Value {
432 return newStringValue(o.origValue.Interface().(error).Error())
433 }
434
435 func (o *objectGoReflect) deleteStr(name unistring.String, throw bool) bool {
436 n := name.String()
437 if o._has(n) {
438 o.val.runtime.typeErrorResult(throw, "Cannot delete property %s from a Go type", n)
439 return false
440 }
441 return o.baseObject.deleteStr(name, throw)
442 }
443
444 type goreflectPropIter struct {
445 o *objectGoReflect
446 idx int
447 }
448
449 func (i *goreflectPropIter) nextField() (propIterItem, iterNextFunc) {
450 names := i.o.fieldsInfo.Names
451 if i.idx < len(names) {
452 name := names[i.idx]
453 i.idx++
454 return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.nextField
455 }
456
457 i.idx = 0
458 return i.nextMethod()
459 }
460
461 func (i *goreflectPropIter) nextMethod() (propIterItem, iterNextFunc) {
462 names := i.o.methodsInfo.Names
463 if i.idx < len(names) {
464 name := names[i.idx]
465 i.idx++
466 return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.nextMethod
467 }
468
469 return propIterItem{}, nil
470 }
471
472 func (o *objectGoReflect) iterateStringKeys() iterNextFunc {
473 r := &goreflectPropIter{
474 o: o,
475 }
476 if o.fieldsInfo != nil {
477 return r.nextField
478 }
479
480 return r.nextMethod
481 }
482
483 func (o *objectGoReflect) stringKeys(_ bool, accum []Value) []Value {
484
485 if o.fieldsInfo != nil {
486 for _, name := range o.fieldsInfo.Names {
487 accum = append(accum, newStringValue(name))
488 }
489 }
490
491 for _, name := range o.methodsInfo.Names {
492 accum = append(accum, newStringValue(name))
493 }
494
495 return accum
496 }
497
498 func (o *objectGoReflect) export(*objectExportCtx) interface{} {
499 return o.origValue.Interface()
500 }
501
502 func (o *objectGoReflect) exportType() reflect.Type {
503 return o.origValue.Type()
504 }
505
506 func (o *objectGoReflect) equal(other objectImpl) bool {
507 if other, ok := other.(*objectGoReflect); ok {
508 k1, k2 := o.fieldsValue.Kind(), other.fieldsValue.Kind()
509 if k1 == k2 {
510 if isContainer(k1) {
511 return o.fieldsValue == other.fieldsValue
512 }
513 return o.fieldsValue.Interface() == other.fieldsValue.Interface()
514 }
515 }
516 return false
517 }
518
519 func (o *objectGoReflect) reflectValue() reflect.Value {
520 return o.fieldsValue
521 }
522
523 func (o *objectGoReflect) setReflectValue(v reflect.Value) {
524 o.fieldsValue = v
525 o.origValue = v
526 o.methodsValue = v.Addr()
527 }
528
529 func (o *objectGoReflect) esValue() Value {
530 return o.val
531 }
532
533 func (r *Runtime) buildFieldInfo(t reflect.Type, index []int, info *reflectFieldsInfo) {
534 n := t.NumField()
535 for i := 0; i < n; i++ {
536 field := t.Field(i)
537 name := field.Name
538 if !ast.IsExported(name) {
539 continue
540 }
541 if r.fieldNameMapper != nil {
542 name = r.fieldNameMapper.FieldName(t, field)
543 }
544
545 if name != "" {
546 if inf, exists := info.Fields[name]; !exists {
547 info.Names = append(info.Names, name)
548 } else {
549 if len(inf.Index) <= len(index) {
550 continue
551 }
552 }
553 }
554
555 if name != "" || field.Anonymous {
556 idx := make([]int, len(index)+1)
557 copy(idx, index)
558 idx[len(idx)-1] = i
559
560 if name != "" {
561 info.Fields[name] = reflectFieldInfo{
562 Index: idx,
563 Anonymous: field.Anonymous,
564 }
565 }
566 if field.Anonymous {
567 typ := field.Type
568 for typ.Kind() == reflect.Ptr {
569 typ = typ.Elem()
570 }
571 if typ.Kind() == reflect.Struct {
572 r.buildFieldInfo(typ, idx, info)
573 }
574 }
575 }
576 }
577 }
578
579 var emptyMethodsInfo = reflectMethodsInfo{}
580
581 func (r *Runtime) buildMethodsInfo(t reflect.Type) (info *reflectMethodsInfo) {
582 n := t.NumMethod()
583 if n == 0 {
584 return &emptyMethodsInfo
585 }
586 info = new(reflectMethodsInfo)
587 info.Methods = make(map[string]int, n)
588 info.Names = make([]string, 0, n)
589 for i := 0; i < n; i++ {
590 method := t.Method(i)
591 name := method.Name
592 if !ast.IsExported(name) {
593 continue
594 }
595 if r.fieldNameMapper != nil {
596 name = r.fieldNameMapper.MethodName(t, method)
597 if name == "" {
598 continue
599 }
600 }
601
602 if _, exists := info.Methods[name]; !exists {
603 info.Names = append(info.Names, name)
604 }
605
606 info.Methods[name] = i
607 }
608 return
609 }
610
611 func (r *Runtime) buildFieldsInfo(t reflect.Type) (info *reflectFieldsInfo) {
612 info = new(reflectFieldsInfo)
613 n := t.NumField()
614 info.Fields = make(map[string]reflectFieldInfo, n)
615 info.Names = make([]string, 0, n)
616 r.buildFieldInfo(t, nil, info)
617 return
618 }
619
620 func (r *Runtime) fieldsInfo(t reflect.Type) (info *reflectFieldsInfo) {
621 var exists bool
622 if info, exists = r.fieldsInfoCache[t]; !exists {
623 info = r.buildFieldsInfo(t)
624 if r.fieldsInfoCache == nil {
625 r.fieldsInfoCache = make(map[reflect.Type]*reflectFieldsInfo)
626 }
627 r.fieldsInfoCache[t] = info
628 }
629
630 return
631 }
632
633 func (r *Runtime) methodsInfo(t reflect.Type) (info *reflectMethodsInfo) {
634 var exists bool
635 if info, exists = r.methodsInfoCache[t]; !exists {
636 info = r.buildMethodsInfo(t)
637 if r.methodsInfoCache == nil {
638 r.methodsInfoCache = make(map[reflect.Type]*reflectMethodsInfo)
639 }
640 r.methodsInfoCache[t] = info
641 }
642
643 return
644 }
645
646
647
648
649
650 func (r *Runtime) SetFieldNameMapper(mapper FieldNameMapper) {
651 r.fieldNameMapper = mapper
652 r.fieldsInfoCache = nil
653 r.methodsInfoCache = nil
654 }
655
656
657
658
659
660 func TagFieldNameMapper(tagName string, uncapMethods bool) FieldNameMapper {
661 return tagFieldNameMapper{
662 tagName: tagName,
663 uncapMethods: uncapMethods,
664 }
665 }
666
667
668
669 func UncapFieldNameMapper() FieldNameMapper {
670 return uncapFieldNameMapper{}
671 }
672
View as plain text