builtin_symbol.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. package goja
  2. import "github.com/dop251/goja/unistring"
  3. var (
  4. SymHasInstance = newSymbol(asciiString("Symbol.hasInstance"))
  5. SymIsConcatSpreadable = newSymbol(asciiString("Symbol.isConcatSpreadable"))
  6. SymIterator = newSymbol(asciiString("Symbol.iterator"))
  7. SymMatch = newSymbol(asciiString("Symbol.match"))
  8. SymMatchAll = newSymbol(asciiString("Symbol.matchAll"))
  9. SymReplace = newSymbol(asciiString("Symbol.replace"))
  10. SymSearch = newSymbol(asciiString("Symbol.search"))
  11. SymSpecies = newSymbol(asciiString("Symbol.species"))
  12. SymSplit = newSymbol(asciiString("Symbol.split"))
  13. SymToPrimitive = newSymbol(asciiString("Symbol.toPrimitive"))
  14. SymToStringTag = newSymbol(asciiString("Symbol.toStringTag"))
  15. SymUnscopables = newSymbol(asciiString("Symbol.unscopables"))
  16. )
  17. func (r *Runtime) builtin_symbol(call FunctionCall) Value {
  18. var desc String
  19. if arg := call.Argument(0); !IsUndefined(arg) {
  20. desc = arg.toString()
  21. }
  22. return newSymbol(desc)
  23. }
  24. func (r *Runtime) symbolproto_tostring(call FunctionCall) Value {
  25. sym, ok := call.This.(*Symbol)
  26. if !ok {
  27. if obj, ok := call.This.(*Object); ok {
  28. if v, ok := obj.self.(*primitiveValueObject); ok {
  29. if sym1, ok := v.pValue.(*Symbol); ok {
  30. sym = sym1
  31. }
  32. }
  33. }
  34. }
  35. if sym == nil {
  36. panic(r.NewTypeError("Method Symbol.prototype.toString is called on incompatible receiver"))
  37. }
  38. return sym.descriptiveString()
  39. }
  40. func (r *Runtime) symbolproto_valueOf(call FunctionCall) Value {
  41. _, ok := call.This.(*Symbol)
  42. if ok {
  43. return call.This
  44. }
  45. if obj, ok := call.This.(*Object); ok {
  46. if v, ok := obj.self.(*primitiveValueObject); ok {
  47. if sym, ok := v.pValue.(*Symbol); ok {
  48. return sym
  49. }
  50. }
  51. }
  52. panic(r.NewTypeError("Symbol.prototype.valueOf requires that 'this' be a Symbol"))
  53. }
  54. func (r *Runtime) symbol_for(call FunctionCall) Value {
  55. key := call.Argument(0).toString()
  56. keyStr := key.string()
  57. if v := r.symbolRegistry[keyStr]; v != nil {
  58. return v
  59. }
  60. if r.symbolRegistry == nil {
  61. r.symbolRegistry = make(map[unistring.String]*Symbol)
  62. }
  63. v := newSymbol(key)
  64. r.symbolRegistry[keyStr] = v
  65. return v
  66. }
  67. func (r *Runtime) symbol_keyfor(call FunctionCall) Value {
  68. arg := call.Argument(0)
  69. sym, ok := arg.(*Symbol)
  70. if !ok {
  71. panic(r.NewTypeError("%s is not a symbol", arg.String()))
  72. }
  73. for key, s := range r.symbolRegistry {
  74. if s == sym {
  75. return stringValueFromRaw(key)
  76. }
  77. }
  78. return _undefined
  79. }
  80. func (r *Runtime) thisSymbolValue(v Value) *Symbol {
  81. if sym, ok := v.(*Symbol); ok {
  82. return sym
  83. }
  84. if obj, ok := v.(*Object); ok {
  85. if pVal, ok := obj.self.(*primitiveValueObject); ok {
  86. if sym, ok := pVal.pValue.(*Symbol); ok {
  87. return sym
  88. }
  89. }
  90. }
  91. panic(r.NewTypeError("Value is not a Symbol"))
  92. }
  93. func (r *Runtime) createSymbolProto(val *Object) objectImpl {
  94. o := &baseObject{
  95. class: classObject,
  96. val: val,
  97. extensible: true,
  98. prototype: r.global.ObjectPrototype,
  99. }
  100. o.init()
  101. o._putProp("constructor", r.getSymbol(), true, false, true)
  102. o.setOwnStr("description", &valueProperty{
  103. configurable: true,
  104. getterFunc: r.newNativeFunc(func(call FunctionCall) Value {
  105. return r.thisSymbolValue(call.This).desc
  106. }, "get description", 0),
  107. accessor: true,
  108. }, false)
  109. o._putProp("toString", r.newNativeFunc(r.symbolproto_tostring, "toString", 0), true, false, true)
  110. o._putProp("valueOf", r.newNativeFunc(r.symbolproto_valueOf, "valueOf", 0), true, false, true)
  111. o._putSym(SymToPrimitive, valueProp(r.newNativeFunc(r.symbolproto_valueOf, "[Symbol.toPrimitive]", 1), false, false, true))
  112. o._putSym(SymToStringTag, valueProp(newStringValue("Symbol"), false, false, true))
  113. return o
  114. }
  115. func (r *Runtime) createSymbol(val *Object) objectImpl {
  116. o := r.newNativeFuncAndConstruct(val, r.builtin_symbol, func(args []Value, newTarget *Object) *Object {
  117. panic(r.NewTypeError("Symbol is not a constructor"))
  118. }, r.getSymbolPrototype(), "Symbol", _positiveZero)
  119. o._putProp("for", r.newNativeFunc(r.symbol_for, "for", 1), true, false, true)
  120. o._putProp("keyFor", r.newNativeFunc(r.symbol_keyfor, "keyFor", 1), true, false, true)
  121. for _, s := range []*Symbol{
  122. SymHasInstance,
  123. SymIsConcatSpreadable,
  124. SymIterator,
  125. SymMatch,
  126. SymMatchAll,
  127. SymReplace,
  128. SymSearch,
  129. SymSpecies,
  130. SymSplit,
  131. SymToPrimitive,
  132. SymToStringTag,
  133. SymUnscopables,
  134. } {
  135. n := s.desc.(asciiString)
  136. n = n[len("Symbol."):]
  137. o._putProp(unistring.String(n), s, false, false, false)
  138. }
  139. return o
  140. }
  141. func (r *Runtime) getSymbolPrototype() *Object {
  142. ret := r.global.SymbolPrototype
  143. if ret == nil {
  144. ret = &Object{runtime: r}
  145. r.global.SymbolPrototype = ret
  146. ret.self = r.createSymbolProto(ret)
  147. }
  148. return ret
  149. }
  150. func (r *Runtime) getSymbol() *Object {
  151. ret := r.global.Symbol
  152. if ret == nil {
  153. ret = &Object{runtime: r}
  154. r.global.Symbol = ret
  155. ret.self = r.createSymbol(ret)
  156. }
  157. return ret
  158. }