object_goreflect.go 17 KB

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