From af3256d2fbb0fec651b0e761a54d16fe4fea074a Mon Sep 17 00:00:00 2001 From: "Flavio S. Glock" Date: Fri, 2 Aug 2024 13:28:15 +0200 Subject: [PATCH] Perlito5 - misc/Java-Asm-Interpreter/MethodExecutorAsm new Runtime --- .../MethodExecutorAsm/EmitterVisitor.java | 2 +- .../MethodExecutorAsm/Runtime.java | 281 +++++++++++------- .../snippets/runtime_add.java | 118 ++++++++ 3 files changed, 292 insertions(+), 109 deletions(-) create mode 100644 misc/Java-Asm-Interpreter/MethodExecutorAsm/snippets/runtime_add.java diff --git a/misc/Java-Asm-Interpreter/MethodExecutorAsm/EmitterVisitor.java b/misc/Java-Asm-Interpreter/MethodExecutorAsm/EmitterVisitor.java index 440274ac..53faa3ea 100644 --- a/misc/Java-Asm-Interpreter/MethodExecutorAsm/EmitterVisitor.java +++ b/misc/Java-Asm-Interpreter/MethodExecutorAsm/EmitterVisitor.java @@ -474,7 +474,7 @@ public void visit(IfNode node) throws Exception { node.condition.accept(this.with(ContextType.SCALAR)); // Convert the result to a boolean - ctx.mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "Runtime", "toBoolean", "()Z", false); + ctx.mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "Runtime", "getBoolean", "()Z", false); // Jump to the else label if the condition is false ctx.mv.visitJumpInsn(Opcodes.IFEQ, elseLabel); diff --git a/misc/Java-Asm-Interpreter/MethodExecutorAsm/Runtime.java b/misc/Java-Asm-Interpreter/MethodExecutorAsm/Runtime.java index 7db74678..ed07b031 100644 --- a/misc/Java-Asm-Interpreter/MethodExecutorAsm/Runtime.java +++ b/misc/Java-Asm-Interpreter/MethodExecutorAsm/Runtime.java @@ -2,51 +2,170 @@ import java.util.*; public class Runtime { - long i; - String s; - Method subroutineReference; // used by apply() + private enum Type { + INTEGER, DOUBLE, STRING, CODE, UNDEF, REFERENCE + // also BLESSED and special literals like filehandles, typeglobs, and regular expressions + } - public static HashMap> anonSubs = - new HashMap>(); // temp storage for make_sub() - public static HashMap evalContext = - new HashMap(); // storage for eval string compiler context + // TODO add cache for integer/string values + public Type type; + public Object value; - public Runtime() { - this.i = 0; - } + public static HashMap> anonSubs = + new HashMap>(); // temp storage for make_sub() + public static HashMap evalContext = + new HashMap(); // storage for eval string compiler context - public Runtime(long i) { - this.i = i; - } + // Constructors + public Runtime() { + this.type = Type.UNDEF; + this.value = value; + } - public Runtime(int i) { - this.i = (long) i; - } + public Runtime(long value) { + this.type = Type.INTEGER; + this.value = value; + } - public Runtime(String s) { - this.s = s; - } + public Runtime(int value) { + this.type = Type.INTEGER; + this.value = (long) value; + } + + public Runtime(double value) { + this.type = Type.DOUBLE; + this.value = value; + } + + public Runtime(String value) { + this.type = Type.STRING; + this.value = value; + } + + public Runtime(Runtime value) { + this.type = Type.REFERENCE; + this.value = value; + } + + public Runtime(Method value) { + this.type = Type.CODE; + this.value = value; + } + + // Getters + public long getLong() { + switch (type) { + case INTEGER: + return (long) value; + case DOUBLE: + return (long) ((double) value); + case STRING: + try { + return Long.parseLong((String) value); + } catch (NumberFormatException e) { + return 0; + } + case CODE: + return ((Method) this.value).hashCode(); // Use Method's hashCode as the ID + default: + return 0; + } + } + + private double getDouble() { + switch (this.type) { + case INTEGER: + return (long) this.value; + case DOUBLE: + return (double) this.value; + case STRING: + try { + return Double.parseDouble((String) this.value); + } catch (NumberFormatException e) { + return 0.0; // Return zero if the string cannot be converted + } + case CODE: + return ((Method) this.value).hashCode(); // Use Method's hashCode as the ID + default: + return 0.0; + } + } + + public boolean getBoolean() { + switch (type) { + case INTEGER: + return (long) value != 0; + case DOUBLE: + return (long) ((double) value) != 0; + case STRING: + String s = (String) value; + return !s.equals("") && !s.equals("0"); + default: + return true; + } + } + + public String getString() { + if (type == Type.STRING) { + return (String) value; + } else { + throw new IllegalStateException("Variable does not contain a string"); + } + } + + // Setters + public Runtime set(Runtime value) { + this.type = value.type; + this.value = value.value; + return this; + } + + public Runtime set(long value) { + this.type = Type.INTEGER; + this.value = value; + return this; + } + + public Runtime set(String value) { + this.type = Type.STRING; + this.value = value; + return this; + } + + @Override + public String toString() { + switch (type) { + case INTEGER: + return Long.toString((long) value); + case DOUBLE: + return Double.toString((double) value); + case STRING: + return (String) value; + case REFERENCE: + return "Reference to: " + value.toString(); + case CODE: + return "Code Reference: " + value.toString(); + default: + return "Undefined"; + } + } public static Runtime make_sub(String className) throws Exception { // finish setting up a CODE object Class clazz = Runtime.anonSubs.remove(className); Method mm = clazz.getMethod("apply", Runtime.class, ContextType.class); - Runtime rr = new Runtime(-1); - rr.subroutineReference = mm; - return rr; + return new Runtime(mm); } public Runtime apply(Runtime a, ContextType callContext) throws Exception { - Runtime result = (Runtime) subroutineReference.invoke(null, a, callContext); - return result; + if (type == Type.CODE) { + return (Runtime) ((Method) value).invoke(null, a, callContext); + } else { + throw new IllegalStateException("Variable does not contain a code reference"); + } } public static void eval_string(Runtime code, String evalTag) throws Exception { - - // TODO - cleanup possible duplicate code in these places: - // - Main.java - execute main program - // - EmitterVisitor.java - create anon sub - // retrieve the eval context that was saved at program compile-time EmitterContext evalCtx = Runtime.evalContext.get(evalTag); @@ -78,90 +197,36 @@ public static void eval_string(Runtime code, String evalTag) throws Exception { return; } - public Runtime set(Runtime a) { - this.i = a.i; - this.s = a.s; - this.subroutineReference = a.subroutineReference; - return this; - } - - public String toString() { - if (this.s != null) { - return this.s; - } - return String.valueOf(this.i); - } - - public boolean toBoolean() { - return this.i != 0; - } - - public static boolean is_false() { - return false; - } - - public static boolean is_true() { - return true; - } - - public static Runtime print(String a) { - System.out.println("value=" + a); - return new Runtime(1); - } - - public static Runtime print(int a) { - System.out.println("value=" + a); - return new Runtime(1); - } - - public static Runtime print(Object a) { - Runtime.print((Runtime) a); - return new Runtime(1); - } - - public static Runtime print(Runtime a) { - a.print(); - return new Runtime(1); - } - public Runtime print() { - System.out.println("value=" + this.i + " " + this.s); + System.out.println(this.toString()); return new Runtime(1); } - public static Runtime make(int a) { - return new Runtime(a); - } - - public Runtime add(int a, int b) { - return new Runtime(a + b); - } - - public Runtime add(int b) { - return new Runtime(this.i + b); - } - - public Runtime add(Runtime b) { - return new Runtime(this.i + b.i); - } - - public Runtime subtract(Runtime b) { - return new Runtime(this.i - b.i); - } - - public Runtime multiply(int b) { - return new Runtime(this.i * b); - } - - public Runtime multiply(Runtime b) { - return new Runtime(this.i * b.i); - } - - public Runtime divide(Runtime b) { - return new Runtime(this.i / b.i); - } - public Runtime stringConcat(Runtime b) { return new Runtime(this.toString() + b.toString()); } + + public Runtime add(Runtime arg) { + if (this.type == Type.STRING || arg.type == Type.STRING) { + // Try to parse both values as long + try { + long val1 = Long.parseLong((String) this.value); + long val2 = Long.parseLong((String) arg.value); + return new Runtime(val1 + val2); + } catch (NumberFormatException e) { + // If parsing fails, fall back to double addition + double val1 = this.getDouble(); + double val2 = arg.getDouble(); + return new Runtime(val1 + val2); + } + } else if (this.type == Type.DOUBLE || arg.type == Type.DOUBLE) { + double val1 = this.getDouble(); + double val2 = arg.getDouble(); + return new Runtime(val1 + val2); + } else { + long val1 = this.getLong(); + long val2 = arg.getLong(); + return new Runtime(val1 + val2); + } + } } diff --git a/misc/Java-Asm-Interpreter/MethodExecutorAsm/snippets/runtime_add.java b/misc/Java-Asm-Interpreter/MethodExecutorAsm/snippets/runtime_add.java new file mode 100644 index 00000000..7b9cf062 --- /dev/null +++ b/misc/Java-Asm-Interpreter/MethodExecutorAsm/snippets/runtime_add.java @@ -0,0 +1,118 @@ +import java.lang.reflect.Method; + +public class Runtime { + public enum Type { + INTEGER, DOUBLE, STRING, CODE, // Add other types as needed + } + + private Type type; + private Object value; + + // Constructor + public Runtime(Type type, Object value) { + this.type = type; + this.value = value; + } + + // Getters + public long getLong() { + switch (type) { + case INTEGER: + return (long) value; + case DOUBLE: + return (long) ((double) value); + case STRING: + try { + return Long.parseLong((String) value); + } catch (NumberFormatException e) { + return 0L; // Return zero if the string cannot be converted + } + case CODE: + return ((Method) value).hashCode(); // Use Method's hashCode as the ID + default: + throw new IllegalStateException("Variable does not contain a type that can be converted to a long"); + } + } + + // Add method + public Runtime add(Runtime arg) { + if (this.type == Type.STRING || arg.type == Type.STRING) { + return addString(this, arg); + } else if (this.type == Type.DOUBLE || arg.type == Type.DOUBLE) { + return addDouble(this, arg); + } else if (this.type == Type.INTEGER || arg.type == Type.INTEGER) { + return addInteger(this, arg); + } else if (this.type == Type.CODE || arg.type == Type.CODE) { + return addCode(this, arg); + } else { + throw new IllegalStateException("Unsupported variable type for addition"); + } + } + + // Helper methods for addition + private Runtime addString(Runtime var1, Runtime var2) { + double val1 = toDouble(var1); + double val2 = toDouble(var2); + return new Runtime(Type.DOUBLE, val1 + val2); + } + + private Runtime addDouble(Runtime var1, Runtime var2) { + double val1 = toDouble(var1); + double val2 = toDouble(var2); + return new Runtime(Type.DOUBLE, val1 + val2); + } + + private Runtime addInteger(Runtime var1, Runtime var2) { + long val1 = toLong(var1); + long val2 = toLong(var2); + return new Runtime(Type.INTEGER, val1 + val2); + } + + private Runtime addCode(Runtime var1, Runtime var2) { + long val1 = toLong(var1); + long val2 = toLong(var2); + return new Runtime(Type.INTEGER, val1 + val2); + } + + // Helper method to convert Runtime to double + private double toDouble(Runtime var) { + switch (var.type) { + case INTEGER: + return (long) var.value; + case DOUBLE: + return (double) var.value; + case STRING: + try { + return Double.parseDouble((String) var.value); + } catch (NumberFormatException e) { + return 0.0; // Return zero if the string cannot be converted + } + case CODE: + return ((Method) var.value).hashCode(); // Use Method's hashCode as the ID + default: + throw new IllegalStateException("Variable does not contain a type that can be converted to a double"); + } + } + + // Helper method to convert Runtime to long + private long toLong(Runtime var) { + switch (var.type) { + case INTEGER: + return (long) var.value; + case DOUBLE: + return (long) ((double) var.value); + case STRING: + try { + return Long.parseLong((String) var.value); + } catch (NumberFormatException e) { + return 0L; // Return zero if the string cannot be converted + } + case CODE: + return ((Method) var.value).hashCode(); // Use Method's hashCode as the ID + default: + throw new IllegalStateException("Variable does not contain a type that can be converted to a long"); + } + } + + // Other methods... +}