/** * 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 static com.github.anba.es6draft.runtime.AbstractOperations.CreateArrayFromList; import static com.github.anba.es6draft.runtime.AbstractOperations.CreateDataProperty; import static com.github.anba.es6draft.runtime.AbstractOperations.Get; import static com.github.anba.es6draft.runtime.AbstractOperations.ToString; import static com.github.anba.es6draft.runtime.internal.Errors.newTypeError; import static com.github.anba.es6draft.runtime.internal.Properties.createProperties; import static com.github.anba.es6draft.runtime.types.Undefined.UNDEFINED; import com.github.anba.es6draft.runtime.ExecutionContext; import com.github.anba.es6draft.runtime.Realm; import com.github.anba.es6draft.runtime.internal.Initializable; import com.github.anba.es6draft.runtime.internal.Messages; import com.github.anba.es6draft.runtime.internal.Properties.Accessor; import com.github.anba.es6draft.runtime.internal.Properties.Attributes; import com.github.anba.es6draft.runtime.internal.Properties.Function; import com.github.anba.es6draft.runtime.internal.Properties.Prototype; import com.github.anba.es6draft.runtime.internal.Properties.Value; import com.github.anba.es6draft.runtime.internal.ScriptException; import com.github.anba.es6draft.runtime.internal.StackTraces; import com.github.anba.es6draft.runtime.types.Intrinsics; 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.3 Properties of the Error Prototype Object * </ul> */ public final class ErrorPrototype extends OrdinaryObject implements Initializable { /** * Constructs a new Error prototype object. * * @param realm * the realm object */ public ErrorPrototype(Realm realm) { super(realm); } @Override public void initialize(Realm realm) { createProperties(realm, this, Properties.class); } /** * 19.5.3 Properties of the Error Prototype Object */ public enum Properties { ; @Prototype public static final Intrinsics __proto__ = Intrinsics.ObjectPrototype; /** * 19.5.3.1 Error.prototype.constructor */ @Value(name = "constructor") public static final Intrinsics constructor = Intrinsics.Error; /** * 19.5.3.3 Error.prototype.name */ @Value(name = "name") public static final String name = "Error"; /** * 19.5.3.2 Error.prototype.message */ @Value(name = "message") public static final String message = ""; /** * 19.5.3.4 Error.prototype.toString ( ) * * @param cx * the execution context * @param thisValue * the function this-value * @return the string representation */ @Function(name = "toString", arity = 0) public static Object toString(ExecutionContext cx, Object thisValue) { /* step 2 */ if (!Type.isObject(thisValue)) { throw newTypeError(cx, Messages.Key.NotObjectType); } /* step 1 */ ScriptObject o = Type.objectValue(thisValue); /* steps 3-4 */ Object name = Get(cx, o, "name"); /* steps 5-6 */ CharSequence sname = Type.isUndefined(name) ? "Error" : ToString(cx, name); /* steps 7-8 */ Object msg = Get(cx, o, "message"); /* steps 9-10 */ CharSequence smsg = Type.isUndefined(msg) ? "" : ToString(cx, msg); /* step 11 */ if (sname.length() == 0) { return smsg; } /* step 12 */ if (smsg.length() == 0) { return sname; } /* step 13 */ return sname + ": " + smsg; } /** * Extension: Error.prototype.fileName * * @param cx * the execution context * @param thisValue * the function this-value * @return the file name */ @Accessor(name = "fileName", type = Accessor.Type.Getter, attributes = @Attributes( writable = false, enumerable = false, configurable = true)) public static Object get_fileName(ExecutionContext cx, Object thisValue) { if (!(thisValue instanceof ErrorObject)) { return UNDEFINED; } ScriptException e = ((ErrorObject) thisValue).getException(); return StackTraces.stackTraceStream(e).findFirst().map(StackTraceElement::getFileName).orElse(""); } /** * Extension: Error.prototype.fileName * * @param cx * the execution context * @param thisValue * the function this-value * @param value * the new file name * @return the undefined value */ @Accessor(name = "fileName", type = Accessor.Type.Setter, attributes = @Attributes( writable = false, enumerable = false, configurable = true)) public static Object set_fileName(ExecutionContext cx, Object thisValue, Object value) { if (!(thisValue instanceof ErrorObject)) { return UNDEFINED; } CreateDataProperty(cx, (ErrorObject) thisValue, "fileName", value); return UNDEFINED; } /** * Extension: Error.prototype.lineNumber * * @param cx * the execution context * @param thisValue * the function this-value * @return the line number */ @Accessor(name = "lineNumber", type = Accessor.Type.Getter, attributes = @Attributes( writable = false, enumerable = false, configurable = true)) public static Object get_lineNumber(ExecutionContext cx, Object thisValue) { if (!(thisValue instanceof ErrorObject)) { return UNDEFINED; } ScriptException e = ((ErrorObject) thisValue).getException(); return StackTraces.stackTraceStream(e).findFirst().map(StackTraceElement::getLineNumber).orElse(0); } /** * Extension: Error.prototype.lineNumber * * @param cx * the execution context * @param thisValue * the function this-value * @param value * the new line number * @return the undefined value */ @Accessor(name = "lineNumber", type = Accessor.Type.Setter, attributes = @Attributes( writable = false, enumerable = false, configurable = true)) public static Object set_lineNumber(ExecutionContext cx, Object thisValue, Object value) { if (!(thisValue instanceof ErrorObject)) { return UNDEFINED; } CreateDataProperty(cx, (ErrorObject) thisValue, "lineNumber", value); return UNDEFINED; } /** * Extension: Error.prototype.columnNumber * * @param cx * the execution context * @param thisValue * the function this-value * @return the column number */ @Accessor(name = "columnNumber", type = Accessor.Type.Getter, attributes = @Attributes( writable = false, enumerable = false, configurable = true)) public static Object get_columnNumber(ExecutionContext cx, Object thisValue) { if (!(thisValue instanceof ErrorObject)) { return UNDEFINED; } // no column information available in StackTraceElements... return 0; } /** * Extension: Error.prototype.columnNumber * * @param cx * the execution context * @param thisValue * the function this-value * @param value * the new column number * @return the undefined value */ @Accessor(name = "columnNumber", type = Accessor.Type.Setter, attributes = @Attributes( writable = false, enumerable = false, configurable = true)) public static Object set_columnNumber(ExecutionContext cx, Object thisValue, Object value) { if (!(thisValue instanceof ErrorObject)) { return UNDEFINED; } CreateDataProperty(cx, (ErrorObject) thisValue, "columnNumber", value); return UNDEFINED; } /** * Extension: Error.prototype.stack * * @param cx * the execution context * @param thisValue * the function this-value * @return the stack string */ @Accessor(name = "stack", type = Accessor.Type.Getter, attributes = @Attributes( writable = false, enumerable = false, configurable = true)) public static Object get_stack(ExecutionContext cx, Object thisValue) { if (!(thisValue instanceof ErrorObject)) { return UNDEFINED; } ScriptException e = ((ErrorObject) thisValue).getException(); return StackTraces.stackTraceStream(e).collect(StringBuilder::new, (sb, element) -> { String methodName = element.getMethodName(); String fileName = element.getFileName(); int lineNumber = element.getLineNumber(); sb.append(methodName).append('@').append(fileName).append(':').append(lineNumber).append('\n'); }, StringBuilder::append).toString(); } /** * Extension: Error.prototype.stack * * @param cx * the execution context * @param thisValue * the function this-value * @param value * the new stack string * @return the undefined value */ @Accessor(name = "stack", type = Accessor.Type.Setter, attributes = @Attributes( writable = false, enumerable = false, configurable = true)) public static Object set_stack(ExecutionContext cx, Object thisValue, Object value) { if (!(thisValue instanceof ErrorObject)) { return UNDEFINED; } CreateDataProperty(cx, (ErrorObject) thisValue, "stack", value); return UNDEFINED; } /** * Extension: Error.prototype.stackTrace * * @param cx * the execution context * @param thisValue * the function this-value * @return stack-trace object */ @Accessor(name = "stackTrace", type = Accessor.Type.Getter, attributes = @Attributes( writable = false, enumerable = false, configurable = true)) public static Object get_stackTrace(ExecutionContext cx, Object thisValue) { if (!(thisValue instanceof ErrorObject)) { return UNDEFINED; } ScriptException e = ((ErrorObject) thisValue).getException(); return CreateArrayFromList(cx, StackTraces.stackTraceStream(e).map(element -> { OrdinaryObject elem = ObjectCreate(cx, Intrinsics.ObjectPrototype); CreateDataProperty(cx, elem, "methodName", element.getMethodName()); CreateDataProperty(cx, elem, "fileName", element.getFileName()); CreateDataProperty(cx, elem, "lineNumber", element.getLineNumber()); return elem; })); } } }