From a161775ea64497ee193998fee8d584628d017340 Mon Sep 17 00:00:00 2001 From: TudbuT Date: Fri, 29 Apr 2022 18:10:14 +0200 Subject: [PATCH] attempts at fixing multithread functionstack/garbage collector issues --- bootstrap/ISBPL.java | 1283 +++++++++++++++++++++--------------------- 1 file changed, 641 insertions(+), 642 deletions(-) diff --git a/bootstrap/ISBPL.java b/bootstrap/ISBPL.java index fdb68ed..e5cdc92 100644 --- a/bootstrap/ISBPL.java +++ b/bootstrap/ISBPL.java @@ -3,6 +3,7 @@ import java.lang.reflect.*; import java.net.BindException; import java.net.ServerSocket; import java.net.Socket; +import java.nio.file.Files; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; @@ -21,10 +22,10 @@ public class ISBPL { public ISBPLDebugger.IPC debuggerIPC = new ISBPLDebugger.IPC(); ArrayList types = new ArrayList<>(); HashMap level0 = new HashMap<>(); - final ISBPLThreadLocal>> functionStack = ISBPLThreadLocal.withInitial(() -> { - Stack> stack = new Stack<>(); - stack.push(level0); - return stack; + final ISBPLThreadLocal>> functionStack = ISBPLThreadLocal.withInitial(() -> { + Stack> stack = new Stack<>(); + stack.push(level0); + return stack; }); final ISBPLThreadLocal> fileStack = ISBPLThreadLocal.withInitial(Stack::new); HashMap varLinks = new HashMap<>(); @@ -35,7 +36,7 @@ public class ISBPL { ArrayList included = new ArrayList<>(); HashMap natives = new HashMap<>(); - private Object syncMakeThread = new Object(); + private final Object syncMakeThread = new Object(); private ISBPLKeyword getKeyword(String word) { switch (word) { case "native": @@ -51,7 +52,7 @@ public class ISBPL { idx++; Object var = new Object(); ISBPLCallable c; - vars.put(var, new ISBPLObject(getType("null"), 0)); + vars.put(var, getNullObject()); addFunction(words[idx], c = ((stack1) -> stack1.push(vars.get(var)))); addFunction("=" + words[idx], (stack1) -> vars.put(var, stack1.pop())); varLinks.put(c, var); @@ -165,20 +166,16 @@ public class ISBPL { synchronized(syncMakeThread) { idx++; AtomicInteger i = new AtomicInteger(idx); - Stack s = new Stack<>(); + Stack s = new ISBPLStack<>(); for(ISBPLObject obj : stack) { s.push(obj); } - ISBPLCallable block = readBlock(i, words, file, false); + // This cant be a non-function, unless we clone vars aswell to avoid garbage collecting them accidentally. + ISBPLCallable block = readBlock(i, words, file, true); long tid = Thread.currentThread().getId(); - Stack> fs = new Stack<>(); - for(HashMap map : functionStack.get()) { - fs.push(map); - } new Thread(() -> { debuggerIPC.run.put(Thread.currentThread().getId(), debuggerIPC.run.getOrDefault(tid, -1) == -1 ? -1 : 0); debuggerIPC.stack.put(Thread.currentThread().getId(), s); - functionStack.set(fs); try { block.call(s); } catch (ISBPLStop stop) { @@ -231,7 +228,7 @@ public class ISBPL { i.checkType(getType("int")); ISBPLObject[] arr = new ISBPLObject[((int) i.object)]; for (int j = 0 ; j < arr.length ; j++) { - arr[j] = new ISBPLObject(getType("null"), 0); + arr[j] = getNullObject(); } stack.push(new ISBPLObject(getType("array"), arr)); }; @@ -316,301 +313,233 @@ public class ISBPL { case "islong": func = (Stack stack) -> { ISBPLObject o = stack.pop(); - stack.push(new ISBPLObject(getType("int"), o.type.equals(getType("long")) ? 1 : 0)); - }; - break; - case "isdouble": - func = (Stack stack) -> { - ISBPLObject o = stack.pop(); - stack.push(new ISBPLObject(getType("int"), o.type.equals(getType("double")) ? 1 : 0)); - }; - break; - case "isarray": - func = (Stack stack) -> { - ISBPLObject o = stack.pop(); - stack.push(new ISBPLObject(getType("int"), o.type.equals(getType("array")) ? 1 : 0)); - }; - break; - case "_layer_call": - func = (Stack stack) -> { - ISBPLObject i = stack.pop(); - ISBPLObject s = stack.pop(); - i.checkType(getType("int")); - functionStack.get().get(functionStack.get().size() - 1 - ((int) i.object)).get(toJavaString(s)).call(stack); - }; - break; - case "reload": - func = (Stack stack) -> { - String filepath = getFilePathForInclude((Stack) stack, fileStack.get()); - File f = new File(filepath).getAbsoluteFile(); - try { - interpret(f, readFile(f), stack); - } - catch (IOException e) { - throw new ISBPLError("IO", "Couldn't find file " + filepath + " required by reload keyword."); - } - }; - break; - case "include": - func = (Stack stack) -> { - String filepath = getFilePathForInclude((Stack) stack, fileStack.get()); - if(!included.contains(filepath)) { + stack.push(new ISBPLObject(getType("int"), o.type.equals(getType("long")) ? 1 : 0)); + }; + break; + case "isdouble": + func = (Stack stack) -> { + ISBPLObject o = stack.pop(); + stack.push(new ISBPLObject(getType("int"), o.type.equals(getType("double")) ? 1 : 0)); + }; + break; + case "isarray": + func = (Stack stack) -> { + ISBPLObject o = stack.pop(); + stack.push(new ISBPLObject(getType("int"), o.type.equals(getType("array")) ? 1 : 0)); + }; + break; + case "_layer_call": + func = (Stack stack) -> { + ISBPLObject i = stack.pop(); + ISBPLObject s = stack.pop(); + i.checkType(getType("int")); + functionStack.get().get(functionStack.get().size() - 1 - ((int) i.object)).get(toJavaString(s)).call(stack); + }; + break; + case "reload": + func = (Stack stack) -> { + String filepath = getFilePathForInclude((Stack) stack, fileStack.get()); File f = new File(filepath).getAbsoluteFile(); try { interpret(f, readFile(f), stack); } catch (IOException e) { - throw new ISBPLError("IO", "Couldn't find file " + filepath + " required by include keyword."); + throw new ISBPLError("IO", "Couldn't find file " + filepath + " required by reload keyword."); } - included.add(filepath); - } - }; - break; - case "putchar": - func = (Stack stack) -> { - ISBPLObject c = stack.pop(); - c.checkType(getType("char")); - System.out.print(((char) c.object)); - }; - break; - case "eputchar": - func = (Stack stack) -> { - ISBPLObject c = stack.pop(); - c.checkType(getType("char")); - System.err.print(((char) c.object)); - }; - break; - case "_file": - func = (Stack stack) -> { - ISBPLObject s = stack.pop(); - File f = new File(toJavaString(s)); - stack.push(new ISBPLObject(getType("file"), f)); - }; - break; - case "read": - func = (Stack stack) -> { - ISBPLObject end = stack.pop(); - ISBPLObject begin = stack.pop(); - ISBPLObject fileToRead = stack.pop(); - end.checkType(getType("int")); - begin.checkType(getType("int")); - fileToRead.checkType(getType("file")); - try { - FileInputStream f = new FileInputStream((File) fileToRead.object); - int b = ((int) begin.object); - int e = ((int) end.object); - byte[] bytes = new byte[e - b]; - f.read(bytes, b, e); - ISBPLObject[] arr = new ISBPLObject[bytes.length]; - for (int i = 0 ; i < arr.length ; i++) { - arr[i] = new ISBPLObject(getType("byte"), bytes[i]); + }; + break; + case "include": + func = (Stack stack) -> { + String filepath = getFilePathForInclude((Stack) stack, fileStack.get()); + if(!included.contains(filepath)) { + File f = new File(filepath).getAbsoluteFile(); + try { + interpret(f, readFile(f), stack); + } + catch (IOException e) { + throw new ISBPLError("IO", "Couldn't find file " + filepath + " required by include keyword."); + } + included.add(filepath); } - stack.push(new ISBPLObject(getType("array"), arr)); - } - catch (FileNotFoundException e) { - throw new ISBPLError("FileNotFound", "File not found."); - } - catch (IOException e) { - throw new ISBPLError("IO", "File couldn't be read from" + (e.getMessage() != null ? ": " + e.getMessage() : ".")); - } - }; - break; - case "flength": - func = (Stack stack) -> { - ISBPLObject f = stack.pop(); - f.checkType(getType("file")); - stack.push(new ISBPLObject(getType("int"), ((int) ((File) f.object).length()))); - }; - break; - case "write": - func = (Stack stack) -> { - ISBPLObject content = stack.pop(); - ISBPLObject fileToWrite = stack.pop(); - content.checkType(getType("array")); - fileToWrite.checkType(getType("file")); - throw new ISBPLError("NotImplemented", "_file write is not implemented"); - }; - break; - case "getos": - func = (Stack stack) -> { - // TODO: This is not done yet, and it's horrible so far. - stack.push(toISBPLString("linux")); - }; - break; - case "mktype": - func = (Stack stack) -> { - ISBPLObject s = stack.pop(); - ISBPLType type = registerType(toJavaString(s)); - stack.push(new ISBPLObject(getType("int"), type.id)); - }; - break; - case "typename": - func = (Stack stack) -> { - ISBPLObject i = stack.pop(); - i.checkType(getType("int")); - stack.push(toISBPLString(types.get(((int) i.object)).name)); - }; - break; - case "gettype": - func = (Stack stack) -> { - ISBPLObject o = stack.pop(); - stack.push(new ISBPLObject(getType("int"), o.type.id)); - }; - break; - case "settype": - func = (Stack stack) -> { - ISBPLObject i = stack.pop(); - ISBPLObject o = stack.pop(); - i.checkType(getType("int")); - stack.push(new ISBPLObject(types.get(((int) i.object)), o.object)); - }; - break; - case "throw": - func = (Stack stack) -> { - ISBPLObject message = stack.pop(); - ISBPLObject type = stack.pop(); - String msg = toJavaString(message); - String t = toJavaString(type); - throw new ISBPLError(t, msg); - }; - break; - case "exit": - func = (Stack stack) -> { - ISBPLObject code = stack.pop(); - code.checkType(getType("int")); - exitCode = ((int) code.object); - throw new ISBPLStop(0); - }; - break; - case "eq": - func = (Stack stack) -> { - ISBPLObject o1 = stack.pop(); - ISBPLObject o2 = stack.pop(); - stack.push(new ISBPLObject(getType("int"), o1.equals(o2) ? 1 : 0)); - }; - break; - case "gt": - func = (Stack stack) -> { - ISBPLObject o2 = stack.pop(); - ISBPLObject o1 = stack.pop(); - o1.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); - o2.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); - stack.push(new ISBPLObject(getType("int"), o1.toDouble() > o2.toDouble() ? 1 : 0)); - }; - break; - case "lt": - func = (Stack stack) -> { - ISBPLObject o2 = stack.pop(); - ISBPLObject o1 = stack.pop(); - o1.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); - o2.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); - stack.push(new ISBPLObject(getType("int"), o1.toDouble() < o2.toDouble() ? 1 : 0)); - }; - break; - case "not": - func = (Stack stack) -> stack.push(new ISBPLObject(getType("int"), stack.pop().isTruthy() ? 0 : 1)); - break; - case "neg": - func = (Stack stack) -> { - ISBPLObject o = stack.pop(); - o.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); - stack.push(new ISBPLObject(o.type, o.negative())); - }; - break; - case "or": - func = (Stack stack) -> { - ISBPLObject o2 = stack.pop(); - ISBPLObject o1 = stack.pop(); - if(o1.isTruthy()) - stack.push(o1); - else - stack.push(o2); - }; - break; - case "and": - func = (Stack stack) -> { - ISBPLObject o2 = stack.pop(); - ISBPLObject o1 = stack.pop(); - // Pushes either 1 or the failed object - if (o1.isTruthy()) { - if (o2.isTruthy()) - stack.push(new ISBPLObject(getType("int"), 1)); + }; + break; + case "putchar": + func = (Stack stack) -> { + ISBPLObject c = stack.pop(); + c.checkType(getType("char")); + System.out.print(((char) c.object)); + }; + break; + case "eputchar": + func = (Stack stack) -> { + ISBPLObject c = stack.pop(); + c.checkType(getType("char")); + System.err.print(((char) c.object)); + }; + break; + case "_file": + func = (Stack stack) -> { + ISBPLObject s = stack.pop(); + File f = new File(toJavaString(s)); + stack.push(new ISBPLObject(getType("file"), f)); + }; + break; + case "read": + func = (Stack stack) -> { + ISBPLObject end = stack.pop(); + ISBPLObject begin = stack.pop(); + ISBPLObject fileToRead = stack.pop(); + end.checkType(getType("int")); + begin.checkType(getType("int")); + fileToRead.checkType(getType("file")); + try(FileInputStream f = new FileInputStream((File) fileToRead.object)) { + int b = ((int) begin.object); + int e = ((int) end.object); + byte[] bytes = new byte[e - b]; + f.read(bytes, b, e); + ISBPLObject[] arr = new ISBPLObject[bytes.length]; + for (int i = 0 ; i < arr.length ; i++) { + arr[i] = new ISBPLObject(getType("byte"), bytes[i]); + } + stack.push(new ISBPLObject(getType("array"), arr)); + } + catch (FileNotFoundException e) { + throw new ISBPLError("FileNotFound", "File not found."); + } + catch (IOException e) { + throw new ISBPLError("IO", "File couldn't be read from" + (e.getMessage() != null ? ": " + e.getMessage() : ".")); + } + }; + break; + case "flength": + func = (Stack stack) -> { + ISBPLObject f = stack.pop(); + f.checkType(getType("file")); + stack.push(new ISBPLObject(getType("int"), ((int) ((File) f.object).length()))); + }; + break; + case "write": + func = (Stack stack) -> { + ISBPLObject content = stack.pop(); + ISBPLObject fileToWrite = stack.pop(); + content.checkType(getType("array")); + fileToWrite.checkType(getType("file")); + throw new ISBPLError("NotImplemented", "_file write is not implemented"); + }; + break; + case "getos": + func = (Stack stack) -> { + // TODO: This is not done yet, and it's horrible so far. + stack.push(toISBPLString("linux")); + }; + break; + case "mktype": + func = (Stack stack) -> { + ISBPLObject s = stack.pop(); + ISBPLType type = registerType(toJavaString(s)); + stack.push(new ISBPLObject(getType("int"), type.id)); + }; + break; + case "typename": + func = (Stack stack) -> { + ISBPLObject i = stack.pop(); + i.checkType(getType("int")); + stack.push(toISBPLString(types.get(((int) i.object)).name)); + }; + break; + case "gettype": + func = (Stack stack) -> { + ISBPLObject o = stack.pop(); + stack.push(new ISBPLObject(getType("int"), o.type.id)); + }; + break; + case "settype": + func = (Stack stack) -> { + ISBPLObject i = stack.pop(); + ISBPLObject o = stack.pop(); + i.checkType(getType("int")); + stack.push(new ISBPLObject(types.get(((int) i.object)), o.object)); + }; + break; + case "throw": + func = (Stack stack) -> { + ISBPLObject message = stack.pop(); + ISBPLObject type = stack.pop(); + String msg = toJavaString(message); + String t = toJavaString(type); + throw new ISBPLError(t, msg); + }; + break; + case "exit": + func = (Stack stack) -> { + ISBPLObject code = stack.pop(); + code.checkType(getType("int")); + exitCode = ((int) code.object); + throw new ISBPLStop(0); + }; + break; + case "eq": + func = (Stack stack) -> { + ISBPLObject o1 = stack.pop(); + ISBPLObject o2 = stack.pop(); + stack.push(new ISBPLObject(getType("int"), o1.equals(o2) ? 1 : 0)); + }; + break; + case "gt": + func = (Stack stack) -> { + ISBPLObject o2 = stack.pop(); + ISBPLObject o1 = stack.pop(); + o1.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); + o2.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); + stack.push(new ISBPLObject(getType("int"), o1.toDouble() > o2.toDouble() ? 1 : 0)); + }; + break; + case "lt": + func = (Stack stack) -> { + ISBPLObject o2 = stack.pop(); + ISBPLObject o1 = stack.pop(); + o1.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); + o2.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); + stack.push(new ISBPLObject(getType("int"), o1.toDouble() < o2.toDouble() ? 1 : 0)); + }; + break; + case "not": + func = (Stack stack) -> stack.push(new ISBPLObject(getType("int"), stack.pop().isTruthy() ? 0 : 1)); + break; + case "neg": + func = (Stack stack) -> { + ISBPLObject o = stack.pop(); + o.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); + stack.push(new ISBPLObject(o.type, o.negative())); + }; + break; + case "or": + func = (Stack stack) -> { + ISBPLObject o2 = stack.pop(); + ISBPLObject o1 = stack.pop(); + if(o1.isTruthy()) + stack.push(o1); else stack.push(o2); - } - else - stack.push(o1); - }; - break; - case "+": - func = (Stack stack) -> { - ISBPLObject o2 = stack.pop(); - ISBPLObject o1 = stack.pop(); - o1.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); - o2.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); - Object object1 = o1.object; - Object object2 = o2.object; - ISBPLObject r = null; - if(object1 instanceof Integer && object2 instanceof Integer) { - r = new ISBPLObject(getType("int"), (int) ((int) (Integer) object1 + (int) (Integer) object2)); - } - if(object1 instanceof Long && object2 instanceof Long) { - r = new ISBPLObject(getType("long"), (long) ((long) (Long) object1 + (long) (Long) object2)); - } - if(object1 instanceof Character && object2 instanceof Character) { - r = new ISBPLObject(getType("char"), (char) ((char) (Character) object1 + (char) (Character) object2)); - } - if(object1 instanceof Byte && object2 instanceof Byte) { - r = new ISBPLObject(getType("byte"), (byte) (Byte.toUnsignedInt((Byte) object1) + Byte.toUnsignedInt((Byte) object2))); - } - if(object1 instanceof Float && object2 instanceof Float) { - r = new ISBPLObject(getType("float"), (float) ((float) (Float) object1 + (float) (Float) object2)); - } - if(object1 instanceof Double && object2 instanceof Double) { - r = new ISBPLObject(getType("double"), (double) ((double) (Double) object1 + (double) (Double) object2)); - } - if(r != null) - stack.push(r); - else - typeError(o1.type.name, o2.type.name); - }; - break; - case "-": - func = (Stack stack) -> { - ISBPLObject o2 = stack.pop(); - ISBPLObject o1 = stack.pop(); - o1.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); - o2.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); - Object object1 = o1.object; - Object object2 = o2.object; - ISBPLObject r = null; - if(object1 instanceof Integer && object2 instanceof Integer) { - r = new ISBPLObject(getType("int"), (int) ((int) (Integer) object1 - (int) (Integer) object2)); - } - if(object1 instanceof Long && object2 instanceof Long) { - r = new ISBPLObject(getType("long"), (long) ((long) (Long) object1 - (long) (Long) object2)); - } - if(object1 instanceof Character && object2 instanceof Character) { - r = new ISBPLObject(getType("char"), (char) ((char) (Character) object1 - (char) (Character) object2)); - } - if(object1 instanceof Byte && object2 instanceof Byte) { - r = new ISBPLObject(getType("byte"), (byte) (Byte.toUnsignedInt((Byte) object1) - Byte.toUnsignedInt((Byte) object2))); - } - if(object1 instanceof Float && object2 instanceof Float) { - r = new ISBPLObject(getType("float"), (float) ((float) (Float) object1 - (float) (Float) object2)); - } - if(object1 instanceof Double && object2 instanceof Double) { - r = new ISBPLObject(getType("double"), (double) ((double) (Double) object1 - (double) (Double) object2)); - } - if(r != null) - stack.push(r); - else - typeError(o1.type.name, o2.type.name); - }; - break; - case "/": - func = (Stack stack) -> { - try { + }; + break; + case "and": + func = (Stack stack) -> { + ISBPLObject o2 = stack.pop(); + ISBPLObject o1 = stack.pop(); + // Pushes either 1 or the failed object + if (o1.isTruthy()) { + if (o2.isTruthy()) + stack.push(new ISBPLObject(getType("int"), 1)); + else + stack.push(o2); + } + else + stack.push(o1); + }; + break; + case "+": + func = (Stack stack) -> { ISBPLObject o2 = stack.pop(); ISBPLObject o1 = stack.pop(); o1.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); @@ -618,102 +547,32 @@ public class ISBPL { Object object1 = o1.object; Object object2 = o2.object; ISBPLObject r = null; - if (object1 instanceof Integer && object2 instanceof Integer) { - r = new ISBPLObject(getType("int"), (int) ((int) (Integer) object1 / (int) (Integer) object2)); + if(object1 instanceof Integer && object2 instanceof Integer) { + r = new ISBPLObject(getType("int"), (int) ((int) (Integer) object1 + (int) (Integer) object2)); } - if (object1 instanceof Long && object2 instanceof Long) { - r = new ISBPLObject(getType("long"), (long) ((long) (Long) object1 / (long) (Long) object2)); + if(object1 instanceof Long && object2 instanceof Long) { + r = new ISBPLObject(getType("long"), (long) ((long) (Long) object1 + (long) (Long) object2)); } - if (object1 instanceof Character && object2 instanceof Character) { - r = new ISBPLObject(getType("char"), (char) ((char) (Character) object1 / (char) (Character) object2)); + if(object1 instanceof Character && object2 instanceof Character) { + r = new ISBPLObject(getType("char"), (char) ((char) (Character) object1 + (char) (Character) object2)); } - if (object1 instanceof Byte && object2 instanceof Byte) { - r = new ISBPLObject(getType("byte"), (byte) (Byte.toUnsignedInt((Byte) object1) / Byte.toUnsignedInt((Byte) object2))); + if(object1 instanceof Byte && object2 instanceof Byte) { + r = new ISBPLObject(getType("byte"), (byte) (Byte.toUnsignedInt((Byte) object1) + Byte.toUnsignedInt((Byte) object2))); } - if (object1 instanceof Float && object2 instanceof Float) { - r = new ISBPLObject(getType("float"), (float) ((float) (Float) object1 / (float) (Float) object2)); + if(object1 instanceof Float && object2 instanceof Float) { + r = new ISBPLObject(getType("float"), (float) ((float) (Float) object1 + (float) (Float) object2)); } - if (object1 instanceof Double && object2 instanceof Double) { - r = new ISBPLObject(getType("double"), (double) ((double) (Double) object1 / (double) (Double) object2)); + if(object1 instanceof Double && object2 instanceof Double) { + r = new ISBPLObject(getType("double"), (double) ((double) (Double) object1 + (double) (Double) object2)); } - if (r != null) + if(r != null) stack.push(r); else typeError(o1.type.name, o2.type.name); - } catch (ArithmeticException ex) { - throw new ISBPLError("Arithmetic", "Division by 0"); - } - }; - break; - case "*": - func = (Stack stack) -> { - ISBPLObject o2 = stack.pop(); - ISBPLObject o1 = stack.pop(); - o1.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); - o2.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); - Object object1 = o1.object; - Object object2 = o2.object; - ISBPLObject r = null; - if(object1 instanceof Integer && object2 instanceof Integer) { - r = new ISBPLObject(getType("int"), (int) ((int) (Integer) object1 * (int) (Integer) object2)); - } - if(object1 instanceof Long && object2 instanceof Long) { - r = new ISBPLObject(getType("long"), (long) ((long) (Long) object1 * (long) (Long) object2)); - } - if(object1 instanceof Character && object2 instanceof Character) { - r = new ISBPLObject(getType("char"), (char) ((char) (Character) object1 * (char) (Character) object2)); - } - if(object1 instanceof Byte && object2 instanceof Byte) { - r = new ISBPLObject(getType("byte"), (byte) (Byte.toUnsignedInt((Byte) object1) * Byte.toUnsignedInt((Byte) object2))); - } - if(object1 instanceof Float && object2 instanceof Float) { - r = new ISBPLObject(getType("float"), (float) ((float) (Float) object1 * (float) (Float) object2)); - } - if(object1 instanceof Double && object2 instanceof Double) { - r = new ISBPLObject(getType("double"), (double) ((double) (Double) object1 * (double) (Double) object2)); - } - if(r != null) - stack.push(r); - else - typeError(o1.type.name, o2.type.name); - }; - break; - case "**": - func = (Stack stack) -> { - ISBPLObject o2 = stack.pop(); - ISBPLObject o1 = stack.pop(); - o1.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); - o2.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); - Object object1 = o1.object; - Object object2 = o2.object; - ISBPLObject r = null; - if(object1 instanceof Integer && object2 instanceof Integer) { - r = new ISBPLObject(getType("int"), (int) Math.pow((int) (Integer) object1, (int) (Integer) object2)); - } - if(object1 instanceof Long && object2 instanceof Long) { - r = new ISBPLObject(getType("long"), (long) Math.pow((long) (Long) object1, (long) (Long) object2)); - } - if(object1 instanceof Character && object2 instanceof Character) { - r = new ISBPLObject(getType("char"), (char) Math.pow((char) (Character) object1, (char) (Character) object2)); - } - if(object1 instanceof Byte && object2 instanceof Byte) { - r = new ISBPLObject(getType("byte"), (byte) Math.pow(Byte.toUnsignedInt((Byte) object1), Byte.toUnsignedInt((Byte) object2))); - } - if(object1 instanceof Float && object2 instanceof Float) { - r = new ISBPLObject(getType("float"), (float) Math.pow((float) (Float) object1, (float) (Float) object2)); - } - if(object1 instanceof Double && object2 instanceof Double) { - r = new ISBPLObject(getType("double"), (double) Math.pow((double) (Double) object1, (double) (Double) object2)); - } - if(r != null) - stack.push(r); - else - typeError(o1.type.name, o2.type.name); - }; - break; - case "%": - func = (Stack stack) -> { - try { + }; + break; + case "-": + func = (Stack stack) -> { ISBPLObject o2 = stack.pop(); ISBPLObject o1 = stack.pop(); o1.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); @@ -721,171 +580,308 @@ public class ISBPL { Object object1 = o1.object; Object object2 = o2.object; ISBPLObject r = null; - if (object1 instanceof Integer && object2 instanceof Integer) { - r = new ISBPLObject(getType("int"), (int) ((int) (Integer) object1 % (int) (Integer) object2)); + if(object1 instanceof Integer && object2 instanceof Integer) { + r = new ISBPLObject(getType("int"), (int) ((int) (Integer) object1 - (int) (Integer) object2)); } - if (object1 instanceof Long && object2 instanceof Long) { - r = new ISBPLObject(getType("long"), (long) ((long) (Long) object1 % (long) (Long) object2)); + if(object1 instanceof Long && object2 instanceof Long) { + r = new ISBPLObject(getType("long"), (long) ((long) (Long) object1 - (long) (Long) object2)); } - if (object1 instanceof Character && object2 instanceof Character) { - r = new ISBPLObject(getType("char"), (char) ((char) (Character) object1 % (char) (Character) object2)); + if(object1 instanceof Character && object2 instanceof Character) { + r = new ISBPLObject(getType("char"), (char) ((char) (Character) object1 - (char) (Character) object2)); } - if (object1 instanceof Byte && object2 instanceof Byte) { - r = new ISBPLObject(getType("byte"), (byte) (Byte.toUnsignedInt((Byte) object1) % Byte.toUnsignedInt((Byte) object2))); + if(object1 instanceof Byte && object2 instanceof Byte) { + r = new ISBPLObject(getType("byte"), (byte) (Byte.toUnsignedInt((Byte) object1) - Byte.toUnsignedInt((Byte) object2))); } - if (object1 instanceof Float && object2 instanceof Float) { - r = new ISBPLObject(getType("float"), (float) ((float) (Float) object1 % (float) (Float) object2)); + if(object1 instanceof Float && object2 instanceof Float) { + r = new ISBPLObject(getType("float"), (float) ((float) (Float) object1 - (float) (Float) object2)); } - if (object1 instanceof Double && object2 instanceof Double) { - r = new ISBPLObject(getType("double"), (double) ((double) (Double) object1 % (double) (Double) object2)); + if(object1 instanceof Double && object2 instanceof Double) { + r = new ISBPLObject(getType("double"), (double) ((double) (Double) object1 - (double) (Double) object2)); } - if (r != null) + if(r != null) stack.push(r); else typeError(o1.type.name, o2.type.name); - } catch (ArithmeticException ex) { - throw new ISBPLError("Arithmetic", "Division by 0"); - } - }; - break; - case "^": - func = (Stack stack) -> { - ISBPLObject o2 = stack.pop(); - ISBPLObject o1 = stack.pop(); - o1.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("long")); - o2.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("long")); - Object object1 = o1.object; - Object object2 = o2.object; - ISBPLObject r = null; - if(object1 instanceof Integer && object2 instanceof Integer) { - r = new ISBPLObject(getType("int"), (int) ((int) (Integer) object1 ^ (int) (Integer) object2)); - } - if(object1 instanceof Long && object2 instanceof Long) { - r = new ISBPLObject(getType("long"), (long) ((long) (Long) object1 ^ (long) (Long) object2)); - } - if(object1 instanceof Character && object2 instanceof Character) { - r = new ISBPLObject(getType("char"), (char) ((char) (Character) object1 ^ (char) (Character) object2)); - } - if(object1 instanceof Byte && object2 instanceof Byte) { - r = new ISBPLObject(getType("byte"), Byte.toUnsignedInt((Byte) object1) ^ Byte.toUnsignedInt((Byte) object2)); - } - if(r != null) - stack.push(r); - else - typeError(o1.type.name, o2.type.name); - }; - break; - case "dup": - func = (Stack stack) -> { - ISBPLObject o = stack.pop(); - stack.push(new ISBPLObject(o.type, o.object)); - stack.push(new ISBPLObject(o.type, o.object)); - }; - break; - case "pop": - func = Stack::pop; - break; - case "swap": - func = (Stack stack) -> { - ISBPLObject o1 = stack.pop(); - ISBPLObject o2 = stack.pop(); - stack.push(o1); - stack.push(o2); - }; - break; - case "_last_word": - func = (Stack stack) -> { - ISBPLObject i = stack.pop(); - i.checkType(getType("int")); - int n = (int) i.object; - if(n >= lastWords.get().size()) - throw new ISBPLError("IllegalArgument", "_last_words called with wrong argument"); - stack.push(toISBPLString(lastWords.get().get(n))); - }; - break; - case "time": - func = (Stack stack) -> { - ISBPLObject i = stack.pop(); - long n = (long) i.toLong(); - try { - Thread.sleep(n); - } - catch (InterruptedException e) { - e.printStackTrace(); - } - stack.push(new ISBPLObject(getType("long"), System.currentTimeMillis())); - }; - break; - case "stream": - func = (Stack stack) -> { - ISBPLObject action = stack.pop(); - action.checkType(getType("int")); - int n = ((int) action.object); - try { - streamer.action(stack, n); - } - catch (IOException e) { - throw new ISBPLError("IO", e.getMessage()); - } - }; - break; - case "_enable_debug": - func = (Stack stack) -> { - if(debuggerIPC.threadID == -1) { - ISBPLDebugger debugger = new ISBPLDebugger(this); - debugger.start(); + }; + break; + case "/": + func = (Stack stack) -> { try { - while(debuggerIPC.threadID == -1) Thread.sleep(1); + ISBPLObject o2 = stack.pop(); + ISBPLObject o1 = stack.pop(); + o1.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); + o2.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); + Object object1 = o1.object; + Object object2 = o2.object; + ISBPLObject r = null; + if (object1 instanceof Integer && object2 instanceof Integer) { + r = new ISBPLObject(getType("int"), (int) ((int) (Integer) object1 / (int) (Integer) object2)); + } + if (object1 instanceof Long && object2 instanceof Long) { + r = new ISBPLObject(getType("long"), (long) ((long) (Long) object1 / (long) (Long) object2)); + } + if (object1 instanceof Character && object2 instanceof Character) { + r = new ISBPLObject(getType("char"), (char) ((char) (Character) object1 / (char) (Character) object2)); + } + if (object1 instanceof Byte && object2 instanceof Byte) { + r = new ISBPLObject(getType("byte"), (byte) (Byte.toUnsignedInt((Byte) object1) / Byte.toUnsignedInt((Byte) object2))); + } + if (object1 instanceof Float && object2 instanceof Float) { + r = new ISBPLObject(getType("float"), (float) ((float) (Float) object1 / (float) (Float) object2)); + } + if (object1 instanceof Double && object2 instanceof Double) { + r = new ISBPLObject(getType("double"), (double) ((double) (Double) object1 / (double) (Double) object2)); + } + if (r != null) + stack.push(r); + else + typeError(o1.type.name, o2.type.name); + } catch (ArithmeticException ex) { + throw new ISBPLError("Arithmetic", "Division by 0"); + } + }; + break; + case "*": + func = (Stack stack) -> { + ISBPLObject o2 = stack.pop(); + ISBPLObject o1 = stack.pop(); + o1.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); + o2.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); + Object object1 = o1.object; + Object object2 = o2.object; + ISBPLObject r = null; + if(object1 instanceof Integer && object2 instanceof Integer) { + r = new ISBPLObject(getType("int"), (int) ((int) (Integer) object1 * (int) (Integer) object2)); + } + if(object1 instanceof Long && object2 instanceof Long) { + r = new ISBPLObject(getType("long"), (long) ((long) (Long) object1 * (long) (Long) object2)); + } + if(object1 instanceof Character && object2 instanceof Character) { + r = new ISBPLObject(getType("char"), (char) ((char) (Character) object1 * (char) (Character) object2)); + } + if(object1 instanceof Byte && object2 instanceof Byte) { + r = new ISBPLObject(getType("byte"), (byte) (Byte.toUnsignedInt((Byte) object1) * Byte.toUnsignedInt((Byte) object2))); + } + if(object1 instanceof Float && object2 instanceof Float) { + r = new ISBPLObject(getType("float"), (float) ((float) (Float) object1 * (float) (Float) object2)); + } + if(object1 instanceof Double && object2 instanceof Double) { + r = new ISBPLObject(getType("double"), (double) ((double) (Double) object1 * (double) (Double) object2)); + } + if(r != null) + stack.push(r); + else + typeError(o1.type.name, o2.type.name); + }; + break; + case "**": + func = (Stack stack) -> { + ISBPLObject o2 = stack.pop(); + ISBPLObject o1 = stack.pop(); + o1.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); + o2.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); + Object object1 = o1.object; + Object object2 = o2.object; + ISBPLObject r = null; + if(object1 instanceof Integer && object2 instanceof Integer) { + r = new ISBPLObject(getType("int"), (int) Math.pow((int) (Integer) object1, (int) (Integer) object2)); + } + if(object1 instanceof Long && object2 instanceof Long) { + r = new ISBPLObject(getType("long"), (long) Math.pow((long) (Long) object1, (long) (Long) object2)); + } + if(object1 instanceof Character && object2 instanceof Character) { + r = new ISBPLObject(getType("char"), (char) Math.pow((char) (Character) object1, (char) (Character) object2)); + } + if(object1 instanceof Byte && object2 instanceof Byte) { + r = new ISBPLObject(getType("byte"), (byte) Math.pow(Byte.toUnsignedInt((Byte) object1), Byte.toUnsignedInt((Byte) object2))); + } + if(object1 instanceof Float && object2 instanceof Float) { + r = new ISBPLObject(getType("float"), (float) Math.pow((float) (Float) object1, (float) (Float) object2)); + } + if(object1 instanceof Double && object2 instanceof Double) { + r = new ISBPLObject(getType("double"), (double) Math.pow((double) (Double) object1, (double) (Double) object2)); + } + if(r != null) + stack.push(r); + else + typeError(o1.type.name, o2.type.name); + }; + break; + case "%": + func = (Stack stack) -> { + try { + ISBPLObject o2 = stack.pop(); + ISBPLObject o1 = stack.pop(); + o1.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); + o2.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("float"), getType("long"), getType("double")); + Object object1 = o1.object; + Object object2 = o2.object; + ISBPLObject r = null; + if (object1 instanceof Integer && object2 instanceof Integer) { + r = new ISBPLObject(getType("int"), (int) ((int) (Integer) object1 % (int) (Integer) object2)); + } + if (object1 instanceof Long && object2 instanceof Long) { + r = new ISBPLObject(getType("long"), (long) ((long) (Long) object1 % (long) (Long) object2)); + } + if (object1 instanceof Character && object2 instanceof Character) { + r = new ISBPLObject(getType("char"), (char) ((char) (Character) object1 % (char) (Character) object2)); + } + if (object1 instanceof Byte && object2 instanceof Byte) { + r = new ISBPLObject(getType("byte"), (byte) (Byte.toUnsignedInt((Byte) object1) % Byte.toUnsignedInt((Byte) object2))); + } + if (object1 instanceof Float && object2 instanceof Float) { + r = new ISBPLObject(getType("float"), (float) ((float) (Float) object1 % (float) (Float) object2)); + } + if (object1 instanceof Double && object2 instanceof Double) { + r = new ISBPLObject(getType("double"), (double) ((double) (Double) object1 % (double) (Double) object2)); + } + if (r != null) + stack.push(r); + else + typeError(o1.type.name, o2.type.name); + } catch (ArithmeticException ex) { + throw new ISBPLError("Arithmetic", "Division by 0"); + } + }; + break; + case "^": + func = (Stack stack) -> { + ISBPLObject o2 = stack.pop(); + ISBPLObject o1 = stack.pop(); + o1.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("long")); + o2.checkTypeMulti(getType("int"), getType("byte"), getType("char"), getType("long")); + Object object1 = o1.object; + Object object2 = o2.object; + ISBPLObject r = null; + if(object1 instanceof Integer && object2 instanceof Integer) { + r = new ISBPLObject(getType("int"), (int) ((int) (Integer) object1 ^ (int) (Integer) object2)); + } + if(object1 instanceof Long && object2 instanceof Long) { + r = new ISBPLObject(getType("long"), (long) ((long) (Long) object1 ^ (long) (Long) object2)); + } + if(object1 instanceof Character && object2 instanceof Character) { + r = new ISBPLObject(getType("char"), (char) ((char) (Character) object1 ^ (char) (Character) object2)); + } + if(object1 instanceof Byte && object2 instanceof Byte) { + r = new ISBPLObject(getType("byte"), Byte.toUnsignedInt((Byte) object1) ^ Byte.toUnsignedInt((Byte) object2)); + } + if(r != null) + stack.push(r); + else + typeError(o1.type.name, o2.type.name); + }; + break; + case "dup": + func = (Stack stack) -> { + ISBPLObject o = stack.pop(); + stack.push(new ISBPLObject(o.type, o.object)); + stack.push(new ISBPLObject(o.type, o.object)); + }; + break; + case "pop": + func = Stack::pop; + break; + case "swap": + func = (Stack stack) -> { + ISBPLObject o1 = stack.pop(); + ISBPLObject o2 = stack.pop(); + stack.push(o1); + stack.push(o2); + }; + break; + case "_last_word": + func = (Stack stack) -> { + ISBPLObject i = stack.pop(); + i.checkType(getType("int")); + int n = (int) i.object; + if(n >= lastWords.get().size()) + throw new ISBPLError("IllegalArgument", "_last_words called with wrong argument"); + stack.push(toISBPLString(lastWords.get().get(n))); + }; + break; + case "time": + func = (Stack stack) -> { + ISBPLObject i = stack.pop(); + long n = (long) i.toLong(); + try { + Thread.sleep(n); } catch (InterruptedException e) { e.printStackTrace(); } - } - stack.push(new ISBPLObject(getType("int"), debuggerIPC.port)); - }; - break; - case "_getvars": - func = (Stack stack) -> { - ISBPLObject[] objects = new ISBPLObject[functionStack.get().size()]; - int i = 0; - for (HashMap map : functionStack.get()) { - ArrayList strings = new ArrayList<>(); - for (String key : map.keySet()) { - if(key.startsWith("=")) { - strings.add(toISBPLString(key.substring(1))); + stack.push(new ISBPLObject(getType("long"), System.currentTimeMillis())); + }; + break; + case "stream": + func = (Stack stack) -> { + ISBPLObject action = stack.pop(); + action.checkType(getType("int")); + int n = ((int) action.object); + try { + streamer.action(stack, n); + } + catch (IOException e) { + throw new ISBPLError("IO", e.getMessage()); + } + }; + break; + case "_enable_debug": + func = (Stack stack) -> { + if(debuggerIPC.threadID == -1) { + ISBPLDebugger debugger = new ISBPLDebugger(this); + debugger.start(); + try { + while(debuggerIPC.threadID == -1) Thread.sleep(1); + } + catch (InterruptedException e) { + e.printStackTrace(); } } - objects[i++] = new ISBPLObject(getType("array"), strings.toArray(new ISBPLObject[0])); - } - ISBPLObject array = new ISBPLObject(getType("array"), objects); - stack.push(array); - }; - break; - case "stacksize": - func = (Stack stack) -> stack.push(new ISBPLObject(getType("int"), stack.size())); - break; - case "fcall": - func = (Stack stack) -> { - ISBPLObject o = stack.pop(); - o.checkType(getType("func")); - ((ISBPLCallable) o.object).call(stack); - }; - break; - case "subprocess": - func = (Stack stack) -> { - try { - Runtime.getRuntime().exec(toJavaString(stack.pop())); - } catch(IOException e) { - throw new ISBPLError("IO", "Couldn't start process"); - } - }; - break; - case "deffunc": - func = (stack) -> { - ISBPLObject str = stack.pop(); - ISBPLObject callable = stack.pop(); - String s = toJavaString(str); - callable.checkType(getType("func")); + stack.push(new ISBPLObject(getType("int"), debuggerIPC.port)); + }; + break; + case "_getvars": + func = (Stack stack) -> { + ISBPLObject[] objects = new ISBPLObject[functionStack.get().size()]; + int i = 0; + for (HashMap map : functionStack.get()) { + ArrayList strings = new ArrayList<>(); + for (String key : map.keySet()) { + if(key.startsWith("=")) { + strings.add(toISBPLString(key.substring(1))); + } + } + objects[i++] = new ISBPLObject(getType("array"), strings.toArray(new ISBPLObject[0])); + } + ISBPLObject array = new ISBPLObject(getType("array"), objects); + stack.push(array); + }; + break; + case "stacksize": + func = (Stack stack) -> stack.push(new ISBPLObject(getType("int"), stack.size())); + break; + case "fcall": + func = (Stack stack) -> { + ISBPLObject o = stack.pop(); + o.checkType(getType("func")); + ((ISBPLCallable) o.object).call(stack); + }; + break; + case "subprocess": + func = (Stack stack) -> { + try { + Runtime.getRuntime().exec(toJavaString(stack.pop())); + } catch(IOException e) { + throw new ISBPLError("IO", "Couldn't start process"); + } + }; + break; + case "deffunc": + func = (stack) -> { + ISBPLObject str = stack.pop(); + ISBPLObject callable = stack.pop(); + String s = toJavaString(str); + callable.checkType(getType("func")); addFunction(s, (ISBPLCallable) callable.object); }; break; @@ -972,7 +968,7 @@ public class ISBPL { return nullObj; } - private Object syncJIOClass = new Object(); + private final Object syncJIOClass = new Object(); public ISBPLObject toISBPL(Class clazz) { synchronized(syncJIOClass) { ISBPLType type = getType(clazz.getName()); @@ -1063,7 +1059,7 @@ public class ISBPL { for (Map.Entry>> entry : constructors.entrySet()) { addFunction(type, "new" + entry.getKey(), stack -> { stack.pop(); - + AtomicInteger mid = new AtomicInteger(0); ArrayList> ms = entry.getValue(); Class[][] paramTypes = new Class[ms.size()][ms.get(0).getParameterCount()]; @@ -1123,27 +1119,6 @@ public class ISBPL { return params[mid.get()]; } - private Object syncFromISBPL = new Object(); - private Object fromISBPL(ISBPLObject o) { - synchronized(syncFromISBPL) { - ISBPLType type = o.type; - if (type.equals(getType("null"))) { - return null; - } - if (type.equals(getType("string"))) - return toJavaString(o); - if (type.equals(getType("array"))) { - ISBPLObject[] isbplArray = ((ISBPLObject[]) o.object); - Object[] array = new Object[isbplArray.length]; - for (int i = 0 ; i < array.length ; i++) { - array[i] = fromISBPL(isbplArray[i]); - } - return array; - } - return o.object; - } - } - public Object primitiveDefault(Class expectedType) { if(expectedType == long.class) return 0L; @@ -1165,87 +1140,82 @@ public class ISBPL { } public Object fromISBPL(ISBPLObject o, Class expectedType) { - synchronized(syncFromISBPL) { - ISBPLType type = o.type; - if (type.equals(getType("null"))) { - return null; - } - if (type.equals(getType("string"))) { - if(expectedType.isAssignableFrom(String.class)) - return toJavaString(o); - else - typeError("string", expectedType.getName()); - } - if (type.equals(getType("array"))) { - ISBPLObject[] isbplArray = ((ISBPLObject[]) o.object); - Object array = new Object[isbplArray.length]; - if(expectedType.isArray()) - array = Array.newInstance(expectedType.getComponentType(), isbplArray.length); - else - typeError("array", "matching-array"); - for (int i = 0 ; i < isbplArray.length ; i++) { - Object obj = fromISBPL(isbplArray[i], expectedType.getComponentType()); - Array.set(array, i, obj == null && expectedType.getComponentType().isPrimitive() ? primitiveDefault(expectedType.getComponentType()) : obj); - } - return array; - } - if(expectedType.isPrimitive()) { - if(expectedType == long.class) - return o.toLong(); - if(expectedType == int.class) - return (int) o.toLong(); - if(expectedType == double.class) - return o.toDouble(); - if(expectedType == float.class) - return (float) o.toDouble(); - if(expectedType == short.class) - return (short) o.toLong(); - if(expectedType == boolean.class) - return o.isTruthy(); - if(expectedType == char.class) - return (char) o.toLong(); - if(expectedType == byte.class) - return (byte) o.toLong(); - } - if(!expectedType.isAssignableFrom(o.object.getClass())) - typeError(o.type.name, expectedType.getName()); - return o.object; + ISBPLType type = o.type; + if (type.equals(getType("null"))) { + return null; } + if (type.equals(getType("string"))) { + if(expectedType.isAssignableFrom(String.class)) + return toJavaString(o); + else + typeError("string", expectedType.getName()); + } + if (type.equals(getType("array"))) { + ISBPLObject[] isbplArray = ((ISBPLObject[]) o.object); + Object array = new Object[isbplArray.length]; + if(expectedType.isArray()) + array = Array.newInstance(expectedType.getComponentType(), isbplArray.length); + else + typeError("array", "matching-array"); + for (int i = 0 ; i < isbplArray.length ; i++) { + Object obj = fromISBPL(isbplArray[i], expectedType.getComponentType()); + Array.set(array, i, obj == null && expectedType.getComponentType().isPrimitive() ? primitiveDefault(expectedType.getComponentType()) : obj); + } + return array; + } + if(expectedType.isPrimitive()) { + if(expectedType == long.class) + return o.toLong(); + if(expectedType == int.class) + return (int) o.toLong(); + if(expectedType == double.class) + return o.toDouble(); + if(expectedType == float.class) + return (float) o.toDouble(); + if(expectedType == short.class) + return (short) o.toLong(); + if(expectedType == boolean.class) + return o.isTruthy(); + if(expectedType == char.class) + return (char) o.toLong(); + if(expectedType == byte.class) + return (byte) o.toLong(); + } + if(!expectedType.isAssignableFrom(o.object.getClass())) + typeError(o.type.name, expectedType.getName()); + return o.object; } - private Object syncToISBPL = new Object(); public ISBPLObject toISBPL(Object object) { - synchronized (syncToISBPL) { - if(object == null) { - return new ISBPLObject(getType("null"), 0); - } - ISBPLObject o = toISBPL(object.getClass()); - if (object instanceof String) { - return toISBPLString(((String) object)); - } - if (object instanceof Integer) - return new ISBPLObject(getType("int"), object); - if (object instanceof Character) - return new ISBPLObject(getType("char"), object); - if (object instanceof Byte) - return new ISBPLObject(getType("byte"), object); - if (object instanceof Float) - return new ISBPLObject(getType("float"), object); - if (object instanceof Long) - return new ISBPLObject(getType("long"), object); - if (object instanceof Double) - return new ISBPLObject(getType("double"), object); - if (object.getClass().isArray()) { - ISBPLObject[] isbplArray = new ISBPLObject[Array.getLength(object)]; - for (int i = 0 ; i < isbplArray.length ; i++) { - isbplArray[i] = toISBPL(Array.get(object, i)); - } - o.type = getType("array"); - object = isbplArray; - } - o.object = object; - return o; + if(object == null) { + return getNullObject(); } + ISBPLObject o = toISBPL(object.getClass()); + if (object instanceof String) { + return toISBPLString(((String) object)); + } + if (object instanceof Integer) + return new ISBPLObject(getType("int"), object); + if (object instanceof Character) + return new ISBPLObject(getType("char"), object); + if (object instanceof Byte) + return new ISBPLObject(getType("byte"), object); + if (object instanceof Float) + return new ISBPLObject(getType("float"), object); + if (object instanceof Long) + return new ISBPLObject(getType("long"), object); + if (object instanceof Double) + return new ISBPLObject(getType("double"), object); + if (object.getClass().isArray()) { + ISBPLObject[] isbplArray = new ISBPLObject[Array.getLength(object)]; + for (int i = 0 ; i < isbplArray.length ; i++) { + isbplArray[i] = toISBPL(Array.get(object, i)); + } + o.type = getType("array"); + object = isbplArray; + } + o.object = object; + return o; } public void addFunction(ISBPLType type, String name, ISBPLCallable callable) { @@ -1407,6 +1377,14 @@ public class ISBPL { } if(stack.size() > 0) { // Doing this nonrecursively because it's much better despite the slight readability disadvantage. + if(stack.peek() == null) { + // We need to dump things immediately. + System.err.println("!!! ISBPL WORD PARSER ERROR !!!"); + System.err.println("This is most likely due to a garbage collector malfunction."); + System.err.println("Stack: " + stack); + System.err.println("LastWords: " + lastWords); + System.err.println("FileStack: " + fileStack); + } ISBPLType type = stack.peek().type; Queue types = new LinkedList<>(); types.add(type); @@ -1462,9 +1440,12 @@ public class ISBPL { finally { if(isFunction) { HashMap fstack = functionStack.get().pop(); - for(ISBPLCallable c : fstack.values()) { - if(varLinks.containsKey(c)) { - vars.remove(varLinks.remove(c)); + for(Map.Entry c : fstack.entrySet()) { + if(varLinks.containsKey(c.getValue())) { + vars.remove(varLinks.remove(c.getValue())); + if(printCalls) { + System.err.println("Garbage collector: removed " + c.getKey()); + } } } } @@ -1533,7 +1514,7 @@ public class ISBPL { } public static void main(String[] args) { - Stack stack = new Stack<>(); + Stack stack = new ISBPLStack<>(); ISBPL isbpl = new ISBPL(); isbpl.debuggerIPC.stack.put(Thread.currentThread().getId(), stack); debug = !System.getenv().getOrDefault("DEBUG", "").equals(""); @@ -1566,6 +1547,7 @@ public class ISBPL { } private static String readFile(File f) throws IOException { + //noinspection resource FileInputStream fis = new FileInputStream(f); ByteArrayOutputStream bytes = new ByteArrayOutputStream(); byte[] currentBytes = new byte[4096]; @@ -1637,7 +1619,7 @@ class ISBPLObject { } public boolean isTruthy() { - return object != null && object != Integer.valueOf(0) && !object.equals(Boolean.valueOf(false)); + return object != null && object != Integer.valueOf(0) && !object.equals(Boolean.FALSE); } // This has heavy optimizations, please do not change unless necessary @@ -1802,6 +1784,7 @@ class ISBPLDebugger extends Thread { try { ServerSocket socket = null; try { + //noinspection resource socket = new ServerSocket(Integer.parseInt(System.getenv().getOrDefault("DEBUG", "9736"))); port = socket.getLocalPort(); System.err.println("Debugger listening on :" + socket.getLocalPort()); @@ -1809,6 +1792,7 @@ class ISBPLDebugger extends Thread { catch (BindException e) { while (socket == null) { try { + //noinspection resource socket = new ServerSocket((int) (Math.random() * 5000 + 5000)); port = socket.getLocalPort(); System.err.println("Debugger listening on :" + socket.getLocalPort()); @@ -2033,7 +2017,7 @@ class ISBPLStreamer { s = stack.pop(); s.checkType(isbpl.getType("string")); f = new File(isbpl.toJavaString(s)); - stream = new ISBPLStream(new FileInputStream(f), new OutputStream() { + stream = new ISBPLStream(Files.newInputStream(f.toPath()), new OutputStream() { @Override public void write(int b) { throw new ISBPLError("IllegalArgument", "Can't write to a FILE_IN stream!"); @@ -2051,7 +2035,7 @@ class ISBPLStreamer { public int read() { throw new ISBPLError("IllegalArgument", "Can't read a FILE_OUT stream!"); } - }, new FileOutputStream(f)); + }, Files.newOutputStream(f.toPath())); streams.add(stream); stack.push(new ISBPLObject(isbpl.getType("int"), stream.id)); break; @@ -2143,4 +2127,19 @@ class ISBPLThreadLocal { public synchronized void set(T t) { map.put(Thread.currentThread().getId(), t); } + + @Override + public String toString() { + return get().toString(); + } +} + +class ISBPLStack extends Stack { + + @Override + public T push(T t) { + //if(t == null) + //throw new IllegalArgumentException("item is null"); + return super.push(t); + } }