adding constructor invocation to AllMethodsPublicProxy
authorThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Sat, 14 Dec 2024 16:46:24 +0000 (16:46 +0000)
committerThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Sat, 14 Dec 2024 16:46:24 +0000 (16:46 +0000)
developer/bash/Mosaic [new file with mode: 0755]
developer/javac🖉/Mosaic_AllMethodsPublicProxy.java
developer/javac🖉/Mosaic_FunctionSignature.xjava [new file with mode: 0644]
developer/javac🖉/Mosaic_IsPrimitive.java
release/Mosaic.jar
tester/javac🖉/Test_FunctionSignature.java [new file with mode: 0644]
tester/javac🖉/Test_IsPrimitive.java [new file with mode: 0644]
tester/log/log.txt
tester/tool🖉/bash_wrapper_list
tester/tool🖉/env

diff --git a/developer/bash/Mosaic b/developer/bash/Mosaic
new file mode 100755 (executable)
index 0000000..ba5b241
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/bash
+java com.ReasoningTechnology."Mosaic".Mosaic
index ea1a0ed..4f38092 100644 (file)
@@ -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("<init>", 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<FunctionSignature, MethodHandle> entry : map.entrySet()) {
+    for(Map.Entry<FunctionSignature, MethodHandle> 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🖉/Mosaic_FunctionSignature.xjava b/developer/javac🖉/Mosaic_FunctionSignature.xjava
new file mode 100644 (file)
index 0000000..083ca75
--- /dev/null
@@ -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();
+  }
+
+}
+
index a50c6b5..e0d6652 100644 (file)
@@ -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;
index e77c1c4..7b94800 100644 (file)
Binary files a/release/Mosaic.jar and b/release/Mosaic.jar differ
diff --git a/tester/javac🖉/Test_FunctionSignature.java b/tester/javac🖉/Test_FunctionSignature.java
new file mode 100644 (file)
index 0000000..1485b93
--- /dev/null
@@ -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🖉/Test_IsPrimitive.java b/tester/javac🖉/Test_IsPrimitive.java
new file mode 100644 (file)
index 0000000..33b9a0e
--- /dev/null
@@ -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<Integer> 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);
+  }
+}
index 4885307..c3fad8a 100644 (file)
@@ -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.
+
+
index 8d272b6..ac5f2f5 100755 (executable)
@@ -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\
+  ""
index f9626b5..d35674e 100644 (file)
@@ -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"