blob: 6bbe139e87a3a2e96227799fea537261e9f87b51 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005"use strict";
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006
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);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040020 // The maximum string length is stored in a smi, so a longer repeat
21 // must result in a range error.
22 if (n < 0 || n > %_MaxSmi()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023 throw MakeRangeError("invalid_count_value", []);
24 }
25
Emily Bernierd0a1eb72015-03-24 16:35:39 -040026 var r = "";
27 while (true) {
28 if (n & 1) r += s;
29 n >>= 1;
30 if (n === 0) return r;
31 s += s;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000033}
34
35
36// ES6 draft 04-05-14, section 21.1.3.18
37function StringStartsWith(searchString /* position */) { // length == 1
38 CHECK_OBJECT_COERCIBLE(this, "String.prototype.startsWith");
39
40 var s = TO_STRING_INLINE(this);
41
42 if (IS_REGEXP(searchString)) {
43 throw MakeTypeError("first_argument_not_regexp",
44 ["String.prototype.startsWith"]);
45 }
46
47 var ss = TO_STRING_INLINE(searchString);
48 var pos = 0;
49 if (%_ArgumentsLength() > 1) {
50 pos = %_Arguments(1); // position
51 pos = ToInteger(pos);
52 }
53
54 var s_len = s.length;
55 var start = MathMin(MathMax(pos, 0), s_len);
56 var ss_len = ss.length;
57 if (ss_len + start > s_len) {
58 return false;
59 }
60
61 return %StringIndexOf(s, ss, start) === start;
62}
63
64
65// ES6 draft 04-05-14, section 21.1.3.7
66function StringEndsWith(searchString /* position */) { // length == 1
67 CHECK_OBJECT_COERCIBLE(this, "String.prototype.endsWith");
68
69 var s = TO_STRING_INLINE(this);
70
71 if (IS_REGEXP(searchString)) {
72 throw MakeTypeError("first_argument_not_regexp",
73 ["String.prototype.endsWith"]);
74 }
75
76 var ss = TO_STRING_INLINE(searchString);
77 var s_len = s.length;
78 var pos = s_len;
79 if (%_ArgumentsLength() > 1) {
80 var arg = %_Arguments(1); // position
81 if (!IS_UNDEFINED(arg)) {
82 pos = ToInteger(arg);
83 }
84 }
85
86 var end = MathMin(MathMax(pos, 0), s_len);
87 var ss_len = ss.length;
88 var start = end - ss_len;
89 if (start < 0) {
90 return false;
91 }
92
93 return %StringLastIndexOf(s, ss, start) === start;
94}
95
96
97// ES6 draft 04-05-14, section 21.1.3.6
Emily Bernierd0a1eb72015-03-24 16:35:39 -040098function StringIncludes(searchString /* position */) { // length == 1
99 CHECK_OBJECT_COERCIBLE(this, "String.prototype.includes");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000100
101 var s = TO_STRING_INLINE(this);
102
103 if (IS_REGEXP(searchString)) {
104 throw MakeTypeError("first_argument_not_regexp",
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400105 ["String.prototype.includes"]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000106 }
107
108 var ss = TO_STRING_INLINE(searchString);
109 var pos = 0;
110 if (%_ArgumentsLength() > 1) {
111 pos = %_Arguments(1); // position
112 pos = ToInteger(pos);
113 }
114
115 var s_len = s.length;
116 var start = MathMin(MathMax(pos, 0), s_len);
117 var ss_len = ss.length;
118 if (ss_len + start > s_len) {
119 return false;
120 }
121
122 return %StringIndexOf(s, ss, start) !== -1;
123}
124
125
126// ES6 Draft 05-22-2014, section 21.1.3.3
127function StringCodePointAt(pos) {
128 CHECK_OBJECT_COERCIBLE(this, "String.prototype.codePointAt");
129
130 var string = TO_STRING_INLINE(this);
131 var size = string.length;
132 pos = TO_INTEGER(pos);
133 if (pos < 0 || pos >= size) {
134 return UNDEFINED;
135 }
136 var first = %_StringCharCodeAt(string, pos);
137 if (first < 0xD800 || first > 0xDBFF || pos + 1 == size) {
138 return first;
139 }
140 var second = %_StringCharCodeAt(string, pos + 1);
141 if (second < 0xDC00 || second > 0xDFFF) {
142 return first;
143 }
144 return (first - 0xD800) * 0x400 + second + 0x2400;
145}
146
147
148// ES6 Draft 05-22-2014, section 21.1.2.2
149function StringFromCodePoint(_) { // length = 1
150 var code;
151 var length = %_ArgumentsLength();
152 var index;
153 var result = "";
154 for (index = 0; index < length; index++) {
155 code = %_Arguments(index);
156 if (!%_IsSmi(code)) {
157 code = ToNumber(code);
158 }
159 if (code < 0 || code > 0x10FFFF || code !== TO_INTEGER(code)) {
160 throw MakeRangeError("invalid_code_point", [code]);
161 }
162 if (code <= 0xFFFF) {
163 result += %_StringCharFromCode(code);
164 } else {
165 code -= 0x10000;
166 result += %_StringCharFromCode((code >>> 10) & 0x3FF | 0xD800);
167 result += %_StringCharFromCode(code & 0x3FF | 0xDC00);
168 }
169 }
170 return result;
171}
172
173
174// -------------------------------------------------------------------
175
176function ExtendStringPrototype() {
177 %CheckIsBootstrapping();
178
179 // Set up the non-enumerable functions on the String object.
180 InstallFunctions($String, DONT_ENUM, $Array(
181 "fromCodePoint", StringFromCodePoint
182 ));
183
184 // Set up the non-enumerable functions on the String prototype object.
185 InstallFunctions($String.prototype, DONT_ENUM, $Array(
186 "codePointAt", StringCodePointAt,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400187 "includes", StringIncludes,
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000188 "endsWith", StringEndsWith,
189 "repeat", StringRepeat,
190 "startsWith", StringStartsWith
191 ));
192}
193
194ExtendStringPrototype();