/*
Реализация среды исполнения языка программирования
Объектно-ориентированный продвинутый векторный транслятор
Copyright © 2021, 2024, 2026 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package avt.lang;
import avt.io.*;
public class Throwable(Object)
{
private static Throwable[] EMPTY_SUPPRESSED;
private static native int suppressedCount();
private long fldStackPointer;
private long fldCodePointerOverride;
private Throwable[] fldSuppressed;
private StackTraceElement[] fldStackTrace;
private String fldMessage;
private Throwable fldCause;
public (): this(null, null) { }
public (Throwable cause): this(null, cause) { }
public (String message): this(message, null) { }
public (String message, Throwable cause) {
if(EMPTY_SUPPRESSED == null) (EMPTY_SUPPRESSED = new Throwable[0]).finalize();
fldMessage = message;
fldCause = cause;
}
package (String message, long codePtrOverride) {
if(EMPTY_SUPPRESSED == null) (EMPTY_SUPPRESSED = new Throwable[0]).finalize();
fldMessage = message;
fldCodePointerOverride = codePtrOverride;
}
public String toString() {
StringBuilder result = (new StringBuilder()).append(getClass().canonicalName);
String message = fldMessage;
if(message != null)
{
message = message.trim();
if(!message.isEmpty()) result.append(": ").append(message);
}
return result.toString();
}
public final void printStackTrace() { System.err.print(stackTraceAsText()); }
public final void printStackTrace(PrintStream output) { (output != null ? output : System.err).print(stackTraceAsText()); }
public final StackTraceElement[] stackTrace { read = fldStackTrace, write = setStackTrace }
public final Throwable[] suppressed { read = fldSuppressed }
public final String message { read = fldMessage, write = fldMessage }
public final Throwable cause { read = fldCause }
protected void afterConstruction() {
int length = suppressedCount();
if(length <= 0)
{
fldSuppressed = EMPTY_SUPPRESSED;
} else
{
Throwable[] suppressed = new Throwable[length];
for(int index = 0; index < length; index++) suppressed[index] = index <= 0 ? findFirstSuppressed() : findNextSuppressed();
suppressed.finalize();
fldSuppressed = suppressed;
}
long codePtrOverride = fldCodePointerOverride;
fldStackTrace = codePtrOverride == 0 ? Thread.stackTrace() : Thread.stackTrace(codePtrOverride);
}
protected String stackTraceAsText() {
String at = package.getResourceString("string.throwable.at");
String more = package.getResourceString("string.throwable.more");
String cause = package.getResourceString("string.throwable.cause");
String ellipsis = package.getResourceString("string.throwable.ellipsis");
String suppressed = package.getResourceString("string.throwable.suppressed");
String ending = Platform.instance.lineSeparator;
StringBuilder result = new StringBuilder(0x7fff);
for(Throwable[] supArray = fldSuppressed, int supLength = supArray == null ? 0 : supArray.length, int supIndex = -1; supIndex < supLength; supIndex++)
{
Throwable current = supIndex < 0 ? this : supArray[supIndex];
(current == this ? result : result.append(suppressed)).append(current).append(ending);
StackTraceElement[] staArray = current.fldStackTrace;
int staLength = staArray == null ? 0 : staArray.length;
for(int staIndex = 0; staIndex < staLength; staIndex++)
{
Object staElement = staArray[staIndex];
if(staElement != null) result.append('\t').append(at).append(staElement).append(ending);
}
for(Throwable curCause = current.fldCause; curCause != null; curCause = curCause.fldCause)
{
StackTraceElement[] stbArray = curCause.fldStackTrace;
int stbLength = stbArray == null ? 0 : stbArray.length;
int common = 0;
for(int staIndex = staLength, int stbIndex = stbLength; staIndex-- > 0 && stbIndex-- > 0; common++)
{
Object staElement = staArray[staIndex];
Object stbElement = stbArray[stbIndex];
if(staElement == null || stbElement == null || !staElement.equals(stbElement)) break;
}
result.append(cause).append(curCause).append(ending);
for(int comLength = stbLength - common, int comIndex = 0; comIndex < comLength; comIndex++)
{
Object stbElement = stbArray[comIndex];
if(stbElement != null) result.append('\t').append(at).append(stbElement).append(ending);
}
result.append('\t').append(ellipsis).append(common).append(more).append(ending);
staArray = stbArray;
staLength = stbLength;
}
}
return result.toString();
}
private void setStackTrace(StackTraceElement[] newStackTrace) {
if(newStackTrace == null)
{
fldStackTrace = null;
return;
}
int length = newStackTrace.length;
if(length < newStackTrace.capacity) Array.copy(newStackTrace, 0, newStackTrace = new StackTraceElement[length], 0, length);
fldStackTrace = newStackTrace;
}
private native Throwable findFirstSuppressed();
private native Throwable findNextSuppressed();
}