[V8] Introduce a QML compilation mode
[profile/ivi/qtjsbackend.git] / src / 3rdparty / v8 / src / messages.js
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // 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
28 // -------------------------------------------------------------------
29 //
30 // If this object gets passed to an error constructor the error will
31 // get an accessor for .message that constructs a descriptive error
32 // message on access.
33 var kAddMessageAccessorsMarker = { };
34
35 // This will be lazily initialized when first needed (and forcibly
36 // overwritten even though it's const).
37 var kMessages = 0;
38
39 function FormatString(format, message) {
40   var args = %MessageGetArguments(message);
41   var result = "";
42   var arg_num = 0;
43   for (var i = 0; i < format.length; i++) {
44     var str = format[i];
45     if (str.length == 2 && %_StringCharCodeAt(str, 0) == 0x25) {
46       // Two-char string starts with "%".
47       var arg_num = (%_StringCharCodeAt(str, 1) - 0x30) >>> 0;
48       if (arg_num < 4) {
49         // str is one of %0, %1, %2 or %3.
50         try {
51           str = ToDetailString(args[arg_num]);
52         } catch (e) {
53           str = "#<error>";
54         }
55       }
56     }
57     result += str;
58   }
59   return result;
60 }
61
62
63 // To check if something is a native error we need to check the
64 // concrete native error types. It is not sufficient to use instanceof
65 // since it possible to create an object that has Error.prototype on
66 // its prototype chain. This is the case for DOMException for example.
67 function IsNativeErrorObject(obj) {
68   switch (%_ClassOf(obj)) {
69     case 'Error':
70     case 'EvalError':
71     case 'RangeError':
72     case 'ReferenceError':
73     case 'SyntaxError':
74     case 'TypeError':
75     case 'URIError':
76       return true;
77   }
78   return false;
79 }
80
81
82 // When formatting internally created error messages, do not
83 // invoke overwritten error toString methods but explicitly use
84 // the error to string method. This is to avoid leaking error
85 // objects between script tags in a browser setting.
86 function ToStringCheckErrorObject(obj) {
87   if (IsNativeErrorObject(obj)) {
88     return %_CallFunction(obj, ErrorToString);
89   } else {
90     return ToString(obj);
91   }
92 }
93
94
95 function ToDetailString(obj) {
96   if (obj != null && IS_OBJECT(obj) && obj.toString === ObjectToString) {
97     var constructor = obj.constructor;
98     if (typeof constructor == "function") {
99       var constructorName = constructor.name;
100       if (IS_STRING(constructorName) && constructorName !== "") {
101         return "#<" + constructorName + ">";
102       }
103     }
104   }
105   return ToStringCheckErrorObject(obj);
106 }
107
108
109 function MakeGenericError(constructor, type, args) {
110   if (IS_UNDEFINED(args)) {
111     args = [];
112   }
113   var e = new constructor(kAddMessageAccessorsMarker);
114   e.type = type;
115   e.arguments = args;
116   return e;
117 }
118
119
120 /**
121  * Set up the Script function and constructor.
122  */
123 %FunctionSetInstanceClassName(Script, 'Script');
124 %SetProperty(Script.prototype, 'constructor', Script,
125              DONT_ENUM | DONT_DELETE | READ_ONLY);
126 %SetCode(Script, function(x) {
127   // Script objects can only be created by the VM.
128   throw new $Error("Not supported");
129 });
130
131
132 // Helper functions; called from the runtime system.
133 function FormatMessage(message) {
134   if (kMessages === 0) {
135     var messagesDictionary = [
136       // Error
137       "cyclic_proto",                 ["Cyclic __proto__ value"],
138       "code_gen_from_strings",        ["Code generation from strings disallowed for this context"],
139       // TypeError
140       "unexpected_token",             ["Unexpected token ", "%0"],
141       "unexpected_token_number",      ["Unexpected number"],
142       "unexpected_token_string",      ["Unexpected string"],
143       "unexpected_token_identifier",  ["Unexpected identifier"],
144       "unexpected_reserved",          ["Unexpected reserved word"],
145       "unexpected_strict_reserved",   ["Unexpected strict mode reserved word"],
146       "unexpected_eos",               ["Unexpected end of input"],
147       "malformed_regexp",             ["Invalid regular expression: /", "%0", "/: ", "%1"],
148       "unterminated_regexp",          ["Invalid regular expression: missing /"],
149       "regexp_flags",                 ["Cannot supply flags when constructing one RegExp from another"],
150       "incompatible_method_receiver", ["Method ", "%0", " called on incompatible receiver ", "%1"],
151       "invalid_lhs_in_assignment",    ["Invalid left-hand side in assignment"],
152       "invalid_lhs_in_for_in",        ["Invalid left-hand side in for-in"],
153       "invalid_lhs_in_postfix_op",    ["Invalid left-hand side expression in postfix operation"],
154       "invalid_lhs_in_prefix_op",     ["Invalid left-hand side expression in prefix operation"],
155       "multiple_defaults_in_switch",  ["More than one default clause in switch statement"],
156       "newline_after_throw",          ["Illegal newline after throw"],
157       "redeclaration",                ["%0", " '", "%1", "' has already been declared"],
158       "no_catch_or_finally",          ["Missing catch or finally after try"],
159       "unknown_label",                ["Undefined label '", "%0", "'"],
160       "uncaught_exception",           ["Uncaught ", "%0"],
161       "stack_trace",                  ["Stack Trace:\n", "%0"],
162       "called_non_callable",          ["%0", " is not a function"],
163       "undefined_method",             ["Object ", "%1", " has no method '", "%0", "'"],
164       "property_not_function",        ["Property '", "%0", "' of object ", "%1", " is not a function"],
165       "cannot_convert_to_primitive",  ["Cannot convert object to primitive value"],
166       "not_constructor",              ["%0", " is not a constructor"],
167       "not_defined",                  ["%0", " is not defined"],
168       "non_object_property_load",     ["Cannot read property '", "%0", "' of ", "%1"],
169       "non_object_property_store",    ["Cannot set property '", "%0", "' of ", "%1"],
170       "non_object_property_call",     ["Cannot call method '", "%0", "' of ", "%1"],
171       "with_expression",              ["%0", " has no properties"],
172       "illegal_invocation",           ["Illegal invocation"],
173       "no_setter_in_callback",        ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"],
174       "apply_non_function",           ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"],
175       "apply_wrong_args",             ["Function.prototype.apply: Arguments list has wrong type"],
176       "invalid_in_operator_use",      ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"],
177       "instanceof_function_expected", ["Expecting a function in instanceof check, but got ", "%0"],
178       "instanceof_nonobject_proto",   ["Function has non-object prototype '", "%0", "' in instanceof check"],
179       "null_to_object",               ["Cannot convert null to object"],
180       "reduce_no_initial",            ["Reduce of empty array with no initial value"],
181       "getter_must_be_callable",      ["Getter must be a function: ", "%0"],
182       "setter_must_be_callable",      ["Setter must be a function: ", "%0"],
183       "value_and_accessor",           ["Invalid property.  A property cannot both have accessors and be writable or have a value, ", "%0"],
184       "proto_object_or_null",         ["Object prototype may only be an Object or null"],
185       "property_desc_object",         ["Property description must be an object: ", "%0"],
186       "redefine_disallowed",          ["Cannot redefine property: ", "%0"],
187       "define_disallowed",            ["Cannot define property:", "%0", ", object is not extensible."],
188       "non_extensible_proto",         ["%0", " is not extensible"],
189       "handler_non_object",           ["Proxy.", "%0", " called with non-object as handler"],
190       "proto_non_object",             ["Proxy.", "%0", " called with non-object as prototype"],
191       "trap_function_expected",       ["Proxy.", "%0", " called with non-function for '", "%1", "' trap"],
192       "handler_trap_missing",         ["Proxy handler ", "%0", " has no '", "%1", "' trap"],
193       "handler_trap_must_be_callable", ["Proxy handler ", "%0", " has non-callable '", "%1", "' trap"],
194       "handler_returned_false",       ["Proxy handler ", "%0", " returned false from '", "%1", "' trap"],
195       "handler_returned_undefined",   ["Proxy handler ", "%0", " returned undefined from '", "%1", "' trap"],
196       "proxy_prop_not_configurable",  ["Proxy handler ", "%0", " returned non-configurable descriptor for property '", "%2", "' from '", "%1", "' trap"],
197       "proxy_non_object_prop_names",  ["Trap '", "%1", "' returned non-object ", "%0"],
198       "proxy_repeated_prop_name",     ["Trap '", "%1", "' returned repeated property name '", "%2", "'"],
199       "invalid_weakmap_key",          ["Invalid value used as weak map key"],
200       // RangeError
201       "invalid_array_length",         ["Invalid array length"],
202       "stack_overflow",               ["Maximum call stack size exceeded"],
203       "invalid_time_value",           ["Invalid time value"],
204       // SyntaxError
205       "unable_to_parse",              ["Parse error"],
206       "invalid_regexp_flags",         ["Invalid flags supplied to RegExp constructor '", "%0", "'"],
207       "invalid_regexp",               ["Invalid RegExp pattern /", "%0", "/"],
208       "illegal_break",                ["Illegal break statement"],
209       "illegal_continue",             ["Illegal continue statement"],
210       "illegal_return",               ["Illegal return statement"],
211       "illegal_let",                  ["Illegal let declaration outside extended mode"],
212       "error_loading_debugger",       ["Error loading debugger"],
213       "no_input_to_regexp",           ["No input to ", "%0"],
214       "invalid_json",                 ["String '", "%0", "' is not valid JSON"],
215       "circular_structure",           ["Converting circular structure to JSON"],
216       "called_on_non_object",         ["%0", " called on non-object"],
217       "called_on_null_or_undefined",  ["%0", " called on null or undefined"],
218       "array_indexof_not_defined",    ["Array.getIndexOf: Argument undefined"],
219       "object_not_extensible",        ["Can't add property ", "%0", ", object is not extensible"],
220       "illegal_access",               ["Illegal access"],
221       "invalid_preparser_data",       ["Invalid preparser data for function ", "%0"],
222       "strict_mode_with",             ["Strict mode code may not include a with statement"],
223       "strict_catch_variable",        ["Catch variable may not be eval or arguments in strict mode"],
224       "too_many_arguments",           ["Too many arguments in function call (only 32766 allowed)"],
225       "too_many_parameters",          ["Too many parameters in function definition (only 32766 allowed)"],
226       "too_many_variables",           ["Too many variables declared (only 32767 allowed)"],
227       "strict_param_name",            ["Parameter name eval or arguments is not allowed in strict mode"],
228       "strict_param_dupe",            ["Strict mode function may not have duplicate parameter names"],
229       "strict_var_name",              ["Variable name may not be eval or arguments in strict mode"],
230       "strict_function_name",         ["Function name may not be eval or arguments in strict mode"],
231       "strict_octal_literal",         ["Octal literals are not allowed in strict mode."],
232       "strict_duplicate_property",    ["Duplicate data property in object literal not allowed in strict mode"],
233       "accessor_data_property",       ["Object literal may not have data and accessor property with the same name"],
234       "accessor_get_set",             ["Object literal may not have multiple get/set accessors with the same name"],
235       "strict_lhs_assignment",        ["Assignment to eval or arguments is not allowed in strict mode"],
236       "strict_lhs_postfix",           ["Postfix increment/decrement may not have eval or arguments operand in strict mode"],
237       "strict_lhs_prefix",            ["Prefix increment/decrement may not have eval or arguments operand in strict mode"],
238       "strict_reserved_word",         ["Use of future reserved word in strict mode"],
239       "strict_delete",                ["Delete of an unqualified identifier in strict mode."],
240       "strict_delete_property",       ["Cannot delete property '", "%0", "' of ", "%1"],
241       "strict_const",                 ["Use of const in strict mode."],
242       "strict_function",              ["In strict mode code, functions can only be declared at top level or immediately within another function." ],
243       "strict_read_only_property",    ["Cannot assign to read only property '", "%0", "' of ", "%1"],
244       "strict_cannot_assign",         ["Cannot assign to read only '", "%0", "' in strict mode"],
245       "strict_poison_pill",           ["'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them"],
246       "strict_caller",                ["Illegal access to a strict mode caller function."],
247       "unprotected_let",              ["Illegal let declaration in unprotected statement context."],
248       "unprotected_const",            ["Illegal const declaration in unprotected statement context."],
249       "cant_prevent_ext_external_array_elements", ["Cannot prevent extension of an object with external array elements"],
250       "redef_external_array_element", ["Cannot redefine a property of an object with external array elements"],
251       "harmony_const_assign",         ["Assignment to constant variable."],
252       "invalid_module_path",          ["Module does not export '", "%0", "', or export is not itself a module"],
253       "module_type_error",            ["Module '", "%0", "' used improperly"],
254     ];
255     var messages = { __proto__ : null };
256     for (var i = 0; i < messagesDictionary.length; i += 2) {
257       var key = messagesDictionary[i];
258       var format = messagesDictionary[i + 1];
259
260       for (var j = 0; j < format.length; j++) {
261         %IgnoreAttributesAndSetProperty(format, %_NumberToString(j), format[j],
262                                         DONT_DELETE | READ_ONLY | DONT_ENUM);
263       }
264       %IgnoreAttributesAndSetProperty(format, 'length', format.length,
265                                       DONT_DELETE | READ_ONLY | DONT_ENUM);
266       %PreventExtensions(format);
267       %IgnoreAttributesAndSetProperty(messages,
268                                       key,
269                                       format,
270                                       DONT_DELETE | DONT_ENUM | READ_ONLY);
271     }
272     %PreventExtensions(messages);
273     %IgnoreAttributesAndSetProperty(builtins, "kMessages",
274                                     messages,
275                                     DONT_DELETE | DONT_ENUM | READ_ONLY);
276   }
277   var message_type = %MessageGetType(message);
278   var format = kMessages[message_type];
279   if (!format) return "<unknown message " + message_type + ">";
280   return FormatString(format, message);
281 }
282
283
284 function GetLineNumber(message) {
285   var start_position = %MessageGetStartPosition(message);
286   if (start_position == -1) return kNoLineNumberInfo;
287   var script = %MessageGetScript(message);
288   var location = script.locationFromPosition(start_position, true);
289   if (location == null) return kNoLineNumberInfo;
290   return location.line + 1;
291 }
292
293
294 // Returns the source code line containing the given source
295 // position, or the empty string if the position is invalid.
296 function GetSourceLine(message) {
297   var script = %MessageGetScript(message);
298   var start_position = %MessageGetStartPosition(message);
299   var location = script.locationFromPosition(start_position, true);
300   if (location == null) return "";
301   location.restrict();
302   return location.sourceText();
303 }
304
305
306 function MakeTypeError(type, args) {
307   return MakeGenericError($TypeError, type, args);
308 }
309
310
311 function MakeRangeError(type, args) {
312   return MakeGenericError($RangeError, type, args);
313 }
314
315
316 function MakeSyntaxError(type, args) {
317   return MakeGenericError($SyntaxError, type, args);
318 }
319
320
321 function MakeReferenceError(type, args) {
322   return MakeGenericError($ReferenceError, type, args);
323 }
324
325
326 function MakeEvalError(type, args) {
327   return MakeGenericError($EvalError, type, args);
328 }
329
330
331 function MakeError(type, args) {
332   return MakeGenericError($Error, type, args);
333 }
334
335 /**
336  * Find a line number given a specific source position.
337  * @param {number} position The source position.
338  * @return {number} 0 if input too small, -1 if input too large,
339        else the line number.
340  */
341 function ScriptLineFromPosition(position) {
342   var lower = 0;
343   var upper = this.lineCount() - 1;
344   var line_ends = this.line_ends;
345
346   // We'll never find invalid positions so bail right away.
347   if (position > line_ends[upper]) {
348     return -1;
349   }
350
351   // This means we don't have to safe-guard indexing line_ends[i - 1].
352   if (position <= line_ends[0]) {
353     return 0;
354   }
355
356   // Binary search to find line # from position range.
357   while (upper >= 1) {
358     var i = (lower + upper) >> 1;
359
360     if (position > line_ends[i]) {
361       lower = i + 1;
362     } else if (position <= line_ends[i - 1]) {
363       upper = i - 1;
364     } else {
365       return i;
366     }
367   }
368
369   return -1;
370 }
371
372 /**
373  * Get information on a specific source position.
374  * @param {number} position The source position
375  * @param {boolean} include_resource_offset Set to true to have the resource
376  *     offset added to the location
377  * @return {SourceLocation}
378  *     If line is negative or not in the source null is returned.
379  */
380 function ScriptLocationFromPosition(position,
381                                     include_resource_offset) {
382   var line = this.lineFromPosition(position);
383   if (line == -1) return null;
384
385   // Determine start, end and column.
386   var line_ends = this.line_ends;
387   var start = line == 0 ? 0 : line_ends[line - 1] + 1;
388   var end = line_ends[line];
389   if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') {
390     end--;
391   }
392   var column = position - start;
393
394   // Adjust according to the offset within the resource.
395   if (include_resource_offset) {
396     line += this.line_offset;
397     if (line == this.line_offset) {
398       column += this.column_offset;
399     }
400   }
401
402   return new SourceLocation(this, position, line, column, start, end);
403 }
404
405
406 /**
407  * Get information on a specific source line and column possibly offset by a
408  * fixed source position. This function is used to find a source position from
409  * a line and column position. The fixed source position offset is typically
410  * used to find a source position in a function based on a line and column in
411  * the source for the function alone. The offset passed will then be the
412  * start position of the source for the function within the full script source.
413  * @param {number} opt_line The line within the source. Default value is 0
414  * @param {number} opt_column The column in within the line. Default value is 0
415  * @param {number} opt_offset_position The offset from the begining of the
416  *     source from where the line and column calculation starts.
417  *     Default value is 0
418  * @return {SourceLocation}
419  *     If line is negative or not in the source null is returned.
420  */
421 function ScriptLocationFromLine(opt_line, opt_column, opt_offset_position) {
422   // Default is the first line in the script. Lines in the script is relative
423   // to the offset within the resource.
424   var line = 0;
425   if (!IS_UNDEFINED(opt_line)) {
426     line = opt_line - this.line_offset;
427   }
428
429   // Default is first column. If on the first line add the offset within the
430   // resource.
431   var column = opt_column || 0;
432   if (line == 0) {
433     column -= this.column_offset;
434   }
435
436   var offset_position = opt_offset_position || 0;
437   if (line < 0 || column < 0 || offset_position < 0) return null;
438   if (line == 0) {
439     return this.locationFromPosition(offset_position + column, false);
440   } else {
441     // Find the line where the offset position is located.
442     var offset_line = this.lineFromPosition(offset_position);
443
444     if (offset_line == -1 || offset_line + line >= this.lineCount()) {
445       return null;
446     }
447
448     return this.locationFromPosition(
449         this.line_ends[offset_line + line - 1] + 1 + column);  // line > 0 here.
450   }
451 }
452
453
454 /**
455  * Get a slice of source code from the script. The boundaries for the slice is
456  * specified in lines.
457  * @param {number} opt_from_line The first line (zero bound) in the slice.
458  *     Default is 0
459  * @param {number} opt_to_column The last line (zero bound) in the slice (non
460  *     inclusive). Default is the number of lines in the script
461  * @return {SourceSlice} The source slice or null of the parameters where
462  *     invalid
463  */
464 function ScriptSourceSlice(opt_from_line, opt_to_line) {
465   var from_line = IS_UNDEFINED(opt_from_line) ? this.line_offset
466                                               : opt_from_line;
467   var to_line = IS_UNDEFINED(opt_to_line) ? this.line_offset + this.lineCount()
468                                           : opt_to_line;
469
470   // Adjust according to the offset within the resource.
471   from_line -= this.line_offset;
472   to_line -= this.line_offset;
473   if (from_line < 0) from_line = 0;
474   if (to_line > this.lineCount()) to_line = this.lineCount();
475
476   // Check parameters.
477   if (from_line >= this.lineCount() ||
478       to_line < 0 ||
479       from_line > to_line) {
480     return null;
481   }
482
483   var line_ends = this.line_ends;
484   var from_position = from_line == 0 ? 0 : line_ends[from_line - 1] + 1;
485   var to_position = to_line == 0 ? 0 : line_ends[to_line - 1] + 1;
486
487   // Return a source slice with line numbers re-adjusted to the resource.
488   return new SourceSlice(this,
489                          from_line + this.line_offset,
490                          to_line + this.line_offset,
491                           from_position, to_position);
492 }
493
494
495 function ScriptSourceLine(opt_line) {
496   // Default is the first line in the script. Lines in the script are relative
497   // to the offset within the resource.
498   var line = 0;
499   if (!IS_UNDEFINED(opt_line)) {
500     line = opt_line - this.line_offset;
501   }
502
503   // Check parameter.
504   if (line < 0 || this.lineCount() <= line) {
505     return null;
506   }
507
508   // Return the source line.
509   var line_ends = this.line_ends;
510   var start = line == 0 ? 0 : line_ends[line - 1] + 1;
511   var end = line_ends[line];
512   return %_CallFunction(this.source, start, end, StringSubstring);
513 }
514
515
516 /**
517  * Returns the number of source lines.
518  * @return {number}
519  *     Number of source lines.
520  */
521 function ScriptLineCount() {
522   // Return number of source lines.
523   return this.line_ends.length;
524 }
525
526
527 /**
528  * Returns the name of script if available, contents of sourceURL comment
529  * otherwise. See
530  * http://fbug.googlecode.com/svn/branches/firebug1.1/docs/ReleaseNotes_1.1.txt
531  * for details on using //@ sourceURL comment to identify scritps that don't
532  * have name.
533  *
534  * @return {?string} script name if present, value for //@ sourceURL comment
535  * otherwise.
536  */
537 function ScriptNameOrSourceURL() {
538   if (this.name) {
539     return this.name;
540   }
541
542   // The result is cached as on long scripts it takes noticable time to search
543   // for the sourceURL.
544   if (this.hasCachedNameOrSourceURL)
545       return this.cachedNameOrSourceURL;
546   this.hasCachedNameOrSourceURL = true;
547
548   // TODO(608): the spaces in a regexp below had to be escaped as \040
549   // because this file is being processed by js2c whose handling of spaces
550   // in regexps is broken. Also, ['"] are excluded from allowed URLs to
551   // avoid matches against sources that invoke evals with sourceURL.
552   // A better solution would be to detect these special comments in
553   // the scanner/parser.
554   var source = ToString(this.source);
555   var sourceUrlPos = %StringIndexOf(source, "sourceURL=", 0);
556   this.cachedNameOrSourceURL = this.name;
557   if (sourceUrlPos > 4) {
558     var sourceUrlPattern =
559         /\/\/@[\040\t]sourceURL=[\040\t]*([^\s\'\"]*)[\040\t]*$/gm;
560     // Don't reuse lastMatchInfo here, so we create a new array with room
561     // for four captures (array with length one longer than the index
562     // of the fourth capture, where the numbering is zero-based).
563     var matchInfo = new InternalArray(CAPTURE(3) + 1);
564     var match =
565         %_RegExpExec(sourceUrlPattern, source, sourceUrlPos - 4, matchInfo);
566     if (match) {
567       this.cachedNameOrSourceURL =
568           SubString(source, matchInfo[CAPTURE(2)], matchInfo[CAPTURE(3)]);
569     }
570   }
571   return this.cachedNameOrSourceURL;
572 }
573
574
575 SetUpLockedPrototype(Script,
576   $Array("source", "name", "line_ends", "line_offset", "column_offset",
577          "cachedNameOrSourceURL", "hasCachedNameOrSourceURL" ),
578   $Array(
579     "lineFromPosition", ScriptLineFromPosition,
580     "locationFromPosition", ScriptLocationFromPosition,
581     "locationFromLine", ScriptLocationFromLine,
582     "sourceSlice", ScriptSourceSlice,
583     "sourceLine", ScriptSourceLine,
584     "lineCount", ScriptLineCount,
585     "nameOrSourceURL", ScriptNameOrSourceURL
586   )
587 );
588
589
590 /**
591  * Class for source location. A source location is a position within some
592  * source with the following properties:
593  *   script   : script object for the source
594  *   line     : source line number
595  *   column   : source column within the line
596  *   position : position within the source
597  *   start    : position of start of source context (inclusive)
598  *   end      : position of end of source context (not inclusive)
599  * Source text for the source context is the character interval
600  * [start, end[. In most cases end will point to a newline character.
601  * It might point just past the final position of the source if the last
602  * source line does not end with a newline character.
603  * @param {Script} script The Script object for which this is a location
604  * @param {number} position Source position for the location
605  * @param {number} line The line number for the location
606  * @param {number} column The column within the line for the location
607  * @param {number} start Source position for start of source context
608  * @param {number} end Source position for end of source context
609  * @constructor
610  */
611 function SourceLocation(script, position, line, column, start, end) {
612   this.script = script;
613   this.position = position;
614   this.line = line;
615   this.column = column;
616   this.start = start;
617   this.end = end;
618 }
619
620 var kLineLengthLimit = 78;
621
622 /**
623  * Restrict source location start and end positions to make the source slice
624  * no more that a certain number of characters wide.
625  * @param {number} opt_limit The with limit of the source text with a default
626  *     of 78
627  * @param {number} opt_before The number of characters to prefer before the
628  *     position with a default value of 10 less that the limit
629  */
630 function SourceLocationRestrict(opt_limit, opt_before) {
631   // Find the actual limit to use.
632   var limit;
633   var before;
634   if (!IS_UNDEFINED(opt_limit)) {
635     limit = opt_limit;
636   } else {
637     limit = kLineLengthLimit;
638   }
639   if (!IS_UNDEFINED(opt_before)) {
640     before = opt_before;
641   } else {
642     // If no before is specified center for small limits and perfer more source
643     // before the the position that after for longer limits.
644     if (limit <= 20) {
645       before = $floor(limit / 2);
646     } else {
647       before = limit - 10;
648     }
649   }
650   if (before >= limit) {
651     before = limit - 1;
652   }
653
654   // If the [start, end[ interval is too big we restrict
655   // it in one or both ends. We make sure to always produce
656   // restricted intervals of maximum allowed size.
657   if (this.end - this.start > limit) {
658     var start_limit = this.position - before;
659     var end_limit = this.position + limit - before;
660     if (this.start < start_limit && end_limit < this.end) {
661       this.start = start_limit;
662       this.end = end_limit;
663     } else if (this.start < start_limit) {
664       this.start = this.end - limit;
665     } else {
666       this.end = this.start + limit;
667     }
668   }
669 }
670
671
672 /**
673  * Get the source text for a SourceLocation
674  * @return {String}
675  *     Source text for this location.
676  */
677 function SourceLocationSourceText() {
678   return %_CallFunction(this.script.source,
679                         this.start,
680                         this.end,
681                         StringSubstring);
682 }
683
684
685 SetUpLockedPrototype(SourceLocation,
686   $Array("script", "position", "line", "column", "start", "end"),
687   $Array(
688     "restrict", SourceLocationRestrict,
689     "sourceText", SourceLocationSourceText
690  )
691 );
692
693
694 /**
695  * Class for a source slice. A source slice is a part of a script source with
696  * the following properties:
697  *   script        : script object for the source
698  *   from_line     : line number for the first line in the slice
699  *   to_line       : source line number for the last line in the slice
700  *   from_position : position of the first character in the slice
701  *   to_position   : position of the last character in the slice
702  * The to_line and to_position are not included in the slice, that is the lines
703  * in the slice are [from_line, to_line[. Likewise the characters in the slice
704  * are [from_position, to_position[.
705  * @param {Script} script The Script object for the source slice
706  * @param {number} from_line
707  * @param {number} to_line
708  * @param {number} from_position
709  * @param {number} to_position
710  * @constructor
711  */
712 function SourceSlice(script, from_line, to_line, from_position, to_position) {
713   this.script = script;
714   this.from_line = from_line;
715   this.to_line = to_line;
716   this.from_position = from_position;
717   this.to_position = to_position;
718 }
719
720 /**
721  * Get the source text for a SourceSlice
722  * @return {String} Source text for this slice. The last line will include
723  *     the line terminating characters (if any)
724  */
725 function SourceSliceSourceText() {
726   return %_CallFunction(this.script.source,
727                         this.from_position,
728                         this.to_position,
729                         StringSubstring);
730 }
731
732 SetUpLockedPrototype(SourceSlice,
733   $Array("script", "from_line", "to_line", "from_position", "to_position"),
734   $Array("sourceText", SourceSliceSourceText)
735 );
736
737
738 // Returns the offset of the given position within the containing
739 // line.
740 function GetPositionInLine(message) {
741   var script = %MessageGetScript(message);
742   var start_position = %MessageGetStartPosition(message);
743   var location = script.locationFromPosition(start_position, false);
744   if (location == null) return -1;
745   location.restrict();
746   return start_position - location.start;
747 }
748
749
750 function GetStackTraceLine(recv, fun, pos, isGlobal) {
751   return new CallSite(recv, fun, pos).toString();
752 }
753
754 // ----------------------------------------------------------------------------
755 // Error implementation
756
757 // Defines accessors for a property that is calculated the first time
758 // the property is read.
759 function DefineOneShotAccessor(obj, name, fun) {
760   // Note that the accessors consistently operate on 'obj', not 'this'.
761   // Since the object may occur in someone else's prototype chain we
762   // can't rely on 'this' being the same as 'obj'.
763   var hasBeenSet = false;
764   var value;
765   var getter = function() {
766     if (hasBeenSet) {
767       return value;
768     }
769     hasBeenSet = true;
770     value = fun(obj);
771     return value;
772   };
773   var setter = function(v) {
774     hasBeenSet = true;
775     value = v;
776   };
777   %DefineOrRedefineAccessorProperty(obj, name, getter, setter, DONT_ENUM);
778 }
779
780 function CallSite(receiver, fun, pos) {
781   this.receiver = receiver;
782   this.fun = fun;
783   this.pos = pos;
784 }
785
786 function CallSiteGetThis() {
787   return this.receiver;
788 }
789
790 function CallSiteGetTypeName() {
791   var constructor = this.receiver.constructor;
792   if (!constructor) {
793     return %_CallFunction(this.receiver, ObjectToString);
794   }
795   var constructorName = constructor.name;
796   if (!constructorName) {
797     return %_CallFunction(this.receiver, ObjectToString);
798   }
799   return constructorName;
800 }
801
802 function CallSiteIsToplevel() {
803   if (this.receiver == null) {
804     return true;
805   }
806   return IS_GLOBAL(this.receiver);
807 }
808
809 function CallSiteIsEval() {
810   var script = %FunctionGetScript(this.fun);
811   return script && script.compilation_type == COMPILATION_TYPE_EVAL;
812 }
813
814 function CallSiteGetEvalOrigin() {
815   var script = %FunctionGetScript(this.fun);
816   return FormatEvalOrigin(script);
817 }
818
819 function CallSiteGetScriptNameOrSourceURL() {
820   var script = %FunctionGetScript(this.fun);
821   return script ? script.nameOrSourceURL() : null;
822 }
823
824 function CallSiteGetFunction() {
825   return this.fun;
826 }
827
828 function CallSiteGetFunctionName() {
829   // See if the function knows its own name
830   var name = this.fun.name;
831   if (name) {
832     return name;
833   } else {
834     return %FunctionGetInferredName(this.fun);
835   }
836   // Maybe this is an evaluation?
837   var script = %FunctionGetScript(this.fun);
838   if (script && script.compilation_type == COMPILATION_TYPE_EVAL) {
839     return "eval";
840   }
841   return null;
842 }
843
844 function CallSiteGetMethodName() {
845   // See if we can find a unique property on the receiver that holds
846   // this function.
847   var ownName = this.fun.name;
848   if (ownName && this.receiver &&
849       (%_CallFunction(this.receiver,
850                       ownName,
851                       ObjectLookupGetter) === this.fun ||
852        %_CallFunction(this.receiver,
853                       ownName,
854                       ObjectLookupSetter) === this.fun ||
855        this.receiver[ownName] === this.fun)) {
856     // To handle DontEnum properties we guess that the method has
857     // the same name as the function.
858     return ownName;
859   }
860   var name = null;
861   for (var prop in this.receiver) {
862     if (this.receiver.__lookupGetter__(prop) === this.fun ||
863         this.receiver.__lookupSetter__(prop) === this.fun ||
864         (!this.receiver.__lookupGetter__(prop) &&
865          this.receiver[prop] === this.fun)) {
866       // If we find more than one match bail out to avoid confusion.
867       if (name) {
868         return null;
869       }
870       name = prop;
871     }
872   }
873   if (name) {
874     return name;
875   }
876   return null;
877 }
878
879 function CallSiteGetFileName() {
880   var script = %FunctionGetScript(this.fun);
881   return script ? script.name : null;
882 }
883
884 function CallSiteGetLineNumber() {
885   if (this.pos == -1) {
886     return null;
887   }
888   var script = %FunctionGetScript(this.fun);
889   var location = null;
890   if (script) {
891     location = script.locationFromPosition(this.pos, true);
892   }
893   return location ? location.line + 1 : null;
894 }
895
896 function CallSiteGetColumnNumber() {
897   if (this.pos == -1) {
898     return null;
899   }
900   var script = %FunctionGetScript(this.fun);
901   var location = null;
902   if (script) {
903     location = script.locationFromPosition(this.pos, true);
904   }
905   return location ? location.column + 1: null;
906 }
907
908 function CallSiteIsNative() {
909   var script = %FunctionGetScript(this.fun);
910   return script ? (script.type == TYPE_NATIVE) : false;
911 }
912
913 function CallSiteGetPosition() {
914   return this.pos;
915 }
916
917 function CallSiteIsConstructor() {
918   var constructor = this.receiver ? this.receiver.constructor : null;
919   if (!constructor) {
920     return false;
921   }
922   return this.fun === constructor;
923 }
924
925 function CallSiteToString() {
926   var fileName;
927   var fileLocation = "";
928   if (this.isNative()) {
929     fileLocation = "native";
930   } else if (this.isEval()) {
931     fileName = this.getScriptNameOrSourceURL();
932     if (!fileName) {
933       fileLocation = this.getEvalOrigin();
934     }
935   } else {
936     fileName = this.getFileName();
937   }
938
939   if (fileName) {
940     fileLocation += fileName;
941     var lineNumber = this.getLineNumber();
942     if (lineNumber != null) {
943       fileLocation += ":" + lineNumber;
944       var columnNumber = this.getColumnNumber();
945       if (columnNumber) {
946         fileLocation += ":" + columnNumber;
947       }
948     }
949   }
950
951   if (!fileLocation) {
952     fileLocation = "unknown source";
953   }
954   var line = "";
955   var functionName = this.getFunction().name;
956   var addPrefix = true;
957   var isConstructor = this.isConstructor();
958   var isMethodCall = !(this.isToplevel() || isConstructor);
959   if (isMethodCall) {
960     var methodName = this.getMethodName();
961     line += this.getTypeName() + ".";
962     if (functionName) {
963       line += functionName;
964       if (methodName && (methodName != functionName)) {
965         line += " [as " + methodName + "]";
966       }
967     } else {
968       line += methodName || "<anonymous>";
969     }
970   } else if (isConstructor) {
971     line += "new " + (functionName || "<anonymous>");
972   } else if (functionName) {
973     line += functionName;
974   } else {
975     line += fileLocation;
976     addPrefix = false;
977   }
978   if (addPrefix) {
979     line += " (" + fileLocation + ")";
980   }
981   return line;
982 }
983
984 SetUpLockedPrototype(CallSite, $Array("receiver", "fun", "pos"), $Array(
985   "getThis", CallSiteGetThis,
986   "getTypeName", CallSiteGetTypeName,
987   "isToplevel", CallSiteIsToplevel,
988   "isEval", CallSiteIsEval,
989   "getEvalOrigin", CallSiteGetEvalOrigin,
990   "getScriptNameOrSourceURL", CallSiteGetScriptNameOrSourceURL,
991   "getFunction", CallSiteGetFunction,
992   "getFunctionName", CallSiteGetFunctionName,
993   "getMethodName", CallSiteGetMethodName,
994   "getFileName", CallSiteGetFileName,
995   "getLineNumber", CallSiteGetLineNumber,
996   "getColumnNumber", CallSiteGetColumnNumber,
997   "isNative", CallSiteIsNative,
998   "getPosition", CallSiteGetPosition,
999   "isConstructor", CallSiteIsConstructor,
1000   "toString", CallSiteToString
1001 ));
1002
1003
1004 function FormatEvalOrigin(script) {
1005   var sourceURL = script.nameOrSourceURL();
1006   if (sourceURL) {
1007     return sourceURL;
1008   }
1009
1010   var eval_origin = "eval at ";
1011   if (script.eval_from_function_name) {
1012     eval_origin += script.eval_from_function_name;
1013   } else {
1014     eval_origin +=  "<anonymous>";
1015   }
1016
1017   var eval_from_script = script.eval_from_script;
1018   if (eval_from_script) {
1019     if (eval_from_script.compilation_type == COMPILATION_TYPE_EVAL) {
1020       // eval script originated from another eval.
1021       eval_origin += " (" + FormatEvalOrigin(eval_from_script) + ")";
1022     } else {
1023       // eval script originated from "real" source.
1024       if (eval_from_script.name) {
1025         eval_origin += " (" + eval_from_script.name;
1026         var location = eval_from_script.locationFromPosition(
1027             script.eval_from_script_position, true);
1028         if (location) {
1029           eval_origin += ":" + (location.line + 1);
1030           eval_origin += ":" + (location.column + 1);
1031         }
1032         eval_origin += ")";
1033       } else {
1034         eval_origin += " (unknown source)";
1035       }
1036     }
1037   }
1038
1039   return eval_origin;
1040 }
1041
1042 function FormatStackTrace(error, frames) {
1043   var lines = [];
1044   try {
1045     lines.push(error.toString());
1046   } catch (e) {
1047     try {
1048       lines.push("<error: " + e + ">");
1049     } catch (ee) {
1050       lines.push("<error>");
1051     }
1052   }
1053   for (var i = 0; i < frames.length; i++) {
1054     var frame = frames[i];
1055     var line;
1056     try {
1057       line = frame.toString();
1058     } catch (e) {
1059       try {
1060         line = "<error: " + e + ">";
1061       } catch (ee) {
1062         // Any code that reaches this point is seriously nasty!
1063         line = "<error>";
1064       }
1065     }
1066     lines.push("    at " + line);
1067   }
1068   return lines.join("\n");
1069 }
1070
1071 function FormatRawStackTrace(error, raw_stack) {
1072   var frames = [ ];
1073   for (var i = 0; i < raw_stack.length; i += 4) {
1074     var recv = raw_stack[i];
1075     var fun = raw_stack[i + 1];
1076     var code = raw_stack[i + 2];
1077     var pc = raw_stack[i + 3];
1078     var pos = %FunctionGetPositionForOffset(code, pc);
1079     frames.push(new CallSite(recv, fun, pos));
1080   }
1081   if (IS_FUNCTION($Error.prepareStackTrace)) {
1082     return $Error.prepareStackTrace(error, frames);
1083   } else {
1084     return FormatStackTrace(error, frames);
1085   }
1086 }
1087
1088
1089 function captureStackTrace(obj, cons_opt) {
1090   var stackTraceLimit = $Error.stackTraceLimit;
1091   if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return;
1092   if (stackTraceLimit < 0 || stackTraceLimit > 10000) {
1093     stackTraceLimit = 10000;
1094   }
1095   var raw_stack = %CollectStackTrace(obj,
1096                                      cons_opt ? cons_opt : captureStackTrace,
1097                                      stackTraceLimit);
1098   DefineOneShotAccessor(obj, 'stack', function (obj) {
1099     return FormatRawStackTrace(obj, raw_stack);
1100   });
1101 }
1102
1103
1104 function SetUpError() {
1105   // Define special error type constructors.
1106
1107   var DefineError = function(f) {
1108     // Store the error function in both the global object
1109     // and the runtime object. The function is fetched
1110     // from the runtime object when throwing errors from
1111     // within the runtime system to avoid strange side
1112     // effects when overwriting the error functions from
1113     // user code.
1114     var name = f.name;
1115     %SetProperty(global, name, f, DONT_ENUM);
1116     %SetProperty(builtins, '$' + name, f, DONT_ENUM | DONT_DELETE | READ_ONLY);
1117     // Configure the error function.
1118     if (name == 'Error') {
1119       // The prototype of the Error object must itself be an error.
1120       // However, it can't be an instance of the Error object because
1121       // it hasn't been properly configured yet.  Instead we create a
1122       // special not-a-true-error-but-close-enough object.
1123       var ErrorPrototype = function() {};
1124       %FunctionSetPrototype(ErrorPrototype, $Object.prototype);
1125       %FunctionSetInstanceClassName(ErrorPrototype, 'Error');
1126       %FunctionSetPrototype(f, new ErrorPrototype());
1127     } else {
1128       %FunctionSetPrototype(f, new $Error());
1129     }
1130     %FunctionSetInstanceClassName(f, 'Error');
1131     %SetProperty(f.prototype, 'constructor', f, DONT_ENUM);
1132     %SetProperty(f.prototype, "name", name, DONT_ENUM);
1133     %SetCode(f, function(m) {
1134       if (%_IsConstructCall()) {
1135         // Define all the expected properties directly on the error
1136         // object. This avoids going through getters and setters defined
1137         // on prototype objects.
1138         %IgnoreAttributesAndSetProperty(this, 'stack', void 0, DONT_ENUM);
1139         %IgnoreAttributesAndSetProperty(this, 'arguments', void 0, DONT_ENUM);
1140         %IgnoreAttributesAndSetProperty(this, 'type', void 0, DONT_ENUM);
1141         if (m === kAddMessageAccessorsMarker) {
1142           // DefineOneShotAccessor always inserts a message property and
1143           // ignores setters.
1144           DefineOneShotAccessor(this, 'message', function (obj) {
1145               return FormatMessage(%NewMessageObject(obj.type, obj.arguments));
1146           });
1147         } else if (!IS_UNDEFINED(m)) {
1148           %IgnoreAttributesAndSetProperty(
1149             this, 'message', ToString(m), DONT_ENUM);
1150         }
1151         captureStackTrace(this, f);
1152       } else {
1153         return new f(m);
1154       }
1155     });
1156     %SetNativeFlag(f);
1157   };
1158
1159   DefineError(function Error() { });
1160   DefineError(function TypeError() { });
1161   DefineError(function RangeError() { });
1162   DefineError(function SyntaxError() { });
1163   DefineError(function ReferenceError() { });
1164   DefineError(function EvalError() { });
1165   DefineError(function URIError() { });
1166 }
1167
1168 SetUpError();
1169
1170 $Error.captureStackTrace = captureStackTrace;
1171
1172 %SetProperty($Error.prototype, 'message', '', DONT_ENUM);
1173
1174 // Global list of error objects visited during ErrorToString. This is
1175 // used to detect cycles in error toString formatting.
1176 var visited_errors = new InternalArray();
1177 var cyclic_error_marker = new $Object();
1178
1179 function GetPropertyWithoutInvokingMonkeyGetters(error, name) {
1180   // Climb the prototype chain until we find the holder.
1181   while (error && !%HasLocalProperty(error, name)) {
1182     error = error.__proto__;
1183   }
1184   if (error === null) return void 0;
1185   if (!IS_OBJECT(error)) return error[name];
1186   // If the property is an accessor on one of the predefined errors that can be
1187   // generated statically by the compiler, don't touch it. This is to address
1188   // http://code.google.com/p/chromium/issues/detail?id=69187
1189   var desc = %GetOwnProperty(error, name);
1190   if (desc && desc[IS_ACCESSOR_INDEX]) {
1191     var isName = name === "name";
1192     if (error === $ReferenceError.prototype)
1193       return isName ? "ReferenceError" : void 0;
1194     if (error === $SyntaxError.prototype)
1195       return isName ? "SyntaxError" : void 0;
1196     if (error === $TypeError.prototype)
1197       return isName ? "TypeError" : void 0;
1198   }
1199   // Otherwise, read normally.
1200   return error[name];
1201 }
1202
1203 function ErrorToStringDetectCycle(error) {
1204   if (!%PushIfAbsent(visited_errors, error)) throw cyclic_error_marker;
1205   try {
1206     var type = GetPropertyWithoutInvokingMonkeyGetters(error, "type");
1207     var name = GetPropertyWithoutInvokingMonkeyGetters(error, "name");
1208     name = IS_UNDEFINED(name) ? "Error" : TO_STRING_INLINE(name);
1209     var message = GetPropertyWithoutInvokingMonkeyGetters(error, "message");
1210     var hasMessage = %_CallFunction(error, "message", ObjectHasOwnProperty);
1211     if (type && !hasMessage) {
1212       var args = GetPropertyWithoutInvokingMonkeyGetters(error, "arguments");
1213       message = FormatMessage(%NewMessageObject(type, args));
1214     }
1215     message = IS_UNDEFINED(message) ? "" : TO_STRING_INLINE(message);
1216     if (name === "") return message;
1217     if (message === "") return name;
1218     return name + ": " + message;
1219   } finally {
1220     visited_errors.length = visited_errors.length - 1;
1221   }
1222 }
1223
1224 function ErrorToString() {
1225   if (!IS_SPEC_OBJECT(this)) {
1226     throw MakeTypeError("called_on_non_object", ["Error.prototype.toString"]);
1227   }
1228
1229   try {
1230     return ErrorToStringDetectCycle(this);
1231   } catch(e) {
1232     // If this error message was encountered already return the empty
1233     // string for it instead of recursively formatting it.
1234     if (e === cyclic_error_marker) {
1235       return '';
1236     }
1237     throw e;
1238   }
1239 }
1240
1241
1242 InstallFunctions($Error.prototype, DONT_ENUM, ['toString', ErrorToString]);
1243
1244 // Boilerplate for exceptions for stack overflows. Used from
1245 // Isolate::StackOverflow().
1246 var kStackOverflowBoilerplate = MakeRangeError('stack_overflow', []);