1// Copyright 2014 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'use strict';
6
7// This file relies on the fact that the following declaration has been made
8// in runtime.js:
9// var $String = global.String;
10// var $Array = global.Array;
11
12// -------------------------------------------------------------------
13
14// ES6 draft 01-20-14, section 21.1.3.13
15function StringRepeat(count) {
16  CHECK_OBJECT_COERCIBLE(this, "String.prototype.repeat");
17
18  var s = TO_STRING_INLINE(this);
19  var n = ToInteger(count);
20  if (n < 0 || !NUMBER_IS_FINITE(n)) {
21    throw MakeRangeError("invalid_count_value", []);
22  }
23
24  var elements = new InternalArray(n);
25  for (var i = 0; i < n; i++) {
26    elements[i] = s;
27  }
28
29  return %StringBuilderConcat(elements, n, "");
30}
31
32
33// ES6 draft 04-05-14, section 21.1.3.18
34function StringStartsWith(searchString /* position */) {  // length == 1
35  CHECK_OBJECT_COERCIBLE(this, "String.prototype.startsWith");
36
37  var s = TO_STRING_INLINE(this);
38
39  if (IS_REGEXP(searchString)) {
40    throw MakeTypeError("first_argument_not_regexp",
41                        ["String.prototype.startsWith"]);
42  }
43
44  var ss = TO_STRING_INLINE(searchString);
45  var pos = 0;
46  if (%_ArgumentsLength() > 1) {
47    pos = %_Arguments(1);  // position
48    pos = ToInteger(pos);
49  }
50
51  var s_len = s.length;
52  var start = MathMin(MathMax(pos, 0), s_len);
53  var ss_len = ss.length;
54  if (ss_len + start > s_len) {
55    return false;
56  }
57
58  return %StringIndexOf(s, ss, start) === start;
59}
60
61
62// ES6 draft 04-05-14, section 21.1.3.7
63function StringEndsWith(searchString /* position */) {  // length == 1
64  CHECK_OBJECT_COERCIBLE(this, "String.prototype.endsWith");
65
66  var s = TO_STRING_INLINE(this);
67
68  if (IS_REGEXP(searchString)) {
69    throw MakeTypeError("first_argument_not_regexp",
70                        ["String.prototype.endsWith"]);
71  }
72
73  var ss = TO_STRING_INLINE(searchString);
74  var s_len = s.length;
75  var pos = s_len;
76  if (%_ArgumentsLength() > 1) {
77    var arg = %_Arguments(1);  // position
78    if (!IS_UNDEFINED(arg)) {
79      pos = ToInteger(arg);
80    }
81  }
82
83  var end = MathMin(MathMax(pos, 0), s_len);
84  var ss_len = ss.length;
85  var start = end - ss_len;
86  if (start < 0) {
87    return false;
88  }
89
90  return %StringLastIndexOf(s, ss, start) === start;
91}
92
93
94// ES6 draft 04-05-14, section 21.1.3.6
95function StringContains(searchString /* position */) {  // length == 1
96  CHECK_OBJECT_COERCIBLE(this, "String.prototype.contains");
97
98  var s = TO_STRING_INLINE(this);
99
100  if (IS_REGEXP(searchString)) {
101    throw MakeTypeError("first_argument_not_regexp",
102                        ["String.prototype.contains"]);
103  }
104
105  var ss = TO_STRING_INLINE(searchString);
106  var pos = 0;
107  if (%_ArgumentsLength() > 1) {
108    pos = %_Arguments(1);  // position
109    pos = ToInteger(pos);
110  }
111
112  var s_len = s.length;
113  var start = MathMin(MathMax(pos, 0), s_len);
114  var ss_len = ss.length;
115  if (ss_len + start > s_len) {
116    return false;
117  }
118
119  return %StringIndexOf(s, ss, start) !== -1;
120}
121
122
123// -------------------------------------------------------------------
124
125function ExtendStringPrototype() {
126  %CheckIsBootstrapping();
127
128  // Set up the non-enumerable functions on the String prototype object.
129  InstallFunctions($String.prototype, DONT_ENUM, $Array(
130    "repeat", StringRepeat,
131    "startsWith", StringStartsWith,
132    "endsWith", StringEndsWith,
133    "contains", StringContains
134  ));
135}
136
137ExtendStringPrototype();
138