builtin_string.go 27 KB

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