builtin_string.go 25 KB

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