string.go 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. package goja
  2. import (
  3. "io"
  4. "strconv"
  5. "strings"
  6. "unicode/utf8"
  7. "github.com/dop251/goja/unistring"
  8. )
  9. const (
  10. __proto__ = "__proto__"
  11. )
  12. var (
  13. stringTrue String = asciiString("true")
  14. stringFalse String = asciiString("false")
  15. stringNull String = asciiString("null")
  16. stringUndefined String = asciiString("undefined")
  17. stringObjectC String = asciiString("object")
  18. stringFunction String = asciiString("function")
  19. stringBoolean String = asciiString("boolean")
  20. stringString String = asciiString("string")
  21. stringSymbol String = asciiString("symbol")
  22. stringNumber String = asciiString("number")
  23. stringBigInt String = asciiString("bigint")
  24. stringNaN String = asciiString("NaN")
  25. stringInfinity = asciiString("Infinity")
  26. stringNegInfinity = asciiString("-Infinity")
  27. stringBound_ String = asciiString("bound ")
  28. stringEmpty String = asciiString("")
  29. stringError String = asciiString("Error")
  30. stringAggregateError String = asciiString("AggregateError")
  31. stringTypeError String = asciiString("TypeError")
  32. stringReferenceError String = asciiString("ReferenceError")
  33. stringSyntaxError String = asciiString("SyntaxError")
  34. stringRangeError String = asciiString("RangeError")
  35. stringEvalError String = asciiString("EvalError")
  36. stringURIError String = asciiString("URIError")
  37. stringGoError String = asciiString("GoError")
  38. stringObjectNull String = asciiString("[object Null]")
  39. stringObjectUndefined String = asciiString("[object Undefined]")
  40. stringInvalidDate String = asciiString("Invalid Date")
  41. )
  42. type utf16Reader interface {
  43. readChar() (c uint16, err error)
  44. }
  45. // String represents an ECMAScript string Value. Its internal representation depends on the contents of the
  46. // string, but in any case it is capable of holding any UTF-16 string, either valid or invalid.
  47. // Instances of this type, as any other primitive values, are goroutine-safe and can be passed between runtimes.
  48. // Strings can be created using Runtime.ToValue(goString) or StringFromUTF16.
  49. type String interface {
  50. Value
  51. CharAt(int) uint16
  52. Length() int
  53. Concat(String) String
  54. Substring(start, end int) String
  55. CompareTo(String) int
  56. Reader() io.RuneReader
  57. utf16Reader() utf16Reader
  58. utf16RuneReader() io.RuneReader
  59. utf16Runes() []rune
  60. index(String, int) int
  61. lastIndex(String, int) int
  62. toLower() String
  63. toUpper() String
  64. toTrimmedUTF8() string
  65. }
  66. type stringIterObject struct {
  67. baseObject
  68. reader io.RuneReader
  69. }
  70. func isUTF16FirstSurrogate(c uint16) bool {
  71. return c >= 0xD800 && c <= 0xDBFF
  72. }
  73. func isUTF16SecondSurrogate(c uint16) bool {
  74. return c >= 0xDC00 && c <= 0xDFFF
  75. }
  76. func (si *stringIterObject) next() Value {
  77. if si.reader == nil {
  78. return si.val.runtime.createIterResultObject(_undefined, true)
  79. }
  80. r, _, err := si.reader.ReadRune()
  81. if err == io.EOF {
  82. si.reader = nil
  83. return si.val.runtime.createIterResultObject(_undefined, true)
  84. }
  85. return si.val.runtime.createIterResultObject(stringFromRune(r), false)
  86. }
  87. func stringFromRune(r rune) String {
  88. if r < utf8.RuneSelf {
  89. var sb strings.Builder
  90. sb.WriteByte(byte(r))
  91. return asciiString(sb.String())
  92. }
  93. var sb unicodeStringBuilder
  94. sb.WriteRune(r)
  95. return sb.String()
  96. }
  97. func (r *Runtime) createStringIterator(s String) Value {
  98. o := &Object{runtime: r}
  99. si := &stringIterObject{
  100. reader: &lenientUtf16Decoder{utf16Reader: s.utf16Reader()},
  101. }
  102. si.class = classObject
  103. si.val = o
  104. si.extensible = true
  105. o.self = si
  106. si.prototype = r.getStringIteratorPrototype()
  107. si.init()
  108. return o
  109. }
  110. type stringObject struct {
  111. baseObject
  112. value String
  113. length int
  114. lengthProp valueProperty
  115. }
  116. func newStringValue(s string) String {
  117. if u := unistring.Scan(s); u != nil {
  118. return unicodeString(u)
  119. }
  120. return asciiString(s)
  121. }
  122. func stringValueFromRaw(raw unistring.String) String {
  123. if b := raw.AsUtf16(); b != nil {
  124. return unicodeString(b)
  125. }
  126. return asciiString(raw)
  127. }
  128. func (s *stringObject) init() {
  129. s.baseObject.init()
  130. s.setLength()
  131. }
  132. func (s *stringObject) setLength() {
  133. if s.value != nil {
  134. s.length = s.value.Length()
  135. }
  136. s.lengthProp.value = intToValue(int64(s.length))
  137. s._put("length", &s.lengthProp)
  138. }
  139. func (s *stringObject) getStr(name unistring.String, receiver Value) Value {
  140. if i := strToGoIdx(name); i >= 0 && i < s.length {
  141. return s._getIdx(i)
  142. }
  143. return s.baseObject.getStr(name, receiver)
  144. }
  145. func (s *stringObject) getIdx(idx valueInt, receiver Value) Value {
  146. i := int(idx)
  147. if i >= 0 && i < s.length {
  148. return s._getIdx(i)
  149. }
  150. return s.baseObject.getStr(idx.string(), receiver)
  151. }
  152. func (s *stringObject) getOwnPropStr(name unistring.String) Value {
  153. if i := strToGoIdx(name); i >= 0 && i < s.length {
  154. val := s._getIdx(i)
  155. return &valueProperty{
  156. value: val,
  157. enumerable: true,
  158. }
  159. }
  160. return s.baseObject.getOwnPropStr(name)
  161. }
  162. func (s *stringObject) getOwnPropIdx(idx valueInt) Value {
  163. i := int64(idx)
  164. if i >= 0 {
  165. if i < int64(s.length) {
  166. val := s._getIdx(int(i))
  167. return &valueProperty{
  168. value: val,
  169. enumerable: true,
  170. }
  171. }
  172. return nil
  173. }
  174. return s.baseObject.getOwnPropStr(idx.string())
  175. }
  176. func (s *stringObject) _getIdx(idx int) Value {
  177. return s.value.Substring(idx, idx+1)
  178. }
  179. func (s *stringObject) setOwnStr(name unistring.String, val Value, throw bool) bool {
  180. if i := strToGoIdx(name); i >= 0 && i < s.length {
  181. s.val.runtime.typeErrorResult(throw, "Cannot assign to read only property '%d' of a String", i)
  182. return false
  183. }
  184. return s.baseObject.setOwnStr(name, val, throw)
  185. }
  186. func (s *stringObject) setOwnIdx(idx valueInt, val Value, throw bool) bool {
  187. i := int64(idx)
  188. if i >= 0 && i < int64(s.length) {
  189. s.val.runtime.typeErrorResult(throw, "Cannot assign to read only property '%d' of a String", i)
  190. return false
  191. }
  192. return s.baseObject.setOwnStr(idx.string(), val, throw)
  193. }
  194. func (s *stringObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
  195. return s._setForeignStr(name, s.getOwnPropStr(name), val, receiver, throw)
  196. }
  197. func (s *stringObject) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
  198. return s._setForeignIdx(idx, s.getOwnPropIdx(idx), val, receiver, throw)
  199. }
  200. func (s *stringObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
  201. if i := strToGoIdx(name); i >= 0 && i < s.length {
  202. _, ok := s._defineOwnProperty(name, &valueProperty{enumerable: true}, descr, throw)
  203. return ok
  204. }
  205. return s.baseObject.defineOwnPropertyStr(name, descr, throw)
  206. }
  207. func (s *stringObject) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
  208. i := int64(idx)
  209. if i >= 0 && i < int64(s.length) {
  210. s.val.runtime.typeErrorResult(throw, "Cannot redefine property: %d", i)
  211. return false
  212. }
  213. return s.baseObject.defineOwnPropertyStr(idx.string(), descr, throw)
  214. }
  215. type stringPropIter struct {
  216. str String // separate, because obj can be the singleton
  217. obj *stringObject
  218. idx, length int
  219. }
  220. func (i *stringPropIter) next() (propIterItem, iterNextFunc) {
  221. if i.idx < i.length {
  222. name := strconv.Itoa(i.idx)
  223. i.idx++
  224. return propIterItem{name: asciiString(name), enumerable: _ENUM_TRUE}, i.next
  225. }
  226. return i.obj.baseObject.iterateStringKeys()()
  227. }
  228. func (s *stringObject) iterateStringKeys() iterNextFunc {
  229. return (&stringPropIter{
  230. str: s.value,
  231. obj: s,
  232. length: s.length,
  233. }).next
  234. }
  235. func (s *stringObject) stringKeys(all bool, accum []Value) []Value {
  236. for i := 0; i < s.length; i++ {
  237. accum = append(accum, asciiString(strconv.Itoa(i)))
  238. }
  239. return s.baseObject.stringKeys(all, accum)
  240. }
  241. func (s *stringObject) deleteStr(name unistring.String, throw bool) bool {
  242. if i := strToGoIdx(name); i >= 0 && i < s.length {
  243. s.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of a String", i)
  244. return false
  245. }
  246. return s.baseObject.deleteStr(name, throw)
  247. }
  248. func (s *stringObject) deleteIdx(idx valueInt, throw bool) bool {
  249. i := int64(idx)
  250. if i >= 0 && i < int64(s.length) {
  251. s.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of a String", i)
  252. return false
  253. }
  254. return s.baseObject.deleteStr(idx.string(), throw)
  255. }
  256. func (s *stringObject) hasOwnPropertyStr(name unistring.String) bool {
  257. if i := strToGoIdx(name); i >= 0 && i < s.length {
  258. return true
  259. }
  260. return s.baseObject.hasOwnPropertyStr(name)
  261. }
  262. func (s *stringObject) hasOwnPropertyIdx(idx valueInt) bool {
  263. i := int64(idx)
  264. if i >= 0 && i < int64(s.length) {
  265. return true
  266. }
  267. return s.baseObject.hasOwnPropertyStr(idx.string())
  268. }
  269. func devirtualizeString(s String) (asciiString, unicodeString) {
  270. switch s := s.(type) {
  271. case asciiString:
  272. return s, nil
  273. case unicodeString:
  274. return "", s
  275. case *importedString:
  276. s.ensureScanned()
  277. if s.u != nil {
  278. return "", s.u
  279. }
  280. return asciiString(s.s), nil
  281. default:
  282. panic(unknownStringTypeErr(s))
  283. }
  284. }
  285. func unknownStringTypeErr(v Value) interface{} {
  286. return newTypeError("Internal bug: unknown string type: %T", v)
  287. }
  288. // StringFromUTF16 creates a string value from an array of UTF-16 code units. The result is a copy, so the initial
  289. // slice can be modified after calling this function (but it must not be modified while the function is running).
  290. // No validation of any kind is performed.
  291. func StringFromUTF16(chars []uint16) String {
  292. isAscii := true
  293. for _, c := range chars {
  294. if c >= utf8.RuneSelf {
  295. isAscii = false
  296. break
  297. }
  298. }
  299. if isAscii {
  300. var sb strings.Builder
  301. sb.Grow(len(chars))
  302. for _, c := range chars {
  303. sb.WriteByte(byte(c))
  304. }
  305. return asciiString(sb.String())
  306. }
  307. buf := make([]uint16, len(chars)+1)
  308. buf[0] = unistring.BOM
  309. copy(buf[1:], chars)
  310. return unicodeString(buf)
  311. }