• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5(function(global, utils) {
6
7%CheckIsBootstrapping();
8
9// -------------------------------------------------------------------
10// Imports
11
12var ArrayIndexOf;
13var ArrayJoin;
14var GlobalRegExp = global.RegExp;
15var GlobalString = global.String;
16var IsRegExp;
17var MakeRangeError;
18var MakeTypeError;
19var MaxSimple;
20var MinSimple;
21var RegExpInitialize;
22var matchSymbol = utils.ImportNow("match_symbol");
23var replaceSymbol = utils.ImportNow("replace_symbol");
24var searchSymbol = utils.ImportNow("search_symbol");
25var splitSymbol = utils.ImportNow("split_symbol");
26
27utils.Import(function(from) {
28  ArrayIndexOf = from.ArrayIndexOf;
29  ArrayJoin = from.ArrayJoin;
30  IsRegExp = from.IsRegExp;
31  MakeRangeError = from.MakeRangeError;
32  MakeTypeError = from.MakeTypeError;
33  MaxSimple = from.MaxSimple;
34  MinSimple = from.MinSimple;
35  RegExpInitialize = from.RegExpInitialize;
36});
37
38//-------------------------------------------------------------------
39
40// ECMA-262 section 15.5.4.2
41function StringToString() {
42  if (!IS_STRING(this) && !IS_STRING_WRAPPER(this)) {
43    throw MakeTypeError(kNotGeneric, 'String.prototype.toString');
44  }
45  return %_ValueOf(this);
46}
47
48
49// ECMA-262 section 15.5.4.3
50function StringValueOf() {
51  if (!IS_STRING(this) && !IS_STRING_WRAPPER(this)) {
52    throw MakeTypeError(kNotGeneric, 'String.prototype.valueOf');
53  }
54  return %_ValueOf(this);
55}
56
57
58// ECMA-262, section 15.5.4.6
59function StringConcat(other /* and more */) {  // length == 1
60  "use strict";
61  CHECK_OBJECT_COERCIBLE(this, "String.prototype.concat");
62  var s = TO_STRING(this);
63  var len = arguments.length;
64  for (var i = 0; i < len; ++i) {
65    s = s + TO_STRING(arguments[i]);
66  }
67  return s;
68}
69
70
71// ECMA-262 section 15.5.4.7
72function StringIndexOf(pattern, position) {  // length == 1
73  CHECK_OBJECT_COERCIBLE(this, "String.prototype.indexOf");
74
75  var subject = TO_STRING(this);
76  pattern = TO_STRING(pattern);
77  var index = TO_INTEGER(position);
78  if (index < 0) index = 0;
79  if (index > subject.length) index = subject.length;
80  return %StringIndexOf(subject, pattern, index);
81}
82
83%FunctionSetLength(StringIndexOf, 1);
84
85
86// ECMA-262 section 15.5.4.8
87function StringLastIndexOf(pat, pos) {  // length == 1
88  CHECK_OBJECT_COERCIBLE(this, "String.prototype.lastIndexOf");
89
90  var sub = TO_STRING(this);
91  var subLength = sub.length;
92  var pat = TO_STRING(pat);
93  var patLength = pat.length;
94  var index = subLength - patLength;
95  var position = TO_NUMBER(pos);
96  if (!NUMBER_IS_NAN(position)) {
97    position = TO_INTEGER(position);
98    if (position < 0) {
99      position = 0;
100    }
101    if (position + patLength < subLength) {
102      index = position;
103    }
104  }
105  if (index < 0) {
106    return -1;
107  }
108  return %StringLastIndexOf(sub, pat, index);
109}
110
111%FunctionSetLength(StringLastIndexOf, 1);
112
113
114// ECMA-262 section 15.5.4.9
115//
116// This function is implementation specific.  For now, we do not
117// do anything locale specific.
118function StringLocaleCompareJS(other) {
119  CHECK_OBJECT_COERCIBLE(this, "String.prototype.localeCompare");
120
121  return %StringLocaleCompare(TO_STRING(this), TO_STRING(other));
122}
123
124
125// ES6 21.1.3.11.
126function StringMatchJS(pattern) {
127  CHECK_OBJECT_COERCIBLE(this, "String.prototype.match");
128
129  if (!IS_NULL_OR_UNDEFINED(pattern)) {
130    var matcher = pattern[matchSymbol];
131    if (!IS_UNDEFINED(matcher)) {
132      return %_Call(matcher, pattern, this);
133    }
134  }
135
136  var subject = TO_STRING(this);
137
138  // Equivalent to RegExpCreate (ES#sec-regexpcreate)
139  var regexp = %_NewObject(GlobalRegExp, GlobalRegExp);
140  RegExpInitialize(regexp, pattern);
141  return regexp[matchSymbol](subject);
142}
143
144
145// ECMA-262 v6, section 21.1.3.12
146//
147// For now we do nothing, as proper normalization requires big tables.
148// If Intl is enabled, then i18n.js will override it and provide the the
149// proper functionality.
150function StringNormalize(formArg) {  // length == 0
151  CHECK_OBJECT_COERCIBLE(this, "String.prototype.normalize");
152  var s = TO_STRING(this);
153
154  var form = IS_UNDEFINED(formArg) ? 'NFC' : TO_STRING(formArg);
155
156  var NORMALIZATION_FORMS = ['NFC', 'NFD', 'NFKC', 'NFKD'];
157  var normalizationForm = %_Call(ArrayIndexOf, NORMALIZATION_FORMS, form);
158  if (normalizationForm === -1) {
159    throw MakeRangeError(kNormalizationForm,
160                         %_Call(ArrayJoin, NORMALIZATION_FORMS, ', '));
161  }
162
163  return s;
164}
165
166%FunctionSetLength(StringNormalize, 0);
167
168
169// This has the same size as the RegExpLastMatchInfo array, and can be used
170// for functions that expect that structure to be returned.  It is used when
171// the needle is a string rather than a regexp.  In this case we can't update
172// lastMatchArray without erroneously affecting the properties on the global
173// RegExp object.
174var reusableMatchInfo = [2, "", "", -1, -1];
175
176
177// ES6, section 21.1.3.14
178function StringReplace(search, replace) {
179  CHECK_OBJECT_COERCIBLE(this, "String.prototype.replace");
180
181  // Decision tree for dispatch
182  // .. regexp search (in src/js/regexp.js, RegExpReplace)
183  // .... string replace
184  // ...... non-global search
185  // ........ empty string replace
186  // ........ non-empty string replace (with $-expansion)
187  // ...... global search
188  // ........ no need to circumvent last match info override
189  // ........ need to circument last match info override
190  // .... function replace
191  // ...... global search
192  // ...... non-global search
193  // .. string search
194  // .... special case that replaces with one single character
195  // ...... function replace
196  // ...... string replace (with $-expansion)
197
198  if (!IS_NULL_OR_UNDEFINED(search)) {
199    var replacer = search[replaceSymbol];
200    if (!IS_UNDEFINED(replacer)) {
201      return %_Call(replacer, search, this, replace);
202    }
203  }
204
205  var subject = TO_STRING(this);
206
207  search = TO_STRING(search);
208
209  if (search.length == 1 &&
210      subject.length > 0xFF &&
211      IS_STRING(replace) &&
212      %StringIndexOf(replace, '$', 0) < 0) {
213    // Searching by traversing a cons string tree and replace with cons of
214    // slices works only when the replaced string is a single character, being
215    // replaced by a simple string and only pays off for long strings.
216    return %StringReplaceOneCharWithString(subject, search, replace);
217  }
218  var start = %StringIndexOf(subject, search, 0);
219  if (start < 0) return subject;
220  var end = start + search.length;
221
222  var result = %_SubString(subject, 0, start);
223
224  // Compute the string to replace with.
225  if (IS_CALLABLE(replace)) {
226    result += replace(search, start, subject);
227  } else {
228    reusableMatchInfo[CAPTURE0] = start;
229    reusableMatchInfo[CAPTURE1] = end;
230    result = ExpandReplacement(TO_STRING(replace),
231                               subject,
232                               reusableMatchInfo,
233                               result);
234  }
235
236  return result + %_SubString(subject, end, subject.length);
237}
238
239
240// Expand the $-expressions in the string and return a new string with
241// the result.
242function ExpandReplacement(string, subject, matchInfo, result) {
243  var length = string.length;
244  var next = %StringIndexOf(string, '$', 0);
245  if (next < 0) {
246    if (length > 0) result += string;
247    return result;
248  }
249
250  if (next > 0) result += %_SubString(string, 0, next);
251
252  while (true) {
253    var expansion = '$';
254    var position = next + 1;
255    if (position < length) {
256      var peek = %_StringCharCodeAt(string, position);
257      if (peek == 36) {         // $$
258        ++position;
259        result += '$';
260      } else if (peek == 38) {  // $& - match
261        ++position;
262        result +=
263          %_SubString(subject, matchInfo[CAPTURE0], matchInfo[CAPTURE1]);
264      } else if (peek == 96) {  // $` - prefix
265        ++position;
266        result += %_SubString(subject, 0, matchInfo[CAPTURE0]);
267      } else if (peek == 39) {  // $' - suffix
268        ++position;
269        result += %_SubString(subject, matchInfo[CAPTURE1], subject.length);
270      } else if (peek >= 48 && peek <= 57) {
271        // Valid indices are $1 .. $9, $01 .. $09 and $10 .. $99
272        var scaled_index = (peek - 48) << 1;
273        var advance = 1;
274        var number_of_captures = NUMBER_OF_CAPTURES(matchInfo);
275        if (position + 1 < string.length) {
276          var next = %_StringCharCodeAt(string, position + 1);
277          if (next >= 48 && next <= 57) {
278            var new_scaled_index = scaled_index * 10 + ((next - 48) << 1);
279            if (new_scaled_index < number_of_captures) {
280              scaled_index = new_scaled_index;
281              advance = 2;
282            }
283          }
284        }
285        if (scaled_index != 0 && scaled_index < number_of_captures) {
286          var start = matchInfo[CAPTURE(scaled_index)];
287          if (start >= 0) {
288            result +=
289              %_SubString(subject, start, matchInfo[CAPTURE(scaled_index + 1)]);
290          }
291          position += advance;
292        } else {
293          result += '$';
294        }
295      } else {
296        result += '$';
297      }
298    } else {
299      result += '$';
300    }
301
302    // Go the the next $ in the string.
303    next = %StringIndexOf(string, '$', position);
304
305    // Return if there are no more $ characters in the string. If we
306    // haven't reached the end, we need to append the suffix.
307    if (next < 0) {
308      if (position < length) {
309        result += %_SubString(string, position, length);
310      }
311      return result;
312    }
313
314    // Append substring between the previous and the next $ character.
315    if (next > position) {
316      result += %_SubString(string, position, next);
317    }
318  }
319  return result;
320}
321
322
323// ES6 21.1.3.15.
324function StringSearch(pattern) {
325  CHECK_OBJECT_COERCIBLE(this, "String.prototype.search");
326
327  if (!IS_NULL_OR_UNDEFINED(pattern)) {
328    var searcher = pattern[searchSymbol];
329    if (!IS_UNDEFINED(searcher)) {
330      return %_Call(searcher, pattern, this);
331    }
332  }
333
334  var subject = TO_STRING(this);
335
336  // Equivalent to RegExpCreate (ES#sec-regexpcreate)
337  var regexp = %_NewObject(GlobalRegExp, GlobalRegExp);
338  RegExpInitialize(regexp, pattern);
339  return %_Call(regexp[searchSymbol], regexp, subject);
340}
341
342
343// ECMA-262 section 15.5.4.13
344function StringSlice(start, end) {
345  CHECK_OBJECT_COERCIBLE(this, "String.prototype.slice");
346
347  var s = TO_STRING(this);
348  var s_len = s.length;
349  var start_i = TO_INTEGER(start);
350  var end_i = s_len;
351  if (!IS_UNDEFINED(end)) {
352    end_i = TO_INTEGER(end);
353  }
354
355  if (start_i < 0) {
356    start_i += s_len;
357    if (start_i < 0) {
358      start_i = 0;
359    }
360  } else {
361    if (start_i > s_len) {
362      return '';
363    }
364  }
365
366  if (end_i < 0) {
367    end_i += s_len;
368    if (end_i < 0) {
369      return '';
370    }
371  } else {
372    if (end_i > s_len) {
373      end_i = s_len;
374    }
375  }
376
377  if (end_i <= start_i) {
378    return '';
379  }
380
381  return %_SubString(s, start_i, end_i);
382}
383
384
385// ES6 21.1.3.17.
386function StringSplitJS(separator, limit) {
387  CHECK_OBJECT_COERCIBLE(this, "String.prototype.split");
388
389  if (!IS_NULL_OR_UNDEFINED(separator)) {
390    var splitter = separator[splitSymbol];
391    if (!IS_UNDEFINED(splitter)) {
392      return %_Call(splitter, separator, this, limit);
393    }
394  }
395
396  var subject = TO_STRING(this);
397  limit = (IS_UNDEFINED(limit)) ? kMaxUint32 : TO_UINT32(limit);
398
399  var length = subject.length;
400  var separator_string = TO_STRING(separator);
401
402  if (limit === 0) return [];
403
404  // ECMA-262 says that if separator is undefined, the result should
405  // be an array of size 1 containing the entire string.
406  if (IS_UNDEFINED(separator)) return [subject];
407
408  var separator_length = separator_string.length;
409
410  // If the separator string is empty then return the elements in the subject.
411  if (separator_length === 0) return %StringToArray(subject, limit);
412
413  return %StringSplit(subject, separator_string, limit);
414}
415
416
417// ECMA-262 section 15.5.4.15
418function StringSubstring(start, end) {
419  CHECK_OBJECT_COERCIBLE(this, "String.prototype.subString");
420
421  var s = TO_STRING(this);
422  var s_len = s.length;
423
424  var start_i = TO_INTEGER(start);
425  if (start_i < 0) {
426    start_i = 0;
427  } else if (start_i > s_len) {
428    start_i = s_len;
429  }
430
431  var end_i = s_len;
432  if (!IS_UNDEFINED(end)) {
433    end_i = TO_INTEGER(end);
434    if (end_i > s_len) {
435      end_i = s_len;
436    } else {
437      if (end_i < 0) end_i = 0;
438      if (start_i > end_i) {
439        var tmp = end_i;
440        end_i = start_i;
441        start_i = tmp;
442      }
443    }
444  }
445
446  return %_SubString(s, start_i, end_i);
447}
448
449
450// ES6 draft, revision 26 (2014-07-18), section B.2.3.1
451function StringSubstr(start, n) {
452  CHECK_OBJECT_COERCIBLE(this, "String.prototype.substr");
453
454  var s = TO_STRING(this);
455  var len;
456
457  // Correct n: If not given, set to string length; if explicitly
458  // set to undefined, zero, or negative, returns empty string.
459  if (IS_UNDEFINED(n)) {
460    len = s.length;
461  } else {
462    len = TO_INTEGER(n);
463    if (len <= 0) return '';
464  }
465
466  // Correct start: If not given (or undefined), set to zero; otherwise
467  // convert to integer and handle negative case.
468  if (IS_UNDEFINED(start)) {
469    start = 0;
470  } else {
471    start = TO_INTEGER(start);
472    // If positive, and greater than or equal to the string length,
473    // return empty string.
474    if (start >= s.length) return '';
475    // If negative and absolute value is larger than the string length,
476    // use zero.
477    if (start < 0) {
478      start += s.length;
479      if (start < 0) start = 0;
480    }
481  }
482
483  var end = start + len;
484  if (end > s.length) end = s.length;
485
486  return %_SubString(s, start, end);
487}
488
489
490// ECMA-262, 15.5.4.16
491function StringToLowerCaseJS() {
492  CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLowerCase");
493
494  return %StringToLowerCase(TO_STRING(this));
495}
496
497
498// ECMA-262, 15.5.4.17
499function StringToLocaleLowerCase() {
500  CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleLowerCase");
501
502  return %StringToLowerCase(TO_STRING(this));
503}
504
505
506// ECMA-262, 15.5.4.18
507function StringToUpperCaseJS() {
508  CHECK_OBJECT_COERCIBLE(this, "String.prototype.toUpperCase");
509
510  return %StringToUpperCase(TO_STRING(this));
511}
512
513
514// ECMA-262, 15.5.4.19
515function StringToLocaleUpperCase() {
516  CHECK_OBJECT_COERCIBLE(this, "String.prototype.toLocaleUpperCase");
517
518  return %StringToUpperCase(TO_STRING(this));
519}
520
521
522// ES6 draft, revision 26 (2014-07-18), section B.2.3.2.1
523function HtmlEscape(str) {
524  return %_Call(StringReplace, TO_STRING(str), /"/g, "&quot;");
525}
526
527
528// ES6 draft, revision 26 (2014-07-18), section B.2.3.2
529function StringAnchor(name) {
530  CHECK_OBJECT_COERCIBLE(this, "String.prototype.anchor");
531  return "<a name=\"" + HtmlEscape(name) + "\">" + TO_STRING(this) +
532         "</a>";
533}
534
535
536// ES6 draft, revision 26 (2014-07-18), section B.2.3.3
537function StringBig() {
538  CHECK_OBJECT_COERCIBLE(this, "String.prototype.big");
539  return "<big>" + TO_STRING(this) + "</big>";
540}
541
542
543// ES6 draft, revision 26 (2014-07-18), section B.2.3.4
544function StringBlink() {
545  CHECK_OBJECT_COERCIBLE(this, "String.prototype.blink");
546  return "<blink>" + TO_STRING(this) + "</blink>";
547}
548
549
550// ES6 draft, revision 26 (2014-07-18), section B.2.3.5
551function StringBold() {
552  CHECK_OBJECT_COERCIBLE(this, "String.prototype.bold");
553  return "<b>" + TO_STRING(this) + "</b>";
554}
555
556
557// ES6 draft, revision 26 (2014-07-18), section B.2.3.6
558function StringFixed() {
559  CHECK_OBJECT_COERCIBLE(this, "String.prototype.fixed");
560  return "<tt>" + TO_STRING(this) + "</tt>";
561}
562
563
564// ES6 draft, revision 26 (2014-07-18), section B.2.3.7
565function StringFontcolor(color) {
566  CHECK_OBJECT_COERCIBLE(this, "String.prototype.fontcolor");
567  return "<font color=\"" + HtmlEscape(color) + "\">" + TO_STRING(this) +
568         "</font>";
569}
570
571
572// ES6 draft, revision 26 (2014-07-18), section B.2.3.8
573function StringFontsize(size) {
574  CHECK_OBJECT_COERCIBLE(this, "String.prototype.fontsize");
575  return "<font size=\"" + HtmlEscape(size) + "\">" + TO_STRING(this) +
576         "</font>";
577}
578
579
580// ES6 draft, revision 26 (2014-07-18), section B.2.3.9
581function StringItalics() {
582  CHECK_OBJECT_COERCIBLE(this, "String.prototype.italics");
583  return "<i>" + TO_STRING(this) + "</i>";
584}
585
586
587// ES6 draft, revision 26 (2014-07-18), section B.2.3.10
588function StringLink(s) {
589  CHECK_OBJECT_COERCIBLE(this, "String.prototype.link");
590  return "<a href=\"" + HtmlEscape(s) + "\">" + TO_STRING(this) + "</a>";
591}
592
593
594// ES6 draft, revision 26 (2014-07-18), section B.2.3.11
595function StringSmall() {
596  CHECK_OBJECT_COERCIBLE(this, "String.prototype.small");
597  return "<small>" + TO_STRING(this) + "</small>";
598}
599
600
601// ES6 draft, revision 26 (2014-07-18), section B.2.3.12
602function StringStrike() {
603  CHECK_OBJECT_COERCIBLE(this, "String.prototype.strike");
604  return "<strike>" + TO_STRING(this) + "</strike>";
605}
606
607
608// ES6 draft, revision 26 (2014-07-18), section B.2.3.13
609function StringSub() {
610  CHECK_OBJECT_COERCIBLE(this, "String.prototype.sub");
611  return "<sub>" + TO_STRING(this) + "</sub>";
612}
613
614
615// ES6 draft, revision 26 (2014-07-18), section B.2.3.14
616function StringSup() {
617  CHECK_OBJECT_COERCIBLE(this, "String.prototype.sup");
618  return "<sup>" + TO_STRING(this) + "</sup>";
619}
620
621// ES6, section 21.1.3.13
622function StringRepeat(count) {
623  CHECK_OBJECT_COERCIBLE(this, "String.prototype.repeat");
624
625  var s = TO_STRING(this);
626  var n = TO_INTEGER(count);
627
628  if (n < 0 || n === INFINITY) throw MakeRangeError(kInvalidCountValue);
629
630  // Early return to allow an arbitrarily-large repeat of the empty string.
631  if (s.length === 0) return "";
632
633  // The maximum string length is stored in a smi, so a longer repeat
634  // must result in a range error.
635  if (n > %_MaxSmi()) throw MakeRangeError(kInvalidCountValue);
636
637  var r = "";
638  while (true) {
639    if (n & 1) r += s;
640    n >>= 1;
641    if (n === 0) return r;
642    s += s;
643  }
644}
645
646
647// ES6 draft 04-05-14, section 21.1.3.18
648function StringStartsWith(searchString, position) {  // length == 1
649  CHECK_OBJECT_COERCIBLE(this, "String.prototype.startsWith");
650
651  var s = TO_STRING(this);
652
653  if (IsRegExp(searchString)) {
654    throw MakeTypeError(kFirstArgumentNotRegExp, "String.prototype.startsWith");
655  }
656
657  var ss = TO_STRING(searchString);
658  var pos = TO_INTEGER(position);
659
660  var s_len = s.length;
661  var start = MinSimple(MaxSimple(pos, 0), s_len);
662  var ss_len = ss.length;
663  if (ss_len + start > s_len) {
664    return false;
665  }
666
667  return %_SubString(s, start, start + ss_len) === ss;
668}
669
670%FunctionSetLength(StringStartsWith, 1);
671
672
673// ES6 draft 04-05-14, section 21.1.3.7
674function StringEndsWith(searchString, position) {  // length == 1
675  CHECK_OBJECT_COERCIBLE(this, "String.prototype.endsWith");
676
677  var s = TO_STRING(this);
678
679  if (IsRegExp(searchString)) {
680    throw MakeTypeError(kFirstArgumentNotRegExp, "String.prototype.endsWith");
681  }
682
683  var ss = TO_STRING(searchString);
684  var s_len = s.length;
685  var pos = !IS_UNDEFINED(position) ? TO_INTEGER(position) : s_len
686
687  var end = MinSimple(MaxSimple(pos, 0), s_len);
688  var ss_len = ss.length;
689  var start = end - ss_len;
690  if (start < 0) {
691    return false;
692  }
693
694  return %_SubString(s, start, start + ss_len) === ss;
695}
696
697%FunctionSetLength(StringEndsWith, 1);
698
699
700// ES6 draft 04-05-14, section 21.1.3.6
701function StringIncludes(searchString, position) {  // length == 1
702  CHECK_OBJECT_COERCIBLE(this, "String.prototype.includes");
703
704  var string = TO_STRING(this);
705
706  if (IsRegExp(searchString)) {
707    throw MakeTypeError(kFirstArgumentNotRegExp, "String.prototype.includes");
708  }
709
710  searchString = TO_STRING(searchString);
711  var pos = TO_INTEGER(position);
712
713  var stringLength = string.length;
714  if (pos < 0) pos = 0;
715  if (pos > stringLength) pos = stringLength;
716  var searchStringLength = searchString.length;
717
718  if (searchStringLength + pos > stringLength) {
719    return false;
720  }
721
722  return %StringIndexOf(string, searchString, pos) !== -1;
723}
724
725%FunctionSetLength(StringIncludes, 1);
726
727
728// ES6 Draft 05-22-2014, section 21.1.3.3
729function StringCodePointAt(pos) {
730  CHECK_OBJECT_COERCIBLE(this, "String.prototype.codePointAt");
731
732  var string = TO_STRING(this);
733  var size = string.length;
734  pos = TO_INTEGER(pos);
735  if (pos < 0 || pos >= size) {
736    return UNDEFINED;
737  }
738  var first = %_StringCharCodeAt(string, pos);
739  if (first < 0xD800 || first > 0xDBFF || pos + 1 == size) {
740    return first;
741  }
742  var second = %_StringCharCodeAt(string, pos + 1);
743  if (second < 0xDC00 || second > 0xDFFF) {
744    return first;
745  }
746  return (first - 0xD800) * 0x400 + second + 0x2400;
747}
748
749
750// -------------------------------------------------------------------
751// String methods related to templates
752
753// ES6 Draft 03-17-2015, section 21.1.2.4
754function StringRaw(callSite) {
755  "use strict";
756  var numberOfSubstitutions = arguments.length;
757  var cooked = TO_OBJECT(callSite);
758  var raw = TO_OBJECT(cooked.raw);
759  var literalSegments = TO_LENGTH(raw.length);
760  if (literalSegments <= 0) return "";
761
762  var result = TO_STRING(raw[0]);
763
764  for (var i = 1; i < literalSegments; ++i) {
765    if (i < numberOfSubstitutions) {
766      result += TO_STRING(arguments[i]);
767    }
768    result += TO_STRING(raw[i]);
769  }
770
771  return result;
772}
773
774// -------------------------------------------------------------------
775
776// Set up the non-enumerable functions on the String object.
777utils.InstallFunctions(GlobalString, DONT_ENUM, [
778  "raw", StringRaw
779]);
780
781// Set up the non-enumerable functions on the String prototype object.
782utils.InstallFunctions(GlobalString.prototype, DONT_ENUM, [
783  "valueOf", StringValueOf,
784  "toString", StringToString,
785  "codePointAt", StringCodePointAt,
786  "concat", StringConcat,
787  "endsWith", StringEndsWith,
788  "includes", StringIncludes,
789  "indexOf", StringIndexOf,
790  "lastIndexOf", StringLastIndexOf,
791  "localeCompare", StringLocaleCompareJS,
792  "match", StringMatchJS,
793  "normalize", StringNormalize,
794  "repeat", StringRepeat,
795  "replace", StringReplace,
796  "search", StringSearch,
797  "slice", StringSlice,
798  "split", StringSplitJS,
799  "substring", StringSubstring,
800  "substr", StringSubstr,
801  "startsWith", StringStartsWith,
802  "toLowerCase", StringToLowerCaseJS,
803  "toLocaleLowerCase", StringToLocaleLowerCase,
804  "toUpperCase", StringToUpperCaseJS,
805  "toLocaleUpperCase", StringToLocaleUpperCase,
806
807  "link", StringLink,
808  "anchor", StringAnchor,
809  "fontcolor", StringFontcolor,
810  "fontsize", StringFontsize,
811  "big", StringBig,
812  "blink", StringBlink,
813  "bold", StringBold,
814  "fixed", StringFixed,
815  "italics", StringItalics,
816  "small", StringSmall,
817  "strike", StringStrike,
818  "sub", StringSub,
819  "sup", StringSup
820]);
821
822// -------------------------------------------------------------------
823// Exports
824
825utils.Export(function(to) {
826  to.ExpandReplacement = ExpandReplacement;
827  to.StringIndexOf = StringIndexOf;
828  to.StringLastIndexOf = StringLastIndexOf;
829  to.StringMatch = StringMatchJS;
830  to.StringReplace = StringReplace;
831  to.StringSlice = StringSlice;
832  to.StringSplit = StringSplitJS;
833  to.StringSubstr = StringSubstr;
834  to.StringSubstring = StringSubstring;
835});
836
837})
838