blob: 64b2610d06b274262fd817f03ac5123461473799 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000028// This file relies on the fact that the following declarations have been made
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000029//
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000030// in runtime.js:
31// const $Object = global.Object;
32// const $Boolean = global.Boolean;
33// const $Number = global.Number;
34// const $Function = global.Function;
35// const $Array = global.Array;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000036// const $NaN = 0/0;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000037//
38// in math.js:
39// const $floor = MathFloor
40
41const $isNaN = GlobalIsNaN;
42const $isFinite = GlobalIsFinite;
43
44// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045
46
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000047// Helper function used to install functions on objects.
48function InstallFunctions(object, attributes, functions) {
49 for (var i = 0; i < functions.length; i += 2) {
50 var key = functions[i];
51 var f = functions[i + 1];
52 %FunctionSetName(f, key);
53 %SetProperty(object, key, f, attributes);
54 }
55}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056
57
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000058// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059
60
61// ECMA 262 - 15.1.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000062function GlobalIsNaN(number) {
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +000063 var n = ToNumber(number);
64 return NUMBER_IS_NAN(n);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000065}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000066
67
68// ECMA 262 - 15.1.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000069function GlobalIsFinite(number) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000070 return %NumberIsFinite(ToNumber(number));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000071}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072
73
74// ECMA-262 - 15.1.2.2
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000075function GlobalParseInt(string, radix) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000076 if (radix === void 0) {
77 radix = 0;
78 // Some people use parseInt instead of Math.floor. This
79 // optimization makes parseInt on a Smi 12 times faster (60ns
80 // vs 800ns). The following optimization makes parseInt on a
81 // non-Smi number 9 times faster (230ns vs 2070ns). Together
82 // they make parseInt on a string 1.4% slower (274ns vs 270ns).
83 if (%_IsSmi(string)) return string;
84 if (IS_NUMBER(string)) {
85 if (string >= 0.01 && string < 1e9)
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000086 return $floor(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000087 if (string <= -0.01 && string > -1e9)
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000088 return - $floor(-string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000089 }
90 } else {
91 radix = TO_INT32(radix);
92 if (!(radix == 0 || (2 <= radix && radix <= 36)))
93 return $NaN;
94 }
95 return %StringParseInt(ToString(string), radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +000096}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097
98
99// ECMA-262 - 15.1.2.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000100function GlobalParseFloat(string) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101 return %StringParseFloat(ToString(string));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000102}
103
104
105function GlobalEval(x) {
106 if (!IS_STRING(x)) return x;
107
108 var f = %CompileString(x, 0, true);
109 if (!IS_FUNCTION(f)) return f;
110
111 return f.call(%EvalReceiver(this));
112}
113
114
115// execScript for IE compatibility.
116function GlobalExecScript(expr, lang) {
117 // NOTE: We don't care about the character casing.
118 if (!lang || /javascript/i.test(lang)) {
119 var f = %CompileString(ToString(expr), 0, false);
120 f.call(global);
121 }
122 return null;
123}
124
125
126// ----------------------------------------------------------------------------
127
128
129function SetupGlobal() {
130 // ECMA 262 - 15.1.1.1.
131 %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
132
133 // ECMA-262 - 15.1.1.2.
134 %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE);
135
136 // ECMA-262 - 15.1.1.3.
137 %SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
138
139 // Setup non-enumerable function on the global object.
140 InstallFunctions(global, DONT_ENUM, $Array(
141 "isNaN", GlobalIsNaN,
142 "isFinite", GlobalIsFinite,
143 "parseInt", GlobalParseInt,
144 "parseFloat", GlobalParseFloat,
145 "eval", GlobalEval,
146 "execScript", GlobalExecScript
147 ));
148}
149
150SetupGlobal();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000151
152
153// ----------------------------------------------------------------------------
154// Boolean (first part of definition)
155
156
157%SetCode($Boolean, function(x) {
mads.s.ager31e71382008-08-13 09:32:07 +0000158 if (%IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000159 %_SetValueOf(this, ToBoolean(x));
160 } else {
161 return ToBoolean(x);
162 }
163});
164
165%FunctionSetPrototype($Boolean, new $Boolean(false));
166
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000167%SetProperty($Boolean.prototype, "constructor", $Boolean, DONT_ENUM);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000168
169// ----------------------------------------------------------------------------
170// Object
171
172$Object.prototype.constructor = $Object;
173
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000174// ECMA-262 - 15.2.4.2
175function ObjectToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000176 var c = %ClassOf(this);
177 // Hide Arguments from the outside.
178 if (c === 'Arguments') c = 'Object';
179 return "[object " + c + "]";
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000180}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000181
182
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000183// ECMA-262 - 15.2.4.3
184function ObjectToLocaleString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000185 return this.toString();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000186}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000187
188
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000189// ECMA-262 - 15.2.4.4
190function ObjectValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000191 return this;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000192}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000193
194
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000195// ECMA-262 - 15.2.4.5
196function ObjectHasOwnProperty(V) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000197 return %HasLocalProperty(ToObject(this), ToString(V));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000198}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000199
200
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000201// ECMA-262 - 15.2.4.6
202function ObjectIsPrototypeOf(V) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000203 if (!IS_OBJECT(V) && !IS_FUNCTION(V)) return false;
204 return %IsInPrototypeChain(this, V);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000205}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000206
207
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000208// ECMA-262 - 15.2.4.6
209function ObjectPropertyIsEnumerable(V) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000210 if (this == null) return false;
211 if (!IS_OBJECT(this) && !IS_FUNCTION(this)) return false;
212 return %IsPropertyEnumerable(this, ToString(V));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000213}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000214
215
216// Extensions for providing property getters and setters.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000217function ObjectDefineGetter(name, fun) {
218 if (this == null) {
219 throw new $TypeError('Object.prototype.__defineGetter__: this is Null');
220 }
221 if (!IS_FUNCTION(fun)) {
222 throw new $TypeError('Object.prototype.__defineGetter__: Expecting function');
223 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000224 return %DefineAccessor(ToObject(this), ToString(name), GETTER, fun);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000225}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000226
227
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000228function ObjectLookupGetter(name) {
229 if (this == null) {
230 throw new $TypeError('Object.prototype.__lookupGetter__: this is Null');
231 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000232 return %LookupAccessor(ToObject(this), ToString(name), GETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000233}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000234
235
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000236function ObjectDefineSetter(name, fun) {
237 if (this == null) {
238 throw new $TypeError('Object.prototype.__defineSetter__: this is Null');
239 }
240 if (!IS_FUNCTION(fun)) {
241 throw new $TypeError(
242 'Object.prototype.__defineSetter__: Expecting function');
243 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000244 return %DefineAccessor(ToObject(this), ToString(name), SETTER, fun);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000245}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000246
247
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000248function ObjectLookupSetter(name) {
249 if (this == null) {
250 throw new $TypeError('Object.prototype.__lookupSetter__: this is Null');
251 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000252 return %LookupAccessor(ToObject(this), ToString(name), SETTER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000253}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000254
255
256%SetCode($Object, function(x) {
mads.s.ager31e71382008-08-13 09:32:07 +0000257 if (%IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000258 if (x == null) return this;
259 return ToObject(x);
260 } else {
261 if (x == null) return { };
262 return ToObject(x);
263 }
264});
265
266
267// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000268
269
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000270function SetupObject() {
271 // Setup non-enumerable functions on the Object.prototype object.
272 InstallFunctions($Object.prototype, DONT_ENUM, $Array(
273 "toString", ObjectToString,
274 "toLocaleString", ObjectToLocaleString,
275 "valueOf", ObjectValueOf,
276 "hasOwnProperty", ObjectHasOwnProperty,
277 "isPrototypeOf", ObjectIsPrototypeOf,
278 "propertyIsEnumerable", ObjectPropertyIsEnumerable,
279 "__defineGetter__", ObjectDefineGetter,
280 "__lookupGetter__", ObjectLookupGetter,
281 "__defineSetter__", ObjectDefineSetter,
282 "__lookupSetter__", ObjectLookupSetter
283 ));
284}
285
286SetupObject();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000287
288
289// ----------------------------------------------------------------------------
290// Boolean
291
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000292function BooleanToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000293 // NOTE: Both Boolean objects and values can enter here as
294 // 'this'. This is not as dictated by ECMA-262.
295 if (!IS_BOOLEAN(this) && %ClassOf(this) !== 'Boolean')
296 throw new $TypeError('Boolean.prototype.toString is not generic');
297 return ToString(%_ValueOf(this));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000298}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000299
300
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000301function BooleanValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000302 // NOTE: Both Boolean objects and values can enter here as
303 // 'this'. This is not as dictated by ECMA-262.
304 if (!IS_BOOLEAN(this) && %ClassOf(this) !== 'Boolean')
305 throw new $TypeError('Boolean.prototype.valueOf is not generic');
306 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000307}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000308
309
310// ----------------------------------------------------------------------------
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000311
312
313function SetupBoolean() {
314 InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
315 "toString", BooleanToString,
316 "valueOf", BooleanValueOf
317 ));
318}
319
320SetupBoolean();
321
322// ----------------------------------------------------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000323// Number
324
325// Set the Number function and constructor.
326%SetCode($Number, function(x) {
327 var value = %_ArgumentsLength() == 0 ? 0 : ToNumber(x);
mads.s.ager31e71382008-08-13 09:32:07 +0000328 if (%IsConstructCall()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000329 %_SetValueOf(this, value);
330 } else {
331 return value;
332 }
333});
334
335%FunctionSetPrototype($Number, new $Number(0));
336
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000337// ECMA-262 section 15.7.4.2.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000338function NumberToString(radix) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339 // NOTE: Both Number objects and values can enter here as
340 // 'this'. This is not as dictated by ECMA-262.
341 var number = this;
342 if (!IS_NUMBER(this)) {
343 if (%ClassOf(this) !== 'Number')
344 throw new $TypeError('Number.prototype.toString is not generic');
345 // Get the value of this number in case it's an object.
346 number = %_ValueOf(this);
347 }
348 // Fast case: Convert number in radix 10.
349 if (IS_UNDEFINED(radix) || radix === 10) {
350 return ToString(number);
351 }
352
353 // Convert the radix to an integer and check the range.
354 radix = TO_INTEGER(radix);
355 if (radix < 2 || radix > 36) {
356 throw new $RangeError('toString() radix argument must be between 2 and 36');
357 }
358 // Convert the number to a string in the given radix.
359 return %NumberToRadixString(number, radix);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000360}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361
362
363// ECMA-262 section 15.7.4.3
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000364function NumberToLocaleString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000365 return this.toString();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000366}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367
368
369// ECMA-262 section 15.7.4.4
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000370function NumberValueOf() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000371 // NOTE: Both Number objects and values can enter here as
372 // 'this'. This is not as dictated by ECMA-262.
373 if (!IS_NUMBER(this) && %ClassOf(this) !== 'Number')
374 throw new $TypeError('Number.prototype.valueOf is not generic');
375 return %_ValueOf(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000376}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000377
378
379// ECMA-262 section 15.7.4.5
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000380function NumberToFixed(fractionDigits) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381 var f = TO_INTEGER(fractionDigits);
382 if (f < 0 || f > 20) {
383 throw new $RangeError("toFixed() digits argument must be between 0 and 20");
384 }
385 var x = ToNumber(this);
386 return %NumberToFixed(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000387}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000388
389
390// ECMA-262 section 15.7.4.6
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000391function NumberToExponential(fractionDigits) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000392 var f = -1;
393 if (!IS_UNDEFINED(fractionDigits)) {
394 f = TO_INTEGER(fractionDigits);
395 if (f < 0 || f > 20) {
396 throw new $RangeError("toExponential() argument must be between 0 and 20");
397 }
398 }
399 var x = ToNumber(this);
400 return %NumberToExponential(x, f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000401}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000402
403
404// ECMA-262 section 15.7.4.7
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000405function NumberToPrecision(precision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000406 if (IS_UNDEFINED(precision)) return ToString(%_ValueOf(this));
407 var p = TO_INTEGER(precision);
408 if (p < 1 || p > 21) {
409 throw new $RangeError("toPrecision() argument must be between 1 and 21");
410 }
411 var x = ToNumber(this);
412 return %NumberToPrecision(x, p);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000413}
414
415
416// ----------------------------------------------------------------------------
417
418function SetupNumber() {
419 // Setup the constructor property on the Number prototype object.
420 %SetProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
421
422 // ECMA-262 section 15.7.3.1.
423 %SetProperty($Number,
424 "MAX_VALUE",
425 1.7976931348623157e+308,
426 DONT_ENUM | DONT_DELETE | READ_ONLY);
427
428 // ECMA-262 section 15.7.3.2.
429 %SetProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY);
430
431 // ECMA-262 section 15.7.3.3.
432 %SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
433
434 // ECMA-262 section 15.7.3.4.
435 %SetProperty($Number,
436 "NEGATIVE_INFINITY",
437 -1/0,
438 DONT_ENUM | DONT_DELETE | READ_ONLY);
439
440 // ECMA-262 section 15.7.3.5.
441 %SetProperty($Number,
442 "POSITIVE_INFINITY",
443 1/0,
444 DONT_ENUM | DONT_DELETE | READ_ONLY);
445
446 // Setup non-enumerable functions on the Number prototype object.
447 InstallFunctions($Number.prototype, DONT_ENUM, $Array(
448 "toString", NumberToString,
449 "toLocaleString", NumberToLocaleString,
450 "valueOf", NumberValueOf,
451 "toFixed", NumberToFixed,
452 "toExponential", NumberToExponential,
453 "toPrecision", NumberToPrecision
454 ));
455}
456
457SetupNumber();
458
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000459
460
461// ----------------------------------------------------------------------------
462// Function
463
464$Function.prototype.constructor = $Function;
465
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000466function FunctionSourceString(func) {
467 // NOTE: Both Function objects and values can enter here as
468 // 'func'. This is not as dictated by ECMA-262.
469 if (!IS_FUNCTION(func) && %ClassOf(func) != 'Function')
470 throw new $TypeError('Function.prototype.toString is not generic');
471
472 var source = %FunctionGetSourceCode(func);
473 if (!IS_STRING(source)) {
474 var name = %FunctionGetName(func);
475 if (name) {
476 // Mimic what KJS does.
477 return 'function ' + name + '() { [native code] }';
478 } else {
479 return 'function () { [native code] }';
480 }
481 }
482
483 // Censor occurrences of internal calls. We do that for all
484 // functions and don't cache under the assumption that people rarly
485 // convert functions to strings. Note that we (apparently) can't
486 // use regular expression literals in natives files.
487 var regexp = ORIGINAL_REGEXP("%(\\w+\\()", "gm");
488 if (source.match(regexp)) source = source.replace(regexp, "$1");
489 var name = %FunctionGetName(func);
490 return 'function ' + name + source;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000491}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000492
493
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000494function FunctionToString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000495 return FunctionSourceString(this);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000496}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000497
498
499function NewFunction(arg1) { // length == 1
500 var n = %_ArgumentsLength();
501 var p = '';
502 if (n > 1) {
503 p = new $Array(n - 1);
504 // Explicitly convert all parameters to strings.
505 // Array.prototype.join replaces null with empty strings which is
506 // not appropriate.
507 for (var i = 0; i < n - 1; i++) p[i] = ToString(%_Arguments(i));
508 p = p.join(',');
509 // If the formal parameters string include ) - an illegal
510 // character - it may make the combined function expression
511 // compile. We avoid this problem by checking for this early on.
512 if (p.indexOf(')') != -1) throw MakeSyntaxError('unable_to_parse',[]);
513 }
514 var body = (n > 0) ? ToString(%_Arguments(n - 1)) : '';
ager@chromium.org236ad962008-09-25 09:45:57 +0000515 var source = '(function(' + p + ') {\n' + body + '\n})';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000516
517 // The call to SetNewFunctionAttributes will ensure the prototype
518 // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
ager@chromium.org236ad962008-09-25 09:45:57 +0000519 var f = %CompileString(source, -1, false)();
520 %FunctionSetName(f, "anonymous");
521 return %SetNewFunctionAttributes(f);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000522}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000523
524%SetCode($Function, NewFunction);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000525
526// ----------------------------------------------------------------------------
527
528function SetupFunction() {
529 InstallFunctions($Function.prototype, DONT_ENUM, $Array(
530 "toString", FunctionToString
531 ));
532}
533
534SetupFunction();
535