/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-1999 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Igor Bukanov * Roger Lawrence * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */ package org.mozilla.javascript; /** * * The class of error objects * * ECMA 15.11 */ final class NativeError extends IdScriptableObject { static final long serialVersionUID = -5338413581437645187L; private static final Object ERROR_TAG = "Error"; private RhinoException stackProvider; static void init(Scriptable scope, boolean sealed) { NativeError obj = new NativeError(); ScriptableObject.putProperty(obj, "name", "Error"); ScriptableObject.putProperty(obj, "message", ""); ScriptableObject.putProperty(obj, "fileName", ""); ScriptableObject.putProperty(obj, "lineNumber", Integer.valueOf(0)); obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed); } static NativeError make(Context cx, Scriptable scope, IdFunctionObject ctorObj, Object[] args) { Scriptable proto = (Scriptable)(ctorObj.get("prototype", ctorObj)); NativeError obj = new NativeError(); obj.setPrototype(proto); obj.setParentScope(scope); int arglen = args.length; if (arglen >= 1) { ScriptableObject.putProperty(obj, "message", ScriptRuntime.toString(args[0])); if (arglen >= 2) { ScriptableObject.putProperty(obj, "fileName", args[1]); if (arglen >= 3) { int line = ScriptRuntime.toInt32(args[2]); ScriptableObject.putProperty(obj, "lineNumber", Integer.valueOf(line)); } } } return obj; } @Override public String getClassName() { return "Error"; } @Override public String toString() { // According to spec, Error.prototype.toString() may return undefined. Object toString = js_toString(this); return toString instanceof String ? (String) toString : super.toString(); } @Override protected void initPrototypeId(int id) { String s; int arity; switch (id) { case Id_constructor: arity=1; s="constructor"; break; case Id_toString: arity=0; s="toString"; break; case Id_toSource: arity=0; s="toSource"; break; default: throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(ERROR_TAG, id, s, arity); } @Override public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(ERROR_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); switch (id) { case Id_constructor: return make(cx, scope, f, args); case Id_toString: return js_toString(thisObj); case Id_toSource: return js_toSource(cx, scope, thisObj); } throw new IllegalArgumentException(String.valueOf(id)); } public void setStackProvider(RhinoException re) { // We go some extra miles to make sure the stack property is only // generated on demand, is cached after the first access, and is // overwritable like an ordinary property. Hence this setup with // the getter and setter below. if (stackProvider == null) { stackProvider = re; try { defineProperty("stack", null, NativeError.class.getMethod("getStack"), NativeError.class.getMethod("setStack", Object.class), 0); } catch (NoSuchMethodException nsm) { // should not happen throw new RuntimeException(nsm); } } } public Object getStack() { Object value = stackProvider == null ? NOT_FOUND : stackProvider.getScriptStackTrace(); // We store the stack as local property both to cache it // and to make the property writable setStack(value); return value; } public void setStack(Object value) { if (stackProvider != null) { stackProvider = null; delete("stack"); } put("stack", this, value); } private static Object js_toString(Scriptable thisObj) { Object name = ScriptableObject.getProperty(thisObj, "name"); if (name == NOT_FOUND || name == Undefined.instance) { name = "Error"; } else { name = ScriptRuntime.toString(name); } Object msg = ScriptableObject.getProperty(thisObj, "message"); final Object result; if (msg == NOT_FOUND || msg == Undefined.instance) { result = Undefined.instance; } else { result = ((String) name) + ": " + ScriptRuntime.toString(msg); } return result; } private static String js_toSource(Context cx, Scriptable scope, Scriptable thisObj) { // Emulation of SpiderMonkey behavior Object name = ScriptableObject.getProperty(thisObj, "name"); Object message = ScriptableObject.getProperty(thisObj, "message"); Object fileName = ScriptableObject.getProperty(thisObj, "fileName"); Object lineNumber = ScriptableObject.getProperty(thisObj, "lineNumber"); StringBuffer sb = new StringBuffer(); sb.append("(new "); if (name == NOT_FOUND) { name = Undefined.instance; } sb.append(ScriptRuntime.toString(name)); sb.append("("); if (message != NOT_FOUND || fileName != NOT_FOUND || lineNumber != NOT_FOUND) { if (message == NOT_FOUND) { message = ""; } sb.append(ScriptRuntime.uneval(cx, scope, message)); if (fileName != NOT_FOUND || lineNumber != NOT_FOUND) { sb.append(", "); if (fileName == NOT_FOUND) { fileName = ""; } sb.append(ScriptRuntime.uneval(cx, scope, fileName)); if (lineNumber != NOT_FOUND) { int line = ScriptRuntime.toInt32(lineNumber); if (line != 0) { sb.append(", "); sb.append(ScriptRuntime.toString(line)); } } } } sb.append("))"); return sb.toString(); } private static String getString(Scriptable obj, String id) { Object value = ScriptableObject.getProperty(obj, id); if (value == NOT_FOUND) return ""; return ScriptRuntime.toString(value); } @Override protected int findPrototypeId(String s) { int id; // #string_id_map# // #generated# Last update: 2007-05-09 08:15:45 EDT L0: { id = 0; String X = null; int c; int s_length = s.length(); if (s_length==8) { c=s.charAt(3); if (c=='o') { X="toSource";id=Id_toSource; } else if (c=='t') { X="toString";id=Id_toString; } } else if (s_length==11) { X="constructor";id=Id_constructor; } if (X!=null && X!=s && !X.equals(s)) id = 0; break L0; } // #/generated# return id; } private static final int Id_constructor = 1, Id_toString = 2, Id_toSource = 3, MAX_PROTOTYPE_ID = 3; // #/string_id_map# }