/**
* Copyright (c) 2012-2016 André Bargull
* Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms.
*
* <https://github.com/anba/es6draft>
*/
package com.github.anba.es6draft.runtime.objects;
import java.util.Objects;
import com.github.anba.es6draft.runtime.Realm;
import com.github.anba.es6draft.runtime.internal.ScriptException;
import com.github.anba.es6draft.runtime.types.Intrinsics;
import com.github.anba.es6draft.runtime.types.Property;
import com.github.anba.es6draft.runtime.types.ScriptObject;
import com.github.anba.es6draft.runtime.types.Type;
import com.github.anba.es6draft.runtime.types.builtins.OrdinaryObject;
/**
* <h1>19 Fundamental Objects</h1><br>
* <h2>19.5 Error Objects</h2>
* <ul>
* <li>19.5.4 Properties of Error Instances
* <li>19.5.6 NativeError Object Structure
* <ul>
* <li>19.5.6.4 Properties of NativeError Instances
* </ul>
* </ul>
*/
public final class ErrorObject extends OrdinaryObject {
private final ScriptException exception;
/**
* Constructs a new Error object.
*
* @param realm
* the realm object
*/
public ErrorObject(Realm realm) {
super(realm);
this.exception = new ScriptException(this);
}
/**
* Constructs a new Error object.
*
* @param realm
* the realm object
* @param cause
* the exception's cause
*/
public ErrorObject(Realm realm, Throwable cause) {
super(realm);
this.exception = new ScriptException(this, cause);
}
/**
* Constructs a new Error object.
*
* @param realm
* the realm object
* @param prototype
* the error prototype
* @param message
* the error message
*/
public ErrorObject(Realm realm, Intrinsics prototype, String message) {
this(realm);
setPrototype(realm.getIntrinsic(prototype));
defineErrorProperty("message", message, false);
}
/**
* Constructs a new Error object.
*
* @param realm
* the realm object
* @param cause
* the exception's cause
* @param prototype
* the error prototype
* @param message
* the error message
*/
public ErrorObject(Realm realm, Throwable cause, Intrinsics prototype, String message) {
this(realm, cause);
setPrototype(realm.getIntrinsic(prototype));
defineErrorProperty("message", message, false);
}
/**
* Constructs a new Error object.
*
* @param realm
* the realm object
* @param prototype
* the error prototype
* @param message
* the error message
* @param fileName
* the file name
* @param lineNumber
* the line number
* @param columnNumber
* the column number
*/
public ErrorObject(Realm realm, Intrinsics prototype, String message, String fileName,
int lineNumber, int columnNumber) {
this(realm);
setPrototype(realm.getIntrinsic(prototype));
defineErrorProperty("message", message, false);
defineErrorProperty("fileName", fileName, true);
defineErrorProperty("lineNumber", lineNumber, true);
defineErrorProperty("columnNumber", columnNumber, true);
}
/**
* Constructs a new Error object.
*
* @param realm
* the realm object
* @param cause
* the exception's cause
* @param prototype
* the error prototype
* @param message
* the error message
* @param fileName
* the file name
* @param lineNumber
* the line number
* @param columnNumber
* the column number
*/
public ErrorObject(Realm realm, Throwable cause, Intrinsics prototype, String message,
String fileName, int lineNumber, int columnNumber) {
this(realm, cause);
setPrototype(realm.getIntrinsic(prototype));
defineErrorProperty("message", message, false);
defineErrorProperty("fileName", fileName, true);
defineErrorProperty("lineNumber", lineNumber, true);
defineErrorProperty("columnNumber", columnNumber, true);
}
/*package*/void defineErrorProperty(String name, Object value, boolean enumerable) {
infallibleDefineOwnProperty(name, new Property(value, true, enumerable, true));
}
/**
* Returns the wrapped {@link ScriptException} object.
*
* @return the wrapped {@link ScriptException} object
*/
public ScriptException getException() {
return exception;
}
@Override
public String className() {
return "Error";
}
@Override
public String toString() {
String name = getErrorObjectProperty(this, "name", "Error");
String message = getErrorObjectProperty(this, "message", "");
if (name.length() == 0) {
return message;
}
if (message.length() == 0) {
return name;
}
return name + ": " + message;
}
/**
* Specialized property retrieval to prevent any script execution.
*
* @param error
* the error object
* @param propertyName
* the property key
* @param defaultValue
* the default value
* @return property string value
*/
private static String getErrorObjectProperty(ErrorObject error, String propertyName, String defaultValue) {
Property property = error.lookupOwnProperty(propertyName);
if (property == null) {
ScriptObject proto = error.getPrototype();
if (proto instanceof ErrorPrototype || proto instanceof NativeErrorPrototype) {
property = ((OrdinaryObject) proto).lookupOwnProperty(propertyName);
}
}
Object value = property != null && property.isDataDescriptor() ? property.getValue() : null;
if (value == null || Type.isUndefined(value)) {
return defaultValue;
}
// Prevent possible recursion
if (value instanceof ErrorObject) {
return "<error>";
}
return Objects.toString(value);
}
}