builtin_string.go 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051
  1. package goja
  2. import (
  3. "github.com/dop251/goja/unistring"
  4. "math"
  5. "strings"
  6. "unicode/utf16"
  7. "unicode/utf8"
  8. "github.com/dop251/goja/parser"
  9. "golang.org/x/text/collate"
  10. "golang.org/x/text/language"
  11. "golang.org/x/text/unicode/norm"
  12. )
  13. func (r *Runtime) collator() *collate.Collator {
  14. collator := r._collator
  15. if collator == nil {
  16. collator = collate.New(language.Und)
  17. r._collator = collator
  18. }
  19. return collator
  20. }
  21. func toString(arg Value) String {
  22. if s, ok := arg.(String); ok {
  23. return s
  24. }
  25. if s, ok := arg.(*Symbol); ok {
  26. return s.descriptiveString()
  27. }
  28. return arg.toString()
  29. }
  30. func (r *Runtime) builtin_String(call FunctionCall) Value {
  31. if len(call.Arguments) > 0 {
  32. return toString(call.Arguments[0])
  33. } else {
  34. return stringEmpty
  35. }
  36. }
  37. func (r *Runtime) _newString(s String, proto *Object) *Object {
  38. v := &Object{runtime: r}
  39. o := &stringObject{}
  40. o.class = classString
  41. o.val = v
  42. o.extensible = true
  43. v.self = o
  44. o.prototype = proto
  45. if s != nil {
  46. o.value = s
  47. }
  48. o.init()
  49. return v
  50. }
  51. func (r *Runtime) builtin_newString(args []Value, proto *Object) *Object {
  52. var s String
  53. if len(args) > 0 {
  54. s = args[0].toString()
  55. } else {
  56. s = stringEmpty
  57. }
  58. return r._newString(s, proto)
  59. }
  60. func (r *Runtime) stringproto_toStringValueOf(this Value, funcName string) Value {
  61. if str, ok := this.(String); ok {
  62. return str
  63. }
  64. if obj, ok := this.(*Object); ok {
  65. if strObj, ok := obj.self.(*stringObject); ok {
  66. return strObj.value
  67. }
  68. if reflectObj, ok := obj.self.(*objectGoReflect); ok && reflectObj.class == classString {
  69. if toString := reflectObj.toString; toString != nil {
  70. return toString()
  71. }
  72. if valueOf := reflectObj.valueOf; valueOf != nil {
  73. return valueOf()
  74. }
  75. }
  76. }
  77. r.typeErrorResult(true, "String.prototype.%s is called on incompatible receiver", funcName)
  78. return nil
  79. }
  80. func (r *Runtime) stringproto_toString(call FunctionCall) Value {
  81. return r.stringproto_toStringValueOf(call.This, "toString")
  82. }
  83. func (r *Runtime) stringproto_valueOf(call FunctionCall) Value {
  84. return r.stringproto_toStringValueOf(call.This, "valueOf")
  85. }
  86. func (r *Runtime) stringproto_iterator(call FunctionCall) Value {
  87. r.checkObjectCoercible(call.This)
  88. return r.createStringIterator(call.This.toString())
  89. }
  90. func (r *Runtime) string_fromcharcode(call FunctionCall) Value {
  91. b := make([]byte, len(call.Arguments))
  92. for i, arg := range call.Arguments {
  93. chr := toUint16(arg)
  94. if chr >= utf8.RuneSelf {
  95. bb := make([]uint16, len(call.Arguments)+1)
  96. bb[0] = unistring.BOM
  97. bb1 := bb[1:]
  98. for j := 0; j < i; j++ {
  99. bb1[j] = uint16(b[j])
  100. }
  101. bb1[i] = chr
  102. i++
  103. for j, arg := range call.Arguments[i:] {
  104. bb1[i+j] = toUint16(arg)
  105. }
  106. return unicodeString(bb)
  107. }
  108. b[i] = byte(chr)
  109. }
  110. return asciiString(b)
  111. }
  112. func (r *Runtime) string_fromcodepoint(call FunctionCall) Value {
  113. var sb StringBuilder
  114. for _, arg := range call.Arguments {
  115. num := arg.ToNumber()
  116. var c rune
  117. if numInt, ok := num.(valueInt); ok {
  118. if numInt < 0 || numInt > utf8.MaxRune {
  119. panic(r.newError(r.global.RangeError, "Invalid code point %d", numInt))
  120. }
  121. c = rune(numInt)
  122. } else {
  123. panic(r.newError(r.global.RangeError, "Invalid code point %s", num))
  124. }
  125. sb.WriteRune(c)
  126. }
  127. return sb.String()
  128. }
  129. func (r *Runtime) string_raw(call FunctionCall) Value {
  130. cooked := call.Argument(0).ToObject(r)
  131. raw := nilSafe(cooked.self.getStr("raw", nil)).ToObject(r)
  132. literalSegments := toLength(raw.self.getStr("length", nil))
  133. if literalSegments <= 0 {
  134. return stringEmpty
  135. }
  136. var stringElements StringBuilder
  137. nextIndex := int64(0)
  138. numberOfSubstitutions := int64(len(call.Arguments) - 1)
  139. for {
  140. nextSeg := nilSafe(raw.self.getIdx(valueInt(nextIndex), nil)).toString()
  141. stringElements.WriteString(nextSeg)
  142. if nextIndex+1 == literalSegments {
  143. return stringElements.String()
  144. }
  145. if nextIndex < numberOfSubstitutions {
  146. stringElements.WriteString(nilSafe(call.Arguments[nextIndex+1]).toString())
  147. }
  148. nextIndex++
  149. }
  150. }
  151. func (r *Runtime) stringproto_at(call FunctionCall) Value {
  152. r.checkObjectCoercible(call.This)
  153. s := call.This.toString()
  154. pos := call.Argument(0).ToInteger()
  155. length := int64(s.Length())
  156. if pos < 0 {
  157. pos = length + pos
  158. }
  159. if pos >= length || pos < 0 {
  160. return _undefined
  161. }
  162. return s.Substring(int(pos), int(pos+1))
  163. }
  164. func (r *Runtime) stringproto_charAt(call FunctionCall) Value {
  165. r.checkObjectCoercible(call.This)
  166. s := call.This.toString()
  167. pos := call.Argument(0).ToInteger()
  168. if pos < 0 || pos >= int64(s.Length()) {
  169. return stringEmpty
  170. }
  171. return s.Substring(int(pos), int(pos+1))
  172. }
  173. func (r *Runtime) stringproto_charCodeAt(call FunctionCall) Value {
  174. r.checkObjectCoercible(call.This)
  175. s := call.This.toString()
  176. pos := call.Argument(0).ToInteger()
  177. if pos < 0 || pos >= int64(s.Length()) {
  178. return _NaN
  179. }
  180. return intToValue(int64(s.CharAt(toIntStrict(pos)) & 0xFFFF))
  181. }
  182. func (r *Runtime) stringproto_codePointAt(call FunctionCall) Value {
  183. r.checkObjectCoercible(call.This)
  184. s := call.This.toString()
  185. p := call.Argument(0).ToInteger()
  186. size := s.Length()
  187. if p < 0 || p >= int64(size) {
  188. return _undefined
  189. }
  190. pos := toIntStrict(p)
  191. first := s.CharAt(pos)
  192. if isUTF16FirstSurrogate(first) {
  193. pos++
  194. if pos < size {
  195. second := s.CharAt(pos)
  196. if isUTF16SecondSurrogate(second) {
  197. return intToValue(int64(utf16.DecodeRune(rune(first), rune(second))))
  198. }
  199. }
  200. }
  201. return intToValue(int64(first & 0xFFFF))
  202. }
  203. func (r *Runtime) stringproto_concat(call FunctionCall) Value {
  204. r.checkObjectCoercible(call.This)
  205. strs := make([]String, len(call.Arguments)+1)
  206. a, u := devirtualizeString(call.This.toString())
  207. allAscii := true
  208. totalLen := 0
  209. if u == nil {
  210. strs[0] = a
  211. totalLen = len(a)
  212. } else {
  213. strs[0] = u
  214. totalLen = u.Length()
  215. allAscii = false
  216. }
  217. for i, arg := range call.Arguments {
  218. a, u := devirtualizeString(arg.toString())
  219. if u != nil {
  220. allAscii = false
  221. totalLen += u.Length()
  222. strs[i+1] = u
  223. } else {
  224. totalLen += a.Length()
  225. strs[i+1] = a
  226. }
  227. }
  228. if allAscii {
  229. var buf strings.Builder
  230. buf.Grow(totalLen)
  231. for _, s := range strs {
  232. buf.WriteString(s.String())
  233. }
  234. return asciiString(buf.String())
  235. } else {
  236. buf := make([]uint16, totalLen+1)
  237. buf[0] = unistring.BOM
  238. pos := 1
  239. for _, s := range strs {
  240. switch s := s.(type) {
  241. case asciiString:
  242. for i := 0; i < len(s); i++ {
  243. buf[pos] = uint16(s[i])
  244. pos++
  245. }
  246. case unicodeString:
  247. copy(buf[pos:], s[1:])
  248. pos += s.Length()
  249. }
  250. }
  251. return unicodeString(buf)
  252. }
  253. }
  254. func (r *Runtime) stringproto_endsWith(call FunctionCall) Value {
  255. r.checkObjectCoercible(call.This)
  256. s := call.This.toString()
  257. searchString := call.Argument(0)
  258. if isRegexp(searchString) {
  259. panic(r.NewTypeError("First argument to String.prototype.endsWith must not be a regular expression"))
  260. }
  261. searchStr := searchString.toString()
  262. l := int64(s.Length())
  263. var pos int64
  264. if posArg := call.Argument(1); posArg != _undefined {
  265. pos = posArg.ToInteger()
  266. } else {
  267. pos = l
  268. }
  269. end := toIntStrict(min(max(pos, 0), l))
  270. searchLength := searchStr.Length()
  271. start := end - searchLength
  272. if start < 0 {
  273. return valueFalse
  274. }
  275. for i := 0; i < searchLength; i++ {
  276. if s.CharAt(start+i) != searchStr.CharAt(i) {
  277. return valueFalse
  278. }
  279. }
  280. return valueTrue
  281. }
  282. func (r *Runtime) stringproto_includes(call FunctionCall) Value {
  283. r.checkObjectCoercible(call.This)
  284. s := call.This.toString()
  285. searchString := call.Argument(0)
  286. if isRegexp(searchString) {
  287. panic(r.NewTypeError("First argument to String.prototype.includes must not be a regular expression"))
  288. }
  289. searchStr := searchString.toString()
  290. var pos int64
  291. if posArg := call.Argument(1); posArg != _undefined {
  292. pos = posArg.ToInteger()
  293. } else {
  294. pos = 0
  295. }
  296. start := toIntStrict(min(max(pos, 0), int64(s.Length())))
  297. if s.index(searchStr, start) != -1 {
  298. return valueTrue
  299. }
  300. return valueFalse
  301. }
  302. func (r *Runtime) stringproto_indexOf(call FunctionCall) Value {
  303. r.checkObjectCoercible(call.This)
  304. value := call.This.toString()
  305. target := call.Argument(0).toString()
  306. pos := call.Argument(1).ToInteger()
  307. if pos < 0 {
  308. pos = 0
  309. } else {
  310. l := int64(value.Length())
  311. if pos > l {
  312. pos = l
  313. }
  314. }
  315. return intToValue(int64(value.index(target, toIntStrict(pos))))
  316. }
  317. func (r *Runtime) stringproto_lastIndexOf(call FunctionCall) Value {
  318. r.checkObjectCoercible(call.This)
  319. value := call.This.toString()
  320. target := call.Argument(0).toString()
  321. numPos := call.Argument(1).ToNumber()
  322. var pos int64
  323. if f, ok := numPos.(valueFloat); ok && math.IsNaN(float64(f)) {
  324. pos = int64(value.Length())
  325. } else {
  326. pos = numPos.ToInteger()
  327. if pos < 0 {
  328. pos = 0
  329. } else {
  330. l := int64(value.Length())
  331. if pos > l {
  332. pos = l
  333. }
  334. }
  335. }
  336. return intToValue(int64(value.lastIndex(target, toIntStrict(pos))))
  337. }
  338. func (r *Runtime) stringproto_localeCompare(call FunctionCall) Value {
  339. r.checkObjectCoercible(call.This)
  340. this := norm.NFD.String(call.This.toString().String())
  341. that := norm.NFD.String(call.Argument(0).toString().String())
  342. return intToValue(int64(r.collator().CompareString(this, that)))
  343. }
  344. func (r *Runtime) stringproto_match(call FunctionCall) Value {
  345. r.checkObjectCoercible(call.This)
  346. regexp := call.Argument(0)
  347. if regexp != _undefined && regexp != _null {
  348. if matcher := toMethod(r.getV(regexp, SymMatch)); matcher != nil {
  349. return matcher(FunctionCall{
  350. This: regexp,
  351. Arguments: []Value{call.This},
  352. })
  353. }
  354. }
  355. var rx *regexpObject
  356. if regexp, ok := regexp.(*Object); ok {
  357. rx, _ = regexp.self.(*regexpObject)
  358. }
  359. if rx == nil {
  360. rx = r.newRegExp(regexp, nil, r.global.RegExpPrototype)
  361. }
  362. if matcher, ok := r.toObject(rx.getSym(SymMatch, nil)).self.assertCallable(); ok {
  363. return matcher(FunctionCall{
  364. This: rx.val,
  365. Arguments: []Value{call.This.toString()},
  366. })
  367. }
  368. panic(r.NewTypeError("RegExp matcher is not a function"))
  369. }
  370. func (r *Runtime) stringproto_matchAll(call FunctionCall) Value {
  371. r.checkObjectCoercible(call.This)
  372. regexp := call.Argument(0)
  373. if regexp != _undefined && regexp != _null {
  374. if isRegexp(regexp) {
  375. if o, ok := regexp.(*Object); ok {
  376. flags := nilSafe(o.self.getStr("flags", nil))
  377. r.checkObjectCoercible(flags)
  378. if !strings.Contains(flags.toString().String(), "g") {
  379. panic(r.NewTypeError("RegExp doesn't have global flag set"))
  380. }
  381. }
  382. }
  383. if matcher := toMethod(r.getV(regexp, SymMatchAll)); matcher != nil {
  384. return matcher(FunctionCall{
  385. This: regexp,
  386. Arguments: []Value{call.This},
  387. })
  388. }
  389. }
  390. rx := r.newRegExp(regexp, asciiString("g"), r.global.RegExpPrototype)
  391. if matcher, ok := r.toObject(rx.getSym(SymMatchAll, nil)).self.assertCallable(); ok {
  392. return matcher(FunctionCall{
  393. This: rx.val,
  394. Arguments: []Value{call.This.toString()},
  395. })
  396. }
  397. panic(r.NewTypeError("RegExp matcher is not a function"))
  398. }
  399. func (r *Runtime) stringproto_normalize(call FunctionCall) Value {
  400. r.checkObjectCoercible(call.This)
  401. s := call.This.toString()
  402. var form string
  403. if formArg := call.Argument(0); formArg != _undefined {
  404. form = formArg.toString().toString().String()
  405. } else {
  406. form = "NFC"
  407. }
  408. var f norm.Form
  409. switch form {
  410. case "NFC":
  411. f = norm.NFC
  412. case "NFD":
  413. f = norm.NFD
  414. case "NFKC":
  415. f = norm.NFKC
  416. case "NFKD":
  417. f = norm.NFKD
  418. default:
  419. panic(r.newError(r.global.RangeError, "The normalization form should be one of NFC, NFD, NFKC, NFKD"))
  420. }
  421. switch s := s.(type) {
  422. case asciiString:
  423. return s
  424. case unicodeString:
  425. ss := s.String()
  426. return newStringValue(f.String(ss))
  427. case *importedString:
  428. if s.scanned && s.u == nil {
  429. return asciiString(s.s)
  430. }
  431. return newStringValue(f.String(s.s))
  432. default:
  433. panic(unknownStringTypeErr(s))
  434. }
  435. }
  436. func (r *Runtime) _stringPad(call FunctionCall, start bool) Value {
  437. r.checkObjectCoercible(call.This)
  438. s := call.This.toString()
  439. maxLength := toLength(call.Argument(0))
  440. stringLength := int64(s.Length())
  441. if maxLength <= stringLength {
  442. return s
  443. }
  444. strAscii, strUnicode := devirtualizeString(s)
  445. var filler String
  446. var fillerAscii asciiString
  447. var fillerUnicode unicodeString
  448. if fillString := call.Argument(1); fillString != _undefined {
  449. filler = fillString.toString()
  450. if filler.Length() == 0 {
  451. return s
  452. }
  453. fillerAscii, fillerUnicode = devirtualizeString(filler)
  454. } else {
  455. fillerAscii = " "
  456. filler = fillerAscii
  457. }
  458. remaining := toIntStrict(maxLength - stringLength)
  459. if fillerUnicode == nil && strUnicode == nil {
  460. fl := fillerAscii.Length()
  461. var sb strings.Builder
  462. sb.Grow(toIntStrict(maxLength))
  463. if !start {
  464. sb.WriteString(string(strAscii))
  465. }
  466. for remaining >= fl {
  467. sb.WriteString(string(fillerAscii))
  468. remaining -= fl
  469. }
  470. if remaining > 0 {
  471. sb.WriteString(string(fillerAscii[:remaining]))
  472. }
  473. if start {
  474. sb.WriteString(string(strAscii))
  475. }
  476. return asciiString(sb.String())
  477. }
  478. var sb unicodeStringBuilder
  479. sb.ensureStarted(toIntStrict(maxLength))
  480. if !start {
  481. sb.writeString(s)
  482. }
  483. fl := filler.Length()
  484. for remaining >= fl {
  485. sb.writeString(filler)
  486. remaining -= fl
  487. }
  488. if remaining > 0 {
  489. sb.writeString(filler.Substring(0, remaining))
  490. }
  491. if start {
  492. sb.writeString(s)
  493. }
  494. return sb.String()
  495. }
  496. func (r *Runtime) stringproto_padEnd(call FunctionCall) Value {
  497. return r._stringPad(call, false)
  498. }
  499. func (r *Runtime) stringproto_padStart(call FunctionCall) Value {
  500. return r._stringPad(call, true)
  501. }
  502. func (r *Runtime) stringproto_repeat(call FunctionCall) Value {
  503. r.checkObjectCoercible(call.This)
  504. s := call.This.toString()
  505. n := call.Argument(0).ToNumber()
  506. if n == _positiveInf {
  507. panic(r.newError(r.global.RangeError, "Invalid count value"))
  508. }
  509. numInt := n.ToInteger()
  510. if numInt < 0 {
  511. panic(r.newError(r.global.RangeError, "Invalid count value"))
  512. }
  513. if numInt == 0 || s.Length() == 0 {
  514. return stringEmpty
  515. }
  516. num := toIntStrict(numInt)
  517. a, u := devirtualizeString(s)
  518. if u == nil {
  519. var sb strings.Builder
  520. sb.Grow(len(a) * num)
  521. for i := 0; i < num; i++ {
  522. sb.WriteString(string(a))
  523. }
  524. return asciiString(sb.String())
  525. }
  526. var sb unicodeStringBuilder
  527. sb.Grow(u.Length() * num)
  528. for i := 0; i < num; i++ {
  529. sb.writeUnicodeString(u)
  530. }
  531. return sb.String()
  532. }
  533. func getReplaceValue(replaceValue Value) (str String, rcall func(FunctionCall) Value) {
  534. if replaceValue, ok := replaceValue.(*Object); ok {
  535. if c, ok := replaceValue.self.assertCallable(); ok {
  536. rcall = c
  537. return
  538. }
  539. }
  540. str = replaceValue.toString()
  541. return
  542. }
  543. func stringReplace(s String, found [][]int, newstring String, rcall func(FunctionCall) Value) Value {
  544. if len(found) == 0 {
  545. return s
  546. }
  547. a, u := devirtualizeString(s)
  548. var buf StringBuilder
  549. lastIndex := 0
  550. lengthS := s.Length()
  551. if rcall != nil {
  552. for _, item := range found {
  553. if item[0] != lastIndex {
  554. buf.WriteSubstring(s, lastIndex, item[0])
  555. }
  556. matchCount := len(item) / 2
  557. argumentList := make([]Value, matchCount+2)
  558. for index := 0; index < matchCount; index++ {
  559. offset := 2 * index
  560. if item[offset] != -1 {
  561. if u == nil {
  562. argumentList[index] = a[item[offset]:item[offset+1]]
  563. } else {
  564. argumentList[index] = u.Substring(item[offset], item[offset+1])
  565. }
  566. } else {
  567. argumentList[index] = _undefined
  568. }
  569. }
  570. argumentList[matchCount] = valueInt(item[0])
  571. argumentList[matchCount+1] = s
  572. replacement := rcall(FunctionCall{
  573. This: _undefined,
  574. Arguments: argumentList,
  575. }).toString()
  576. buf.WriteString(replacement)
  577. lastIndex = item[1]
  578. }
  579. } else {
  580. for _, item := range found {
  581. if item[0] != lastIndex {
  582. buf.WriteString(s.Substring(lastIndex, item[0]))
  583. }
  584. matchCount := len(item) / 2
  585. writeSubstitution(s, item[0], matchCount, func(idx int) String {
  586. if item[idx*2] != -1 {
  587. if u == nil {
  588. return a[item[idx*2]:item[idx*2+1]]
  589. }
  590. return u.Substring(item[idx*2], item[idx*2+1])
  591. }
  592. return stringEmpty
  593. }, newstring, &buf)
  594. lastIndex = item[1]
  595. }
  596. }
  597. if lastIndex != lengthS {
  598. buf.WriteString(s.Substring(lastIndex, lengthS))
  599. }
  600. return buf.String()
  601. }
  602. func (r *Runtime) stringproto_replace(call FunctionCall) Value {
  603. r.checkObjectCoercible(call.This)
  604. searchValue := call.Argument(0)
  605. replaceValue := call.Argument(1)
  606. if searchValue != _undefined && searchValue != _null {
  607. if replacer := toMethod(r.getV(searchValue, SymReplace)); replacer != nil {
  608. return replacer(FunctionCall{
  609. This: searchValue,
  610. Arguments: []Value{call.This, replaceValue},
  611. })
  612. }
  613. }
  614. s := call.This.toString()
  615. var found [][]int
  616. searchStr := searchValue.toString()
  617. pos := s.index(searchStr, 0)
  618. if pos != -1 {
  619. found = append(found, []int{pos, pos + searchStr.Length()})
  620. }
  621. str, rcall := getReplaceValue(replaceValue)
  622. return stringReplace(s, found, str, rcall)
  623. }
  624. func (r *Runtime) stringproto_replaceAll(call FunctionCall) Value {
  625. r.checkObjectCoercible(call.This)
  626. searchValue := call.Argument(0)
  627. replaceValue := call.Argument(1)
  628. if searchValue != _undefined && searchValue != _null {
  629. if isRegexp(searchValue) {
  630. if o, ok := searchValue.(*Object); ok {
  631. flags := nilSafe(o.self.getStr("flags", nil))
  632. r.checkObjectCoercible(flags)
  633. if !strings.Contains(flags.toString().String(), "g") {
  634. panic(r.NewTypeError("String.prototype.replaceAll called with a non-global RegExp argument"))
  635. }
  636. }
  637. }
  638. if replacer := toMethod(r.getV(searchValue, SymReplace)); replacer != nil {
  639. return replacer(FunctionCall{
  640. This: searchValue,
  641. Arguments: []Value{call.This, replaceValue},
  642. })
  643. }
  644. }
  645. s := call.This.toString()
  646. var found [][]int
  647. searchStr := searchValue.toString()
  648. searchLength := searchStr.Length()
  649. advanceBy := toIntStrict(max(1, int64(searchLength)))
  650. pos := s.index(searchStr, 0)
  651. for pos != -1 {
  652. found = append(found, []int{pos, pos + searchLength})
  653. pos = s.index(searchStr, pos+advanceBy)
  654. }
  655. str, rcall := getReplaceValue(replaceValue)
  656. return stringReplace(s, found, str, rcall)
  657. }
  658. func (r *Runtime) stringproto_search(call FunctionCall) Value {
  659. r.checkObjectCoercible(call.This)
  660. regexp := call.Argument(0)
  661. if regexp != _undefined && regexp != _null {
  662. if searcher := toMethod(r.getV(regexp, SymSearch)); searcher != nil {
  663. return searcher(FunctionCall{
  664. This: regexp,
  665. Arguments: []Value{call.This},
  666. })
  667. }
  668. }
  669. var rx *regexpObject
  670. if regexp, ok := regexp.(*Object); ok {
  671. rx, _ = regexp.self.(*regexpObject)
  672. }
  673. if rx == nil {
  674. rx = r.newRegExp(regexp, nil, r.global.RegExpPrototype)
  675. }
  676. if searcher, ok := r.toObject(rx.getSym(SymSearch, nil)).self.assertCallable(); ok {
  677. return searcher(FunctionCall{
  678. This: rx.val,
  679. Arguments: []Value{call.This.toString()},
  680. })
  681. }
  682. panic(r.NewTypeError("RegExp searcher is not a function"))
  683. }
  684. func (r *Runtime) stringproto_slice(call FunctionCall) Value {
  685. r.checkObjectCoercible(call.This)
  686. s := call.This.toString()
  687. l := int64(s.Length())
  688. start := call.Argument(0).ToInteger()
  689. var end int64
  690. if arg1 := call.Argument(1); arg1 != _undefined {
  691. end = arg1.ToInteger()
  692. } else {
  693. end = l
  694. }
  695. if start < 0 {
  696. start += l
  697. if start < 0 {
  698. start = 0
  699. }
  700. } else {
  701. if start > l {
  702. start = l
  703. }
  704. }
  705. if end < 0 {
  706. end += l
  707. if end < 0 {
  708. end = 0
  709. }
  710. } else {
  711. if end > l {
  712. end = l
  713. }
  714. }
  715. if end > start {
  716. return s.Substring(int(start), int(end))
  717. }
  718. return stringEmpty
  719. }
  720. func (r *Runtime) stringproto_split(call FunctionCall) Value {
  721. r.checkObjectCoercible(call.This)
  722. separatorValue := call.Argument(0)
  723. limitValue := call.Argument(1)
  724. if separatorValue != _undefined && separatorValue != _null {
  725. if splitter := toMethod(r.getV(separatorValue, SymSplit)); splitter != nil {
  726. return splitter(FunctionCall{
  727. This: separatorValue,
  728. Arguments: []Value{call.This, limitValue},
  729. })
  730. }
  731. }
  732. s := call.This.toString()
  733. limit := -1
  734. if limitValue != _undefined {
  735. limit = int(toUint32(limitValue))
  736. }
  737. separatorValue = separatorValue.ToString()
  738. if limit == 0 {
  739. return r.newArrayValues(nil)
  740. }
  741. if separatorValue == _undefined {
  742. return r.newArrayValues([]Value{s})
  743. }
  744. separator := separatorValue.String()
  745. excess := false
  746. str := s.String()
  747. if limit > len(str) {
  748. limit = len(str)
  749. }
  750. splitLimit := limit
  751. if limit > 0 {
  752. splitLimit = limit + 1
  753. excess = true
  754. }
  755. // TODO handle invalid UTF-16
  756. split := strings.SplitN(str, separator, splitLimit)
  757. if excess && len(split) > limit {
  758. split = split[:limit]
  759. }
  760. valueArray := make([]Value, len(split))
  761. for index, value := range split {
  762. valueArray[index] = newStringValue(value)
  763. }
  764. return r.newArrayValues(valueArray)
  765. }
  766. func (r *Runtime) stringproto_startsWith(call FunctionCall) Value {
  767. r.checkObjectCoercible(call.This)
  768. s := call.This.toString()
  769. searchString := call.Argument(0)
  770. if isRegexp(searchString) {
  771. panic(r.NewTypeError("First argument to String.prototype.startsWith must not be a regular expression"))
  772. }
  773. searchStr := searchString.toString()
  774. l := int64(s.Length())
  775. var pos int64
  776. if posArg := call.Argument(1); posArg != _undefined {
  777. pos = posArg.ToInteger()
  778. }
  779. start := toIntStrict(min(max(pos, 0), l))
  780. searchLength := searchStr.Length()
  781. if int64(searchLength+start) > l {
  782. return valueFalse
  783. }
  784. for i := 0; i < searchLength; i++ {
  785. if s.CharAt(start+i) != searchStr.CharAt(i) {
  786. return valueFalse
  787. }
  788. }
  789. return valueTrue
  790. }
  791. func (r *Runtime) stringproto_substring(call FunctionCall) Value {
  792. r.checkObjectCoercible(call.This)
  793. s := call.This.toString()
  794. l := int64(s.Length())
  795. intStart := call.Argument(0).ToInteger()
  796. var intEnd int64
  797. if end := call.Argument(1); end != _undefined {
  798. intEnd = end.ToInteger()
  799. } else {
  800. intEnd = l
  801. }
  802. if intStart < 0 {
  803. intStart = 0
  804. } else if intStart > l {
  805. intStart = l
  806. }
  807. if intEnd < 0 {
  808. intEnd = 0
  809. } else if intEnd > l {
  810. intEnd = l
  811. }
  812. if intStart > intEnd {
  813. intStart, intEnd = intEnd, intStart
  814. }
  815. return s.Substring(int(intStart), int(intEnd))
  816. }
  817. func (r *Runtime) stringproto_toLowerCase(call FunctionCall) Value {
  818. r.checkObjectCoercible(call.This)
  819. s := call.This.toString()
  820. return s.toLower()
  821. }
  822. func (r *Runtime) stringproto_toUpperCase(call FunctionCall) Value {
  823. r.checkObjectCoercible(call.This)
  824. s := call.This.toString()
  825. return s.toUpper()
  826. }
  827. func (r *Runtime) stringproto_trim(call FunctionCall) Value {
  828. r.checkObjectCoercible(call.This)
  829. s := call.This.toString()
  830. // TODO handle invalid UTF-16
  831. return newStringValue(strings.Trim(s.String(), parser.WhitespaceChars))
  832. }
  833. func (r *Runtime) stringproto_trimEnd(call FunctionCall) Value {
  834. r.checkObjectCoercible(call.This)
  835. s := call.This.toString()
  836. // TODO handle invalid UTF-16
  837. return newStringValue(strings.TrimRight(s.String(), parser.WhitespaceChars))
  838. }
  839. func (r *Runtime) stringproto_trimStart(call FunctionCall) Value {
  840. r.checkObjectCoercible(call.This)
  841. s := call.This.toString()
  842. // TODO handle invalid UTF-16
  843. return newStringValue(strings.TrimLeft(s.String(), parser.WhitespaceChars))
  844. }
  845. func (r *Runtime) stringproto_substr(call FunctionCall) Value {
  846. r.checkObjectCoercible(call.This)
  847. s := call.This.toString()
  848. start := call.Argument(0).ToInteger()
  849. var length int64
  850. sl := int64(s.Length())
  851. if arg := call.Argument(1); arg != _undefined {
  852. length = arg.ToInteger()
  853. } else {
  854. length = sl
  855. }
  856. if start < 0 {
  857. start = max(sl+start, 0)
  858. }
  859. length = min(max(length, 0), sl-start)
  860. if length <= 0 {
  861. return stringEmpty
  862. }
  863. return s.Substring(int(start), int(start+length))
  864. }
  865. func (r *Runtime) stringIterProto_next(call FunctionCall) Value {
  866. thisObj := r.toObject(call.This)
  867. if iter, ok := thisObj.self.(*stringIterObject); ok {
  868. return iter.next()
  869. }
  870. panic(r.NewTypeError("Method String Iterator.prototype.next called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
  871. }
  872. func (r *Runtime) createStringIterProto(val *Object) objectImpl {
  873. o := newBaseObjectObj(val, r.getIteratorPrototype(), classObject)
  874. o._putProp("next", r.newNativeFunc(r.stringIterProto_next, nil, "next", nil, 0), true, false, true)
  875. o._putSym(SymToStringTag, valueProp(asciiString(classStringIterator), false, false, true))
  876. return o
  877. }
  878. func (r *Runtime) getStringIteratorPrototype() *Object {
  879. var o *Object
  880. if o = r.global.StringIteratorPrototype; o == nil {
  881. o = &Object{runtime: r}
  882. r.global.StringIteratorPrototype = o
  883. o.self = r.createStringIterProto(o)
  884. }
  885. return o
  886. }
  887. func (r *Runtime) initString() {
  888. r.global.StringPrototype = r.builtin_newString([]Value{stringEmpty}, r.global.ObjectPrototype)
  889. o := r.global.StringPrototype.self
  890. o._putProp("at", r.newNativeFunc(r.stringproto_at, nil, "at", nil, 1), true, false, true)
  891. o._putProp("charAt", r.newNativeFunc(r.stringproto_charAt, nil, "charAt", nil, 1), true, false, true)
  892. o._putProp("charCodeAt", r.newNativeFunc(r.stringproto_charCodeAt, nil, "charCodeAt", nil, 1), true, false, true)
  893. o._putProp("codePointAt", r.newNativeFunc(r.stringproto_codePointAt, nil, "codePointAt", nil, 1), true, false, true)
  894. o._putProp("concat", r.newNativeFunc(r.stringproto_concat, nil, "concat", nil, 1), true, false, true)
  895. o._putProp("endsWith", r.newNativeFunc(r.stringproto_endsWith, nil, "endsWith", nil, 1), true, false, true)
  896. o._putProp("includes", r.newNativeFunc(r.stringproto_includes, nil, "includes", nil, 1), true, false, true)
  897. o._putProp("indexOf", r.newNativeFunc(r.stringproto_indexOf, nil, "indexOf", nil, 1), true, false, true)
  898. o._putProp("lastIndexOf", r.newNativeFunc(r.stringproto_lastIndexOf, nil, "lastIndexOf", nil, 1), true, false, true)
  899. o._putProp("localeCompare", r.newNativeFunc(r.stringproto_localeCompare, nil, "localeCompare", nil, 1), true, false, true)
  900. o._putProp("match", r.newNativeFunc(r.stringproto_match, nil, "match", nil, 1), true, false, true)
  901. o._putProp("matchAll", r.newNativeFunc(r.stringproto_matchAll, nil, "matchAll", nil, 1), true, false, true)
  902. o._putProp("normalize", r.newNativeFunc(r.stringproto_normalize, nil, "normalize", nil, 0), true, false, true)
  903. o._putProp("padEnd", r.newNativeFunc(r.stringproto_padEnd, nil, "padEnd", nil, 1), true, false, true)
  904. o._putProp("padStart", r.newNativeFunc(r.stringproto_padStart, nil, "padStart", nil, 1), true, false, true)
  905. o._putProp("repeat", r.newNativeFunc(r.stringproto_repeat, nil, "repeat", nil, 1), true, false, true)
  906. o._putProp("replace", r.newNativeFunc(r.stringproto_replace, nil, "replace", nil, 2), true, false, true)
  907. o._putProp("replaceAll", r.newNativeFunc(r.stringproto_replaceAll, nil, "replaceAll", nil, 2), true, false, true)
  908. o._putProp("search", r.newNativeFunc(r.stringproto_search, nil, "search", nil, 1), true, false, true)
  909. o._putProp("slice", r.newNativeFunc(r.stringproto_slice, nil, "slice", nil, 2), true, false, true)
  910. o._putProp("split", r.newNativeFunc(r.stringproto_split, nil, "split", nil, 2), true, false, true)
  911. o._putProp("startsWith", r.newNativeFunc(r.stringproto_startsWith, nil, "startsWith", nil, 1), true, false, true)
  912. o._putProp("substring", r.newNativeFunc(r.stringproto_substring, nil, "substring", nil, 2), true, false, true)
  913. o._putProp("toLocaleLowerCase", r.newNativeFunc(r.stringproto_toLowerCase, nil, "toLocaleLowerCase", nil, 0), true, false, true)
  914. o._putProp("toLocaleUpperCase", r.newNativeFunc(r.stringproto_toUpperCase, nil, "toLocaleUpperCase", nil, 0), true, false, true)
  915. o._putProp("toLowerCase", r.newNativeFunc(r.stringproto_toLowerCase, nil, "toLowerCase", nil, 0), true, false, true)
  916. o._putProp("toString", r.newNativeFunc(r.stringproto_toString, nil, "toString", nil, 0), true, false, true)
  917. o._putProp("toUpperCase", r.newNativeFunc(r.stringproto_toUpperCase, nil, "toUpperCase", nil, 0), true, false, true)
  918. o._putProp("trim", r.newNativeFunc(r.stringproto_trim, nil, "trim", nil, 0), true, false, true)
  919. trimEnd := r.newNativeFunc(r.stringproto_trimEnd, nil, "trimEnd", nil, 0)
  920. trimStart := r.newNativeFunc(r.stringproto_trimStart, nil, "trimStart", nil, 0)
  921. o._putProp("trimEnd", trimEnd, true, false, true)
  922. o._putProp("trimStart", trimStart, true, false, true)
  923. o._putProp("trimRight", trimEnd, true, false, true)
  924. o._putProp("trimLeft", trimStart, true, false, true)
  925. o._putProp("valueOf", r.newNativeFunc(r.stringproto_valueOf, nil, "valueOf", nil, 0), true, false, true)
  926. o._putSym(SymIterator, valueProp(r.newNativeFunc(r.stringproto_iterator, nil, "[Symbol.iterator]", nil, 0), true, false, true))
  927. // Annex B
  928. o._putProp("substr", r.newNativeFunc(r.stringproto_substr, nil, "substr", nil, 2), true, false, true)
  929. r.global.String = r.newNativeFunc(r.builtin_String, r.builtin_newString, "String", r.global.StringPrototype, 1)
  930. o = r.global.String.self
  931. o._putProp("fromCharCode", r.newNativeFunc(r.string_fromcharcode, nil, "fromCharCode", nil, 1), true, false, true)
  932. o._putProp("fromCodePoint", r.newNativeFunc(r.string_fromcodepoint, nil, "fromCodePoint", nil, 1), true, false, true)
  933. o._putProp("raw", r.newNativeFunc(r.string_raw, nil, "raw", nil, 1), true, false, true)
  934. r.addToGlobal("String", r.global.String)
  935. r.stringSingleton = r.builtin_new(r.global.String, nil).self.(*stringObject)
  936. }