From: Thomas Walker Lynch Date: Sat, 14 Dec 2024 16:46:24 +0000 (+0000) Subject: adding constructor invocation to AllMethodsPublicProxy X-Git-Url: https://git.reasoningtechnology.com/style/static/git-favicon.png?a=commitdiff_plain;h=425de7ef97bfa35631211e211228b039a6caa775;p=Mosaic adding constructor invocation to AllMethodsPublicProxy --- diff --git a/developer/bash/Mosaic b/developer/bash/Mosaic new file mode 100755 index 0000000..ba5b241 --- /dev/null +++ b/developer/bash/Mosaic @@ -0,0 +1,2 @@ +#!/bin/bash +java com.ReasoningTechnology."Mosaic".Mosaic diff --git "a/developer/javac\360\237\226\211/Mosaic_AllMethodsPublicProxy.java" "b/developer/javac\360\237\226\211/Mosaic_AllMethodsPublicProxy.java" index ea1a0ed..4f38092 100644 --- "a/developer/javac\360\237\226\211/Mosaic_AllMethodsPublicProxy.java" +++ "b/developer/javac\360\237\226\211/Mosaic_AllMethodsPublicProxy.java" @@ -26,13 +26,13 @@ class FunctionSignature { this.parameter_types = method.getParameterTypes(); } - private static Class[] resolve_parameter_types(Object[] args){ - Class[] parameter_types = new Class[args.length]; - for( int i = 0; i < args.length; i++ ){ - if( args[i] instanceof isPrimitive ){ - parameter_types[i] = ((isPrimitive) args[i]).get_type(); - }else if( args[i] != null ){ - parameter_types[i] = args[i].getClass(); + private static Class[] resolve_parameter_types(Object[] arg_list){ + Class[] parameter_types = new Class[arg_list.length]; + for( int i = 0; i < arg_list.length; i++ ){ + if( arg_list[i] instanceof Mosaic_IsPrimitive ){ + parameter_types[i] = ((Mosaic_IsPrimitive) arg_list[i]).get_type(); + }else if( arg_list[i] != null ){ + parameter_types[i] = arg_list[i].getClass(); }else{ parameter_types[i] = null; } @@ -76,7 +76,6 @@ class FunctionSignature { return sb.toString(); } - } class FunctionSignature_To_Handle_Map { @@ -87,6 +86,53 @@ class FunctionSignature_To_Handle_Map { add_class(class_metadata); } + private void add_class(Class class_metadata){ + try{ + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodHandles.Lookup private_lookup = MethodHandles.privateLookupIn(class_metadata ,lookup); + + // Map constructors + for(Constructor constructor : class_metadata.getDeclaredConstructors()){ + Class[] parameter_types = constructor.getParameterTypes(); + MethodType method_type = MethodType.methodType(class_metadata, parameter_types); + MethodHandle constructor_handle; + + if((constructor.getModifiers() & Modifier.PRIVATE) != 0){ + constructor_handle = private_lookup.findConstructor(class_metadata, method_type); + } else{ + constructor_handle = lookup.findConstructor(class_metadata, method_type); + } + + FunctionSignature signature = new FunctionSignature("", parameter_types); + map.put(signature, constructor_handle); + } + + // Map methods + for(Method method : class_metadata.getDeclaredMethods()){ + Class[] parameter_types = method.getParameterTypes(); + MethodType method_type = MethodType.methodType( + method.getReturnType() ,parameter_types + ); + MethodHandle method_handle; + + if((method.getModifiers() & Modifier.PRIVATE) != 0){ + method_handle = private_lookup.findSpecial(class_metadata ,method.getName() ,method_type ,class_metadata); + } else{ + method_handle = lookup.findVirtual(class_metadata ,method.getName() ,method_type); + } + + FunctionSignature signature = new FunctionSignature(method); + map.put(signature ,method_handle); + } + } catch(Throwable t){ + System.out.println("FunctionSignature_To_Handle_Map::add_class exception:"); + t.printStackTrace(); + } + } + + + /* + private void add_class(Class class_metadata){ try{ MethodHandles.Lookup lookup = MethodHandles.lookup(); @@ -99,7 +145,7 @@ class FunctionSignature_To_Handle_Map { ); MethodHandle method_handle; - if( (method.getModifiers() & java.lang.reflect.Modifier.PRIVATE) != 0 ){ + if((method.getModifiers() & java.lang.reflect.Modifier.PRIVATE) != 0 ){ method_handle = private_lookup.findSpecial(class_metadata ,method.getName() ,method_type ,class_metadata); }else{ method_handle = lookup.findVirtual(class_metadata ,method.getName() ,method_type); @@ -113,6 +159,8 @@ class FunctionSignature_To_Handle_Map { t.printStackTrace(); } } + */ + public MethodHandle get_handle(FunctionSignature signature){ return map.get(signature); @@ -122,7 +170,7 @@ class FunctionSignature_To_Handle_Map { public String toString() { StringBuilder sb = new StringBuilder(); sb.append("FunctionSignature to MethodHandle Map:\n"); - for (Map.Entry entry : map.entrySet()) { + for(Map.Entry entry : map.entrySet()) { sb.append(" ").append(entry.getKey()).append(" -> ").append(entry.getValue()).append("\n"); } return sb.toString(); @@ -139,26 +187,65 @@ public class Mosaic_AllMethodsPublicProxy { this.map = new FunctionSignature_To_Handle_Map(target_type); } + public Object construct(String constructor_name, Object... arg_list) { + try { + // Resolve the constructor signature + FunctionSignature signature = new FunctionSignature(constructor_name, arg_list); + MethodHandle handle = map.get_handle(signature); + + if (handle == null) { + throw new NoSuchMethodException("No constructor found for signature: " + signature.get_method_name()); + } + + // Unwrap Mosaic_IsPrimitive instances + Object[] unwrapped_args = new Object[arg_list.length]; + for (int i = 0; i < arg_list.length; i++) { + if (arg_list[i] instanceof Mosaic_IsPrimitive) { + unwrapped_args[i] = ((Mosaic_IsPrimitive) arg_list[i]).get_value(); + } else { + unwrapped_args[i] = arg_list[i]; + } + } + + // Invoke the constructor handle + return handle.invokeWithArguments(unwrapped_args); + + } catch (Throwable t) { + System.out.println("Mosaic_AllMethodsPublicProxy::construct exception:"); + t.printStackTrace(); + return null; + } + } + + public Object invoke(Object target_instance, String method_name, Object... arg_list) { try { - if (target_instance == null || !target_type.isInstance(target_instance)) { + if(target_instance == null || !target_type.isInstance(target_instance)) { System.out.println("Warning: Instance is not of type " + target_type.getName()); } - // Resolve the function signature + // Resolve the function signature. + // The IsPrimtiive tags are needed here so as to form a correct signature for + // looking up the handle. + // FunctionSignature signature = new FunctionSignature(method_name, arg_list); MethodHandle handle = map.get_handle(signature); System.out.println( "invoked with signature: " + signature.toString() ); - if (handle == null) { + if(handle == null) { throw new NoSuchMethodException("No method found for signature: " + signature.get_method_name()); } - // Unwrap isPrimitive instances in arguments + // This removes the IsPrimitive tags (unwrap the containted + // values). The `get_value` will be boxed in the Java Wrappers, + // i.e. `int` values wills till be Integer, because it is + // Object type. Later `invokeWithArguments` below will unbox the + // primitive values as it is aware of the types required for the call. + // Object[] unwrapped_args = new Object[arg_list.length]; - for (int i = 0; i < arg_list.length; i++) { - if (arg_list[i] instanceof isPrimitive) { - unwrapped_args[i] = ((isPrimitive) arg_list[i]).get_value(); + for(int i = 0; i < arg_list.length; i++) { + if(arg_list[i] instanceof Mosaic_IsPrimitive) { + unwrapped_args[i] = ((Mosaic_IsPrimitive) arg_list[i]).get_value(); } else { unwrapped_args[i] = arg_list[i]; } @@ -166,7 +253,7 @@ public class Mosaic_AllMethodsPublicProxy { return handle.bindTo(target_instance).invokeWithArguments(unwrapped_args); - } catch (Throwable t) { + }catch(Throwable t) { System.out.println("Mosaic_AllMethodsPublicProxy::invoke exception:"); t.printStackTrace(); return null; diff --git "a/developer/javac\360\237\226\211/Mosaic_FunctionSignature.xjava" "b/developer/javac\360\237\226\211/Mosaic_FunctionSignature.xjava" new file mode 100644 index 0000000..083ca75 --- /dev/null +++ "b/developer/javac\360\237\226\211/Mosaic_FunctionSignature.xjava" @@ -0,0 +1,77 @@ +package com.ReasoningTechnology.Mosaic; + +import java.lang.reflect.Method; +import java.util.Arrays; +import com.ReasoningTechnology.Mosaic.Mosaic_IsPrimitive; + +public class Mosaic_FunctionSignature { + private final String method_name; + private final Class[] parameter_types; + + public FunctionSignature(String method_name ,Class[] parameter_types){ + this.method_name = method_name; + this.parameter_types = parameter_types; + } + + public FunctionSignature(String method_name ,Object[] args){ + this.method_name = method_name; + this.parameter_types = resolve_parameter_types(args); + } + + public FunctionSignature(Method method){ + this.method_name = method.getName(); + this.parameter_types = method.getParameterTypes(); + } + + private static Class[] resolve_parameter_types(Object[] arg_list){ + Class[] parameter_types = new Class[arg_list.length]; + for( int i = 0; i < arg_list.length; i++ ){ + if( arg_list[i] instanceof Mosaic_IsPrimitive ){ + parameter_types[i] = ((Mosaic_IsPrimitive) arg_list[i]).get_type(); + }else if( arg_list[i] != null ){ + parameter_types[i] = arg_list[i].getClass(); + }else{ + parameter_types[i] = null; + } + } + return parameter_types; + } + + public String get_method_name(){ + return method_name; + } + + public Class[] get_parameter_types(){ + return parameter_types; + } + + @Override + public boolean equals(Object o){ + if( this == o ) return true; + if( o == null || getClass() != o.getClass() ) return false; + FunctionSignature signature = (FunctionSignature) o; + return method_name.equals(signature.method_name) && + java.util.Arrays.equals(parameter_types ,signature.parameter_types); + } + + @Override + public int hashCode(){ + int result = method_name.hashCode(); + result = 31 * result + java.util.Arrays.hashCode(parameter_types); + return result; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(method_name).append("("); + for (int i = 0; i < parameter_types.length; i++) { + sb.append(parameter_types[i].getSimpleName()); + if (i < parameter_types.length - 1) sb.append(", "); + } + sb.append(")"); + return sb.toString(); + } + +} + diff --git "a/developer/javac\360\237\226\211/Mosaic_IsPrimitive.java" "b/developer/javac\360\237\226\211/Mosaic_IsPrimitive.java" index a50c6b5..e0d6652 100644 --- "a/developer/javac\360\237\226\211/Mosaic_IsPrimitive.java" +++ "b/developer/javac\360\237\226\211/Mosaic_IsPrimitive.java" @@ -16,6 +16,7 @@ public class Mosaic_IsPrimitive { } public Class get_type(){ + if( value == null ) return null; if( value instanceof Integer ) return int.class; if( value instanceof Boolean ) return boolean.class; if( value instanceof Double ) return double.class; diff --git a/release/Mosaic.jar b/release/Mosaic.jar index e77c1c4..7b94800 100644 Binary files a/release/Mosaic.jar and b/release/Mosaic.jar differ diff --git "a/tester/javac\360\237\226\211/Test_FunctionSignature.java" "b/tester/javac\360\237\226\211/Test_FunctionSignature.java" new file mode 100644 index 0000000..1485b93 --- /dev/null +++ "b/tester/javac\360\237\226\211/Test_FunctionSignature.java" @@ -0,0 +1,95 @@ +import com.ReasoningTechnology.Mosaic.*; + +public class Test_FunctionSignature{ + + public class TestSuite{ + + public Boolean test_basic_signature(Mosaic_IO io){ + Boolean[] conditions = new Boolean[3]; + int i = 0; + + // Test resolve_parameter_types with primitives and non-primitives + Mosaic_FunctionSignature sig1 = new Mosaic_FunctionSignature("test", new Object[]{42, "hello"}); + conditions[i++] = sig1.get_parameter_types()[0].equals(int.class); + conditions[i++] = sig1.get_parameter_types()[1].equals(String.class); + + // Test method name retrieval + conditions[i++] = sig1.get_method_name().equals("test"); + + return Mosaic_Util.all(conditions); + } + + public Boolean test_signature_equality(Mosaic_IO io){ + Boolean[] conditions = new Boolean[2]; + int i = 0; + + Mosaic_FunctionSignature sig1 = new Mosaic_FunctionSignature("test", new Object[]{42, "hello"}); + Mosaic_FunctionSignature sig2 = new Mosaic_FunctionSignature("test", new Object[]{42, "hello"}); + + // Test equality and hash code + conditions[i++] = sig1.equals(sig2); + conditions[i++] = sig1.hashCode() == sig2.hashCode(); + + return Mosaic_Util.all(conditions); + } + + public Boolean test_null_arguments(Mosaic_IO io){ + Boolean[] conditions = new Boolean[2]; + int i = 0; + + Mosaic_FunctionSignature sig = new Mosaic_FunctionSignature("test", new Object[]{null}); + + // Test parameter types for null argument + conditions[i++] = sig.get_parameter_types()[0] == null; + + // Test method name retrieval + conditions[i++] = sig.get_method_name().equals("test"); + + return Mosaic_Util.all(conditions); + } + + public Boolean test_to_string(Mosaic_IO io){ + Boolean[] conditions = new Boolean[1]; + int i = 0; + + Mosaic_FunctionSignature sig = new Mosaic_FunctionSignature("example", new Object[]{42, "text"}); + String expected = "example(int, String)"; + + // Test string representation + conditions[i++] = sig.toString().equals(expected); + + return Mosaic_Util.all(conditions); + } + + public Boolean test_method_constructor(Mosaic_IO io){ + Boolean[] conditions = new Boolean[2]; + int i = 0; + + class TestClass{ + public void sampleMethod(int a, String b){} + } + + try{ + Method method = TestClass.class.getDeclaredMethod("sampleMethod", int.class, String.class); + Mosaic_FunctionSignature sig = new Mosaic_FunctionSignature(method); + + // Test method name + conditions[i++] = sig.get_method_name().equals("sampleMethod"); + + // Test parameter types + conditions[i++] = sig.get_parameter_types()[0].equals(int.class) && + sig.get_parameter_types()[1].equals(String.class); + } catch (NoSuchMethodException e){ + return false; // This shouldn't happen in a controlled test + } + + return Mosaic_Util.all(conditions); + } + } + + public static void main(String[] args){ + TestSuite suite = new Test_FunctionSignature().new TestSuite(); + int result = Mosaic_Testbench.run(suite); + System.exit(result); + } +} diff --git "a/tester/javac\360\237\226\211/Test_IsPrimitive.java" "b/tester/javac\360\237\226\211/Test_IsPrimitive.java" new file mode 100644 index 0000000..33b9a0e --- /dev/null +++ "b/tester/javac\360\237\226\211/Test_IsPrimitive.java" @@ -0,0 +1,118 @@ +/* -------------------------------------------------------------------------------- + Integration tests directly simulate the use cases for Mosaic_Testbench. + Each test method validates a specific feature of Mosaic_Testbench ,including pass, + fail ,error handling ,and I/O interactions. +*/ +import java.util.Scanner; + +import com.ReasoningTechnology.Mosaic.Mosaic_IO; +import com.ReasoningTechnology.Mosaic.Mosaic_IsPrimitive; +import com.ReasoningTechnology.Mosaic.Mosaic_Testbench; + +import com.ReasoningTechnology.Mosaic.Mosaic_IO; +import com.ReasoningTechnology.Mosaic.Mosaic_Testbench; +import com.ReasoningTechnology.Mosaic.Mosaic_IsPrimitive; + +public class Test_IsPrimitive{ + + public class TestSuite{ + + + public Boolean test_int_type(Mosaic_IO io){ + Mosaic_IsPrimitive mip = Mosaic_IsPrimitive.make(42); + return mip.get_type().equals(int.class); + } + + public Boolean test_boolean_type(Mosaic_IO io){ + Mosaic_IsPrimitive mip = Mosaic_IsPrimitive.make(true); + return mip.get_type().equals(boolean.class); + } + + public Boolean test_double_type(Mosaic_IO io){ + Mosaic_IsPrimitive mip = Mosaic_IsPrimitive.make(3.14); + return mip.get_type().equals(double.class); + } + + public Boolean test_string_type(Mosaic_IO io){ + Mosaic_IsPrimitive mip = Mosaic_IsPrimitive.make("hello"); + return mip.get_type().equals(String.class); + } + + public Boolean test_object_type(Mosaic_IO io){ + Object obj = new Object(); + Mosaic_IsPrimitive mip = Mosaic_IsPrimitive.make(obj); + return mip.get_type().equals(Object.class); + } + + public Boolean test_char_type(Mosaic_IO io){ + Mosaic_IsPrimitive mip = Mosaic_IsPrimitive.make('a'); + return mip.get_type().equals(char.class); + } + + public Boolean test_null_value(Mosaic_IO io){ + try{ + Mosaic_IsPrimitive mip = Mosaic_IsPrimitive.make(null); + return mip.get_type() == null; // Should handle gracefully or throw + } catch (Exception e){ + return false; + } + } + + public Boolean test_empty_string(Mosaic_IO io){ + Mosaic_IsPrimitive mip = Mosaic_IsPrimitive.make(""); + return mip.get_type().equals(String.class); + } + + public Boolean test_blank_string(Mosaic_IO io){ + Mosaic_IsPrimitive mip = Mosaic_IsPrimitive.make(" "); + return mip.get_type().equals(String.class); + } + + // When passing arguments through Object types, there is no way + // for the callee to know if the caller sent a primitive type or a + // boxed value. This is the point of having IsPrimitive. + // IsPrimitive indicates that we really mean to send the primitive + // type, though it appears in the box. + public Boolean test_primitive_wrapper(Mosaic_IO io){ + Mosaic_IsPrimitive mip = Mosaic_IsPrimitive.make(Integer.valueOf(42)); + return mip.get_type().equals(int.class); + } + + public Boolean test_primitive_array(Mosaic_IO io){ + Mosaic_IsPrimitive mip = Mosaic_IsPrimitive.make(new int[]{1, 2, 3}); + return mip.get_type().equals(int[].class); + } + + public Boolean test_object_array(Mosaic_IO io){ + Mosaic_IsPrimitive mip = Mosaic_IsPrimitive.make(new String[]{"a", "b", "c"}); + return mip.get_type().equals(String[].class); + } + + public Boolean test_enum_type(Mosaic_IO io){ + enum TestEnum{ VALUE1, VALUE2 } + Mosaic_IsPrimitive mip = Mosaic_IsPrimitive.make(TestEnum.VALUE1); + return mip.get_type().equals(TestEnum.class); + } + + public Boolean test_collection_type(Mosaic_IO io){ + java.util.List list = java.util.Arrays.asList(1, 2, 3); + Mosaic_IsPrimitive mip = Mosaic_IsPrimitive.make(list); + return mip.get_type().getName().equals("java.util.Arrays$ArrayList"); + } + + public Boolean test_extreme_primitive_values(Mosaic_IO io){ + Mosaic_IsPrimitive mipMax = Mosaic_IsPrimitive.make(Integer.MAX_VALUE); + Mosaic_IsPrimitive mipMin = Mosaic_IsPrimitive.make(Integer.MIN_VALUE); + Mosaic_IsPrimitive mipNaN = Mosaic_IsPrimitive.make(Double.NaN); + return mipMax.get_type().equals(int.class) + && mipMin.get_type().equals(int.class) + && mipNaN.get_type().equals(double.class); + } + } + + public static void main(String[] args){ + TestSuite suite = new Test_IsPrimitive().new TestSuite(); + int result = Mosaic_Testbench.run(suite); + System.exit(result); + } +} diff --git a/tester/log/log.txt b/tester/log/log.txt index 4885307..c3fad8a 100644 --- a/tester/log/log.txt +++ b/tester/log/log.txt @@ -20,3 +20,25 @@ Output: Intentional extraneous chars to stderr for testing. +2024-12-14T05:51:43.096Z [main] INFO c.R.Mosaic.Mosaic_Logger - +2024-12-14T05:51:43.094778420Z ----------------------------------------------------------- +Test: smoke_test_logging +Message: +This is a smoke test for logging. + +2024-12-14T05:51:43.496Z [main] INFO c.R.Mosaic.Mosaic_Logger - +2024-12-14T05:51:43.494998052Z ----------------------------------------------------------- +Test: test_failure_3 +Stream: stdout +Output: +Intentional extraneous chars to stdout for testing + + +2024-12-14T05:51:43.497Z [main] INFO c.R.Mosaic.Mosaic_Logger - +2024-12-14T05:51:43.497259959Z ----------------------------------------------------------- +Test: test_failure_4 +Stream: stderr +Output: +Intentional extraneous chars to stderr for testing. + + diff --git "a/tester/tool\360\237\226\211/bash_wrapper_list" "b/tester/tool\360\237\226\211/bash_wrapper_list" index 8d272b6..ac5f2f5 100755 --- "a/tester/tool\360\237\226\211/bash_wrapper_list" +++ "b/tester/tool\360\237\226\211/bash_wrapper_list" @@ -1,6 +1,9 @@ #!/bin/env bash script_afp=$(realpath "${BASH_SOURCE[0]}") +# each test listed here will receive a shell wrapper, and run_tests will +# include the test in the test run, in the order it appears in the list. + # input guards env_must_be="tester/tool🖉/env" if [ "$ENV" != "$env_must_be" ]; then @@ -16,5 +19,7 @@ echo\ Test_IO\ Test_Testbench\ Test_MockClass_0\ - Test_Util_proxy - + Test_Util_proxy\ + Test_IsPrimitive\ + Test_FunctionSignature\ + "" diff --git "a/tester/tool\360\237\226\211/env" "b/tester/tool\360\237\226\211/env" index f9626b5..d35674e 100644 --- "a/tester/tool\360\237\226\211/env" +++ "b/tester/tool\360\237\226\211/env" @@ -55,7 +55,7 @@ case "$MODE" in export CLASSPATH=\ "$BASE_CLASSPATH\ -:$REPO_HOME/tester/scratchpad +:$REPO_HOME/tester/scratchpad\ :$REPO_HOME/release/${PROJECT}.jar\ :$CLASSPATH"