object_gomap.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. package goja
  2. import (
  3. "reflect"
  4. "github.com/dop251/goja/unistring"
  5. )
  6. type objectGoMapSimple struct {
  7. baseObject
  8. data map[string]interface{}
  9. }
  10. func (o *objectGoMapSimple) init() {
  11. o.baseObject.init()
  12. o.prototype = o.val.runtime.global.ObjectPrototype
  13. o.class = classObject
  14. o.extensible = true
  15. }
  16. func (o *objectGoMapSimple) _getStr(name string) Value {
  17. v, exists := o.data[name]
  18. if !exists {
  19. return nil
  20. }
  21. return o.val.runtime.ToValue(v)
  22. }
  23. func (o *objectGoMapSimple) getStr(name unistring.String, receiver Value) Value {
  24. if v := o._getStr(name.String()); v != nil {
  25. return v
  26. }
  27. return o.baseObject.getStr(name, receiver)
  28. }
  29. func (o *objectGoMapSimple) getOwnPropStr(name unistring.String) Value {
  30. if v := o._getStr(name.String()); v != nil {
  31. return v
  32. }
  33. return nil
  34. }
  35. func (o *objectGoMapSimple) setOwnStr(name unistring.String, val Value, throw bool) bool {
  36. n := name.String()
  37. if _, exists := o.data[n]; exists {
  38. o.data[n] = val.Export()
  39. return true
  40. }
  41. if proto := o.prototype; proto != nil {
  42. // we know it's foreign because prototype loops are not allowed
  43. if res, ok := proto.self.setForeignStr(name, val, o.val, throw); ok {
  44. return res
  45. }
  46. }
  47. // new property
  48. if !o.extensible {
  49. o.val.runtime.typeErrorResult(throw, "Cannot add property %s, object is not extensible", name)
  50. return false
  51. } else {
  52. o.data[n] = val.Export()
  53. }
  54. return true
  55. }
  56. func trueValIfPresent(present bool) Value {
  57. if present {
  58. return valueTrue
  59. }
  60. return nil
  61. }
  62. func (o *objectGoMapSimple) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
  63. return o._setForeignStr(name, trueValIfPresent(o._hasStr(name.String())), val, receiver, throw)
  64. }
  65. func (o *objectGoMapSimple) _hasStr(name string) bool {
  66. _, exists := o.data[name]
  67. return exists
  68. }
  69. func (o *objectGoMapSimple) hasOwnPropertyStr(name unistring.String) bool {
  70. return o._hasStr(name.String())
  71. }
  72. func (o *objectGoMapSimple) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
  73. if !o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) {
  74. return false
  75. }
  76. n := name.String()
  77. if o.extensible || o._hasStr(n) {
  78. o.data[n] = descr.Value.Export()
  79. return true
  80. }
  81. o.val.runtime.typeErrorResult(throw, "Cannot define property %s, object is not extensible", n)
  82. return false
  83. }
  84. func (o *objectGoMapSimple) deleteStr(name unistring.String, _ bool) bool {
  85. delete(o.data, name.String())
  86. return true
  87. }
  88. type gomapPropIter struct {
  89. o *objectGoMapSimple
  90. propNames []string
  91. idx int
  92. }
  93. func (i *gomapPropIter) next() (propIterItem, iterNextFunc) {
  94. for i.idx < len(i.propNames) {
  95. name := i.propNames[i.idx]
  96. i.idx++
  97. if _, exists := i.o.data[name]; exists {
  98. return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.next
  99. }
  100. }
  101. return propIterItem{}, nil
  102. }
  103. func (o *objectGoMapSimple) iterateStringKeys() iterNextFunc {
  104. propNames := make([]string, len(o.data))
  105. i := 0
  106. for key := range o.data {
  107. propNames[i] = key
  108. i++
  109. }
  110. return (&gomapPropIter{
  111. o: o,
  112. propNames: propNames,
  113. }).next
  114. }
  115. func (o *objectGoMapSimple) stringKeys(_ bool, accum []Value) []Value {
  116. // all own keys are enumerable
  117. for key := range o.data {
  118. accum = append(accum, newStringValue(key))
  119. }
  120. return accum
  121. }
  122. func (o *objectGoMapSimple) export(*objectExportCtx) interface{} {
  123. return o.data
  124. }
  125. func (o *objectGoMapSimple) exportType() reflect.Type {
  126. return reflectTypeMap
  127. }
  128. func (o *objectGoMapSimple) equal(other objectImpl) bool {
  129. if other, ok := other.(*objectGoMapSimple); ok {
  130. return o == other
  131. }
  132. return false
  133. }