OLD | NEW |
| (Empty) |
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 | |
15 function StringRepeat(count) { | |
16 CHECK_OBJECT_COERCIBLE(this, "String.prototype.repeat"); | |
17 | |
18 var s = TO_STRING_INLINE(this); | |
19 var n = ToInteger(count); | |
20 // 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()) { | |
23 throw MakeRangeError("invalid_count_value", []); | |
24 } | |
25 | |
26 var r = ""; | |
27 while (true) { | |
28 if (n & 1) r += s; | |
29 n >>= 1; | |
30 if (n === 0) return r; | |
31 s += s; | |
32 } | |
33 } | |
34 | |
35 | |
36 // ES6 draft 04-05-14, section 21.1.3.18 | |
37 function 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 = $min($max(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 | |
66 function 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 = $min($max(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 | |
98 function StringIncludes(searchString /* position */) { // length == 1 | |
99 CHECK_OBJECT_COERCIBLE(this, "String.prototype.includes"); | |
100 | |
101 var s = TO_STRING_INLINE(this); | |
102 | |
103 if (IS_REGEXP(searchString)) { | |
104 throw MakeTypeError("first_argument_not_regexp", | |
105 ["String.prototype.includes"]); | |
106 } | |
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 = $min($max(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 | |
127 function 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 | |
149 function 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 | |
176 function 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, | |
187 "includes", StringIncludes, | |
188 "endsWith", StringEndsWith, | |
189 "repeat", StringRepeat, | |
190 "startsWith", StringStartsWith | |
191 )); | |
192 } | |
193 | |
194 ExtendStringPrototype(); | |
OLD | NEW |