object_gomap_reflect.go 7.2 KB

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