object_goreflect.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  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 reflectTypeInfo struct {
  60. Fields map[string]reflectFieldInfo
  61. Methods map[string]int
  62. FieldNames, MethodNames []string
  63. }
  64. type objectGoReflect struct {
  65. baseObject
  66. origValue, value reflect.Value
  67. valueTypeInfo, origValueTypeInfo *reflectTypeInfo
  68. toJson func() interface{}
  69. }
  70. func (o *objectGoReflect) init() {
  71. o.baseObject.init()
  72. switch o.value.Kind() {
  73. case reflect.Bool:
  74. o.class = classBoolean
  75. o.prototype = o.val.runtime.global.BooleanPrototype
  76. case reflect.String:
  77. o.class = classString
  78. o.prototype = o.val.runtime.global.StringPrototype
  79. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
  80. reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
  81. reflect.Float32, reflect.Float64:
  82. o.class = classNumber
  83. o.prototype = o.val.runtime.global.NumberPrototype
  84. default:
  85. o.class = classObject
  86. o.prototype = o.val.runtime.global.ObjectPrototype
  87. }
  88. o.extensible = true
  89. o.baseObject._putProp("toString", o.val.runtime.newNativeFunc(o.toStringFunc, nil, "toString", nil, 0), true, false, true)
  90. o.baseObject._putProp("valueOf", o.val.runtime.newNativeFunc(o.valueOfFunc, nil, "valueOf", nil, 0), true, false, true)
  91. o.valueTypeInfo = o.val.runtime.typeInfo(o.value.Type())
  92. o.origValueTypeInfo = o.val.runtime.typeInfo(o.origValue.Type())
  93. if j, ok := o.origValue.Interface().(JsonEncodable); ok {
  94. o.toJson = j.JsonEncodable
  95. }
  96. }
  97. func (o *objectGoReflect) toStringFunc(FunctionCall) Value {
  98. return o.toPrimitiveString()
  99. }
  100. func (o *objectGoReflect) valueOfFunc(FunctionCall) Value {
  101. return o.toPrimitive()
  102. }
  103. func (o *objectGoReflect) getStr(name unistring.String, receiver Value) Value {
  104. if v := o._get(name.String()); v != nil {
  105. return v
  106. }
  107. return o.baseObject.getStr(name, receiver)
  108. }
  109. func (o *objectGoReflect) _getField(jsName string) reflect.Value {
  110. if info, exists := o.valueTypeInfo.Fields[jsName]; exists {
  111. v := o.value.FieldByIndex(info.Index)
  112. return v
  113. }
  114. return reflect.Value{}
  115. }
  116. func (o *objectGoReflect) _getMethod(jsName string) reflect.Value {
  117. if idx, exists := o.origValueTypeInfo.Methods[jsName]; exists {
  118. return o.origValue.Method(idx)
  119. }
  120. return reflect.Value{}
  121. }
  122. func (o *objectGoReflect) getAddr(v reflect.Value) reflect.Value {
  123. if (v.Kind() == reflect.Struct || v.Kind() == reflect.Slice) && v.CanAddr() {
  124. return v.Addr()
  125. }
  126. return v
  127. }
  128. func (o *objectGoReflect) _get(name string) Value {
  129. if o.value.Kind() == reflect.Struct {
  130. if v := o._getField(name); v.IsValid() {
  131. return o.val.runtime.ToValue(o.getAddr(v).Interface())
  132. }
  133. }
  134. if v := o._getMethod(name); v.IsValid() {
  135. return o.val.runtime.ToValue(v.Interface())
  136. }
  137. return nil
  138. }
  139. func (o *objectGoReflect) getOwnPropStr(name unistring.String) Value {
  140. n := name.String()
  141. if o.value.Kind() == reflect.Struct {
  142. if v := o._getField(n); v.IsValid() {
  143. return &valueProperty{
  144. value: o.val.runtime.ToValue(o.getAddr(v).Interface()),
  145. writable: v.CanSet(),
  146. enumerable: true,
  147. }
  148. }
  149. }
  150. if v := o._getMethod(n); v.IsValid() {
  151. return &valueProperty{
  152. value: o.val.runtime.ToValue(v.Interface()),
  153. enumerable: true,
  154. }
  155. }
  156. return nil
  157. }
  158. func (o *objectGoReflect) setOwnStr(name unistring.String, val Value, throw bool) bool {
  159. has, ok := o._put(name.String(), val, throw)
  160. if !has {
  161. if res, ok := o._setForeignStr(name, nil, val, o.val, throw); !ok {
  162. o.val.runtime.typeErrorResult(throw, "Cannot assign to property %s of a host object", name)
  163. return false
  164. } else {
  165. return res
  166. }
  167. }
  168. return ok
  169. }
  170. func (o *objectGoReflect) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
  171. return o._setForeignStr(name, trueValIfPresent(o._has(name.String())), val, receiver, throw)
  172. }
  173. func (o *objectGoReflect) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
  174. return o._setForeignIdx(idx, nil, val, receiver, throw)
  175. }
  176. func (o *objectGoReflect) _put(name string, val Value, throw bool) (has, ok bool) {
  177. if o.value.Kind() == reflect.Struct {
  178. if v := o._getField(name); v.IsValid() {
  179. if !v.CanSet() {
  180. o.val.runtime.typeErrorResult(throw, "Cannot assign to a non-addressable or read-only property %s of a host object", name)
  181. return true, false
  182. }
  183. err := o.val.runtime.toReflectValue(val, v, &objectExportCtx{})
  184. if err != nil {
  185. o.val.runtime.typeErrorResult(throw, "Go struct conversion error: %v", err)
  186. return true, false
  187. }
  188. return true, true
  189. }
  190. }
  191. return false, false
  192. }
  193. func (o *objectGoReflect) _putProp(name unistring.String, value Value, writable, enumerable, configurable bool) Value {
  194. if _, ok := o._put(name.String(), value, false); ok {
  195. return value
  196. }
  197. return o.baseObject._putProp(name, value, writable, enumerable, configurable)
  198. }
  199. func (r *Runtime) checkHostObjectPropertyDescr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
  200. if descr.Getter != nil || descr.Setter != nil {
  201. r.typeErrorResult(throw, "Host objects do not support accessor properties")
  202. return false
  203. }
  204. if descr.Writable == FLAG_FALSE {
  205. r.typeErrorResult(throw, "Host object field %s cannot be made read-only", name)
  206. return false
  207. }
  208. if descr.Configurable == FLAG_TRUE {
  209. r.typeErrorResult(throw, "Host object field %s cannot be made configurable", name)
  210. return false
  211. }
  212. return true
  213. }
  214. func (o *objectGoReflect) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
  215. if o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) {
  216. n := name.String()
  217. if has, ok := o._put(n, descr.Value, throw); !has {
  218. o.val.runtime.typeErrorResult(throw, "Cannot define property '%s' on a host object", n)
  219. return false
  220. } else {
  221. return ok
  222. }
  223. }
  224. return false
  225. }
  226. func (o *objectGoReflect) _has(name string) bool {
  227. if o.value.Kind() == reflect.Struct {
  228. if v := o._getField(name); v.IsValid() {
  229. return true
  230. }
  231. }
  232. if v := o._getMethod(name); v.IsValid() {
  233. return true
  234. }
  235. return false
  236. }
  237. func (o *objectGoReflect) hasOwnPropertyStr(name unistring.String) bool {
  238. return o._has(name.String())
  239. }
  240. func (o *objectGoReflect) _toNumber() Value {
  241. switch o.value.Kind() {
  242. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  243. return intToValue(o.value.Int())
  244. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  245. return intToValue(int64(o.value.Uint()))
  246. case reflect.Bool:
  247. if o.value.Bool() {
  248. return intToValue(1)
  249. } else {
  250. return intToValue(0)
  251. }
  252. case reflect.Float32, reflect.Float64:
  253. return floatToValue(o.value.Float())
  254. }
  255. return nil
  256. }
  257. func (o *objectGoReflect) _toString() Value {
  258. switch o.value.Kind() {
  259. case reflect.String:
  260. return newStringValue(o.value.String())
  261. case reflect.Bool:
  262. if o.value.Interface().(bool) {
  263. return stringTrue
  264. } else {
  265. return stringFalse
  266. }
  267. }
  268. switch v := o.origValue.Interface().(type) {
  269. case fmt.Stringer:
  270. return newStringValue(v.String())
  271. case error:
  272. return newStringValue(v.Error())
  273. }
  274. return stringObjectObject
  275. }
  276. func (o *objectGoReflect) toPrimitiveNumber() Value {
  277. if v := o._toNumber(); v != nil {
  278. return v
  279. }
  280. return o._toString()
  281. }
  282. func (o *objectGoReflect) toPrimitiveString() Value {
  283. if v := o._toNumber(); v != nil {
  284. return v.toString()
  285. }
  286. return o._toString()
  287. }
  288. func (o *objectGoReflect) toPrimitive() Value {
  289. if o.prototype == o.val.runtime.global.NumberPrototype {
  290. return o.toPrimitiveNumber()
  291. }
  292. return o.toPrimitiveString()
  293. }
  294. func (o *objectGoReflect) deleteStr(name unistring.String, throw bool) bool {
  295. n := name.String()
  296. if o._has(n) {
  297. o.val.runtime.typeErrorResult(throw, "Cannot delete property %s from a Go type", n)
  298. return false
  299. }
  300. return o.baseObject.deleteStr(name, throw)
  301. }
  302. type goreflectPropIter struct {
  303. o *objectGoReflect
  304. idx int
  305. }
  306. func (i *goreflectPropIter) nextField() (propIterItem, iterNextFunc) {
  307. names := i.o.valueTypeInfo.FieldNames
  308. if i.idx < len(names) {
  309. name := names[i.idx]
  310. i.idx++
  311. return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.nextField
  312. }
  313. i.idx = 0
  314. return i.nextMethod()
  315. }
  316. func (i *goreflectPropIter) nextMethod() (propIterItem, iterNextFunc) {
  317. names := i.o.origValueTypeInfo.MethodNames
  318. if i.idx < len(names) {
  319. name := names[i.idx]
  320. i.idx++
  321. return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.nextMethod
  322. }
  323. return propIterItem{}, nil
  324. }
  325. func (o *objectGoReflect) iterateStringKeys() iterNextFunc {
  326. r := &goreflectPropIter{
  327. o: o,
  328. }
  329. if o.value.Kind() == reflect.Struct {
  330. return r.nextField
  331. }
  332. return r.nextMethod
  333. }
  334. func (o *objectGoReflect) stringKeys(_ bool, accum []Value) []Value {
  335. // all own keys are enumerable
  336. for _, name := range o.valueTypeInfo.FieldNames {
  337. accum = append(accum, newStringValue(name))
  338. }
  339. for _, name := range o.valueTypeInfo.MethodNames {
  340. accum = append(accum, newStringValue(name))
  341. }
  342. return accum
  343. }
  344. func (o *objectGoReflect) export(*objectExportCtx) interface{} {
  345. return o.origValue.Interface()
  346. }
  347. func (o *objectGoReflect) exportType() reflect.Type {
  348. return o.origValue.Type()
  349. }
  350. func (o *objectGoReflect) equal(other objectImpl) bool {
  351. if other, ok := other.(*objectGoReflect); ok {
  352. return o.value.Interface() == other.value.Interface()
  353. }
  354. return false
  355. }
  356. func (r *Runtime) buildFieldInfo(t reflect.Type, index []int, info *reflectTypeInfo) {
  357. n := t.NumField()
  358. for i := 0; i < n; i++ {
  359. field := t.Field(i)
  360. name := field.Name
  361. if !ast.IsExported(name) {
  362. continue
  363. }
  364. if r.fieldNameMapper != nil {
  365. name = r.fieldNameMapper.FieldName(t, field)
  366. }
  367. if name != "" {
  368. if inf, exists := info.Fields[name]; !exists {
  369. info.FieldNames = append(info.FieldNames, name)
  370. } else {
  371. if len(inf.Index) <= len(index) {
  372. continue
  373. }
  374. }
  375. }
  376. if name != "" || field.Anonymous {
  377. idx := make([]int, len(index)+1)
  378. copy(idx, index)
  379. idx[len(idx)-1] = i
  380. if name != "" {
  381. info.Fields[name] = reflectFieldInfo{
  382. Index: idx,
  383. Anonymous: field.Anonymous,
  384. }
  385. }
  386. if field.Anonymous {
  387. typ := field.Type
  388. for typ.Kind() == reflect.Ptr {
  389. typ = typ.Elem()
  390. }
  391. if typ.Kind() == reflect.Struct {
  392. r.buildFieldInfo(typ, idx, info)
  393. }
  394. }
  395. }
  396. }
  397. }
  398. func (r *Runtime) buildTypeInfo(t reflect.Type) (info *reflectTypeInfo) {
  399. info = new(reflectTypeInfo)
  400. if t.Kind() == reflect.Struct {
  401. info.Fields = make(map[string]reflectFieldInfo)
  402. n := t.NumField()
  403. info.FieldNames = make([]string, 0, n)
  404. r.buildFieldInfo(t, nil, info)
  405. }
  406. info.Methods = make(map[string]int)
  407. n := t.NumMethod()
  408. info.MethodNames = make([]string, 0, n)
  409. for i := 0; i < n; i++ {
  410. method := t.Method(i)
  411. name := method.Name
  412. if !ast.IsExported(name) {
  413. continue
  414. }
  415. if r.fieldNameMapper != nil {
  416. name = r.fieldNameMapper.MethodName(t, method)
  417. if name == "" {
  418. continue
  419. }
  420. }
  421. if _, exists := info.Methods[name]; !exists {
  422. info.MethodNames = append(info.MethodNames, name)
  423. }
  424. info.Methods[name] = i
  425. }
  426. return
  427. }
  428. func (r *Runtime) typeInfo(t reflect.Type) (info *reflectTypeInfo) {
  429. var exists bool
  430. if info, exists = r.typeInfoCache[t]; !exists {
  431. info = r.buildTypeInfo(t)
  432. if r.typeInfoCache == nil {
  433. r.typeInfoCache = make(map[reflect.Type]*reflectTypeInfo)
  434. }
  435. r.typeInfoCache[t] = info
  436. }
  437. return
  438. }
  439. // SetFieldNameMapper sets a custom field name mapper for Go types. It can be called at any time, however
  440. // the mapping for any given value is fixed at the point of creation.
  441. // Setting this to nil restores the default behaviour which is all exported fields and methods are mapped to their
  442. // original unchanged names.
  443. func (r *Runtime) SetFieldNameMapper(mapper FieldNameMapper) {
  444. r.fieldNameMapper = mapper
  445. r.typeInfoCache = nil
  446. }
  447. // TagFieldNameMapper returns a FieldNameMapper that uses the given tagName for struct fields and optionally
  448. // uncapitalises (making the first letter lower case) method names.
  449. // The common tag value syntax is supported (name[,options]), however options are ignored.
  450. // Setting name to anything other than a valid ECMAScript identifier makes the field hidden.
  451. func TagFieldNameMapper(tagName string, uncapMethods bool) FieldNameMapper {
  452. return tagFieldNameMapper{
  453. tagName: tagName,
  454. uncapMethods: uncapMethods,
  455. }
  456. }
  457. // UncapFieldNameMapper returns a FieldNameMapper that uncapitalises struct field and method names
  458. // making the first letter lower case.
  459. func UncapFieldNameMapper() FieldNameMapper {
  460. return uncapFieldNameMapper{}
  461. }