diff --git a/ISBPL.java b/ISBPL.java index 7335521..9faf109 100644 --- a/ISBPL.java +++ b/ISBPL.java @@ -35,7 +35,7 @@ public class ISBPL { static boolean debug = false, printCalls = false; public ISBPLDebugger.IPC debuggerIPC = new ISBPLDebugger.IPC(); ArrayList types = new ArrayList<>(); - ISBPLFrame level0 = new ISBPLFrame(this); + ISBPLFrame level0 = new ISBPLFrame("isbpl", this); final ISBPLThreadLocal> fileStack = ISBPLThreadLocal.withInitial(Stack::new); final ISBPLThreadLocal> frameStack = ISBPLThreadLocal.withInitial(() -> { Stack frames = new Stack<>(); @@ -48,6 +48,7 @@ public class ISBPL { ArrayList included = new ArrayList<>(); HashMap natives = new HashMap<>(); boolean stopExceptions = false; + HashMap> stackTraces = new HashMap<>(); private final Object syncMakeThread = new Object(); private ISBPLKeyword getKeyword(String word) { @@ -70,7 +71,7 @@ public class ISBPL { return (idx, words, file, stack) -> { idx++; AtomicInteger i = new AtomicInteger(idx); - ISBPLCallable callable = readCallable(i, words, file); + ISBPLCallable callable = readCallable("if", i, words, file); if(stack.pop().isTruthy()) { callable.call(stack); } @@ -80,9 +81,9 @@ public class ISBPL { return (idx, words, file, stack) -> { idx++; AtomicInteger i = new AtomicInteger(idx); - ISBPLCallable cond = readCallable(i, words, file); + ISBPLCallable cond = readCallable("while-condition", i, words, file); i.getAndIncrement(); - ISBPLCallable block = readCallable(i, words, file); + ISBPLCallable block = readCallable("while", i, words, file); cond.call(stack); while (stack.pop().isTruthy()) { block.call(stack); @@ -115,14 +116,15 @@ public class ISBPL { } } AtomicInteger i = new AtomicInteger(idx); - ISBPLCallable block = readCallable(i, words, file); + ISBPLCallable block = readCallable("try", i, words, file); i.getAndIncrement(); - ISBPLCallable catcher = readCallable(i, words, file); + ISBPLCallable catcher = readCallable("catch", i, words, file); int stackHeight = stack.size(); try { block.call(stack); } catch (ISBPLError error) { if (Arrays.asList(allowed).contains(error.type) || allowed.length == 1 && allowed[0].equals("all")) { + stack.push(new ISBPLObject(getType("error"), error)); stack.push(toISBPLString(error.message)); stack.push(toISBPLString(error.type)); catcher.call(stack); @@ -132,9 +134,11 @@ public class ISBPL { } } catch (Exception e) { if (Arrays.asList(allowed).contains("Java") || allowed.length == 1 && allowed[0].equals("all")) { + stack.push(new ISBPLObject(getType("error"), e)); stack.push(toISBPL(e)); stack.push(toISBPLString(e.getClass().getName())); stack.push(toISBPLString("Java")); + catcher.call(stack); } else { throw e; @@ -154,9 +158,9 @@ public class ISBPL { return (idx, words, file, stack) -> { idx++; AtomicInteger i = new AtomicInteger(idx); - ISBPLCallable block = readCallable(i, words, file); + ISBPLCallable block = readCallable("do-main", i, words, file); i.getAndIncrement(); - ISBPLCallable catcher = readCallable(i, words, file); + ISBPLCallable catcher = readCallable("do-finally", i, words, file); try { block.call(stack); } finally { @@ -168,7 +172,7 @@ public class ISBPL { case "{": return (idx, words, file, stack) -> { AtomicInteger i = new AtomicInteger(idx); - ISBPLCallable block = readCallable(i, words, file); + ISBPLCallable block = readCallable("lambda", i, words, file); stack.push(new ISBPLObject(getType("func"), block)); return i.get(); }; @@ -181,7 +185,7 @@ public class ISBPL { for(ISBPLObject obj : stack) { s.push(obj); } - ISBPLCallable block = readCallable(i, words, file); + ISBPLCallable block = readCallable("thread", i, words, file); long tid = Thread.currentThread().getId(); Stack fstack = (Stack) frameStack.get().clone(); new Thread(() -> { @@ -234,7 +238,7 @@ public class ISBPL { if(definingMethods) { AtomicInteger idx2 = new AtomicInteger(++j); - addFunction(type, word2, readCallable(idx2, words2, file)); + addFunction(type, word2, readCallable(word2, idx2, words2, file)); j = idx2.get(); } else { @@ -1099,6 +1103,25 @@ public class ISBPL { } }; break; + case "error.stacktrace": + func = (stack) -> { + ISBPLObject error = stack.pop(); + error.checkType(getType("error")); + Throwable t = (Throwable) error.object; + Stack frames = stackTraces.get(t); + ISBPLObject[] array = new ISBPLObject[frames.size()]; + for(int i = 0; i < frames.size(); i++) { + ISBPLFrame frame = frames.get(i); + ArrayList arr = new ArrayList<>(); + while(frame != null) { + arr.add(toISBPLString(frame.name)); + frame = frame.parent; + } + array[i] = new ISBPLObject(getType("array"), arr.toArray(new ISBPLObject[0])); + } + stack.push(new ISBPLObject(getType("array"), array)); + }; + break; default: func = natives.get(name); break; @@ -1422,7 +1445,7 @@ public class ISBPL { i++; String name = words[i]; AtomicInteger integer = new AtomicInteger(++i); - ISBPLCallable callable = readCallable(integer, words, file); + ISBPLCallable callable = readCallable(name, integer, words, file); i = integer.get(); frameStack.get().peek().add(name, callable); return i; @@ -1447,12 +1470,12 @@ public class ISBPL { return newWords.toArray(new String[0]); } - private ISBPLCallable readCallable(AtomicInteger idx, String[] words, File file) { + private ISBPLCallable readCallable(String name, AtomicInteger idx, String[] words, File file) { String[] theWords = readBlock(idx, words, file); ISBPLFrame frame = frameStack.get().peek(); return (stack) -> { fileStack.get().push(file); - frameStack.get().push(new ISBPLFrame(this, frame)); + frameStack.get().push(new ISBPLFrame(name, this, frame)); try { interpretRaw(theWords, stack); } finally { @@ -1613,9 +1636,12 @@ public class ISBPL { e.printStackTrace(); } catch (Throwable t) { + if(stackTraces.get(t) == null) + stackTraces.put(t, (Stack)frameStack.get().clone()); if(debug) ISBPL.gOutputStream.println("Passing exception " + t + " to caller."); if(stopExceptions) { t.printStackTrace(); + ISBPL.gOutputStream.println(printStackTrace(stackTraces.get(t))); ISBPL.gOutputStream.println("Current Words: "); ISBPL.gOutputStream.println(Arrays.toString(words)); dump(stack); @@ -1623,6 +1649,24 @@ public class ISBPL { throw t; } } + + public String printStackTrace(Stack frameStack) { + String s = "INTERPRET"; + try { + String indent = " "; + for (ISBPLFrame frame : frameStack) { + s += "\n" + indent + "\\ "; + String p = ""; + while(frame != null) { + p = "/" + frame.name + p; + frame = frame.parent; + } + s += p; + indent += " "; + } + } catch(Throwable t) { t.printStackTrace(); } + return s; + } // Magic, please test before pushing changes! private String[] splitWords(String code) { @@ -1765,14 +1809,16 @@ public class ISBPL { ISBPL.gOutputStream.println("Error: " + e.type + ": " + e.message); } catch(Throwable e) { e.printStackTrace(); + ISBPL.gErrorStream.println(isbpl.printStackTrace(isbpl.stackTraces.get(e))); } ISBPL.gOutputStream.print("\n> "); } } } catch (ISBPLStop stop) { System.exit(isbpl.exitCode); - } catch (Exception e) { + } catch (Throwable e) { e.printStackTrace(); + ISBPL.gErrorStream.println(isbpl.printStackTrace(isbpl.stackTraces.get(e))); ISBPL.gOutputStream.println(stack); } } @@ -2426,11 +2472,14 @@ class ISBPLFrame { public ISBPLFrame parent; public HashMap map = new HashMap<>(); public HashMap variables = new HashMap<>(); + public String name; - public ISBPLFrame(ISBPL context) { + public ISBPLFrame(String name, ISBPL context) { + this.name = name; this.context = context; } - public ISBPLFrame(ISBPL context, ISBPLFrame parentFrame) { + public ISBPLFrame(String name, ISBPL context, ISBPLFrame parentFrame) { + this.name = name; this.context = context; parent = parentFrame; } diff --git a/std.isbpl b/std.isbpl index 6cf2010..013a4cb 100644 --- a/std.isbpl +++ b/std.isbpl @@ -109,6 +109,19 @@ native null def TYPE_FUNCTION "func" mktype =TYPE_FUNCTION def Function TYPE_FUNCTION =Function +def Error construct error { + ; + construct { + with id message this ; + id message throw + this + } + stacktrace { + native error.stacktrace + error.stacktrace + } +} =Error + def TYPE_ARRAY construct array { ; construct { @@ -120,6 +133,23 @@ def TYPE_ARRAY construct array { def i 0 =i while { i this alen lt } { this i aget lambda fcall i ++ =i } } + stackTraceToString { + def this =this + def s "INTERPRET" =s + def ind " " =ind + { + with element ; + s "\n" ind "\\ " strconcat strconcat strconcat =s + def p "" =p + { + with name ; + "/" name p strconcat strconcat =p + } element foreach + s p strconcat =s + ind " " strconcat =ind + } this foreach + s + } } =TYPE_ARRAY def Array TYPE_ARRAY =Array def TYPE_STRING construct string array {