33import com .annimon .ownlang .lib .*;
44import com .annimon .ownlang .modules .Module ;
55import java .lang .reflect .Array ;
6+ import java .lang .reflect .Constructor ;
67import java .lang .reflect .Field ;
78import java .lang .reflect .InvocationTargetException ;
89import java .lang .reflect .Method ;
910import java .util .ArrayList ;
11+ import java .util .Arrays ;
1012import java .util .List ;
1113
1214/**
@@ -102,7 +104,7 @@ public String toString() {
102104 }
103105 }
104106
105- private static class ClassValue extends MapValue {
107+ private static class ClassValue extends MapValue implements Instantiable {
106108
107109 public static Value classOrNull (Class <?> clazz ) {
108110 if (clazz == null ) return NULL ;
@@ -151,25 +153,22 @@ private void init(Class<?> clazz) {
151153 set ("cast" , new FunctionValue (this ::cast ));
152154 }
153155
154- private Value asSubclass (Value ... args ) {
156+ private Value asSubclass (Value [] args ) {
155157 Arguments .check (1 , args .length );
156158 return new ClassValue (clazz .asSubclass ( ((ClassValue )args [0 ]).clazz ));
157159 }
158160
159- private Value isAssignableFrom (Value ... args ) {
161+ private Value isAssignableFrom (Value [] args ) {
160162 Arguments .check (1 , args .length );
161163 return NumberValue .fromBoolean (clazz .isAssignableFrom ( ((ClassValue )args [0 ]).clazz ));
162164 }
163165
164- private Value newInstance (Value ... args ) {
165- try {
166- return new ObjectValue (clazz .newInstance ());
167- } catch (InstantiationException | IllegalAccessException ex ) {
168- return NULL ;
169- }
166+ @ Override
167+ public Value newInstance (Value [] args ) {
168+ return findConstructorAndInstantiate (args , clazz .getConstructors ());
170169 }
171170
172- private Value cast (Value ... args ) {
171+ private Value cast (Value [] args ) {
173172 Arguments .check (1 , args .length );
174173 return objectToValue (clazz , clazz .cast (((ObjectValue )args [0 ]).object ));
175174 }
@@ -209,7 +208,7 @@ public ObjectValue(Object object) {
209208
210209 @ Override
211210 public boolean containsKey (Value key ) {
212- return getValue ( object . getClass (), object , key . asString () ) != null ;
211+ return get ( key ) != null ;
213212 }
214213
215214 @ Override
@@ -229,32 +228,32 @@ public String toString() {
229228 }
230229//</editor-fold>
231230
232- private Value isNull (Value ... args ) {
231+ private Value isNull (Value [] args ) {
233232 Arguments .checkAtLeast (1 , args .length );
234233 for (Value arg : args ) {
235234 if (arg .raw () == null ) return NumberValue .ONE ;
236235 }
237236 return NumberValue .ZERO ;
238237 }
239238
240- private Value newClass (Value ... args ) {
239+ private Value newClass (Value [] args ) {
241240 Arguments .check (1 , args .length );
242241
243242 final String className = args [0 ].asString ();
244243 try {
245244 return new ClassValue (Class .forName (className ));
246245 } catch (ClassNotFoundException ce ) {
247- return NULL ;
246+ throw new RuntimeException ( "Class " + className + " not found." , ce ) ;
248247 }
249248 }
250249
251- private Value toObject (Value ... args ) {
250+ private Value toObject (Value [] args ) {
252251 Arguments .check (1 , args .length );
253252 if (args [0 ] == NULL ) return NULL ;
254253 return new ObjectValue (valueToObject (args [0 ]));
255254 }
256255
257- private Value toValue (Value ... args ) {
256+ private Value toValue (Value [] args ) {
258257 Arguments .check (1 , args .length );
259258 if (args [0 ] instanceof ObjectValue ) {
260259 return objectToValue ( ((ObjectValue ) args [0 ]).object );
@@ -293,6 +292,22 @@ private static Value getValue(Class<?> clazz, Object object, String key) {
293292
294293 return NULL ;
295294 }
295+
296+ private static Value findConstructorAndInstantiate (Value [] args , Constructor <?>[] ctors ) {
297+ for (Constructor <?> ctor : ctors ) {
298+ if (ctor .getParameterCount () != args .length ) continue ;
299+ if (!isMatch (args , ctor .getParameterTypes ())) continue ;
300+ try {
301+ final Object result = ctor .newInstance (valuesToObjects (args ));
302+ return new ObjectValue (result );
303+ } catch (InstantiationException | IllegalAccessException
304+ | IllegalArgumentException | InvocationTargetException ex ) {
305+ // skip
306+ }
307+ }
308+ throw new RuntimeException ("Constructor for " + args .length + " arguments"
309+ + " not found or non accessible" );
310+ }
296311
297312 private static Function methodsToFunction (Object object , List <Method > methods ) {
298313 return (args ) -> {
@@ -309,10 +324,12 @@ private static Function methodsToFunction(Object object, List<Method> methods) {
309324 // skip
310325 }
311326 }
312- return null ;
327+ final String className = (object == null ? "null" : object .getClass ().getName ());
328+ throw new RuntimeException ("Method for " + args .length + " arguments"
329+ + " not found or non accessible in " + className );
313330 };
314331 }
315-
332+
316333 private static boolean isMatch (Value [] args , Class <?>[] types ) {
317334 for (int i = 0 ; i < args .length ; i ++) {
318335 final Value arg = args [i ];
@@ -324,7 +341,15 @@ private static boolean isMatch(Value[] args, Class<?>[] types) {
324341 boolean assignable = unboxed != null ;
325342 final Object object = valueToObject (arg );
326343 assignable = assignable && (object != null );
327- assignable = assignable && (unboxed .isAssignableFrom (object .getClass ()));
344+ if (assignable && unboxed .isArray () && object .getClass ().isArray ()) {
345+ final Class <?> uComponentType = unboxed .getComponentType ();
346+ final Class <?> oComponentType = object .getClass ().getComponentType ();
347+ assignable = assignable && (uComponentType != null );
348+ assignable = assignable && (oComponentType != null );
349+ assignable = assignable && (uComponentType .isAssignableFrom (oComponentType ));
350+ } else {
351+ assignable = assignable && (unboxed .isAssignableFrom (object .getClass ()));
352+ }
328353 if (assignable ) continue ;
329354
330355 return false ;
@@ -447,7 +472,7 @@ private static Value arrayToValue(Class<?> clazz, Object o) {
447472 }
448473 return result ;
449474 }
450-
475+
451476 private static Object [] valuesToObjects (Value [] args ) {
452477 Object [] result = new Object [args .length ];
453478 for (int i = 0 ; i < args .length ; i ++) {
@@ -477,11 +502,72 @@ private static Object valueToObject(Value value) {
477502
478503 private static Object arrayToObject (ArrayValue value ) {
479504 final int size = value .size ();
480- final Object [] result = new Object [size ];
505+ final Object [] array = new Object [size ];
506+ if (size == 0 ) {
507+ return array ;
508+ }
509+
510+ Class <?> elementsType = null ;
481511 for (int i = 0 ; i < size ; i ++) {
482- result [i ] = valueToObject (value .get (i ));
512+ array [i ] = valueToObject (value .get (i ));
513+ if (i == 0 ) {
514+ elementsType = array [0 ].getClass ();
515+ } else {
516+ elementsType = mostCommonType (elementsType , array [i ].getClass ());
517+ }
518+ }
519+
520+ if (elementsType .equals (Object [].class )) {
521+ return array ;
522+ }
523+ return typedArray (array , size , elementsType );
524+ }
525+
526+ private static <T , U > T [] typedArray (U [] elements , int newLength , Class <?> elementsType ) {
527+ @ SuppressWarnings ("unchecked" )
528+ T [] copy = (T []) Array .newInstance (elementsType , newLength );
529+ System .arraycopy (elements , 0 , copy , 0 , Math .min (elements .length , newLength ));
530+ return copy ;
531+ }
532+
533+ private static Class <?> mostCommonType (Class <?> c1 , Class <?> c2 ) {
534+ if (c1 .equals (c2 )) {
535+ return c1 ;
536+ } else if (c1 .isAssignableFrom (c2 )) {
537+ return c1 ;
538+ } else if (c2 .isAssignableFrom (c1 )) {
539+ return c2 ;
540+ }
541+ final Class <?> s1 = c1 .getSuperclass ();
542+ final Class <?> s2 = c2 .getSuperclass ();
543+ if (s1 == null && s2 == null ) {
544+ final List <Class <?>> upperTypes = Arrays .asList (
545+ Object .class , void .class , boolean .class , char .class ,
546+ byte .class , short .class , int .class , long .class ,
547+ float .class , double .class );
548+ for (Class <?> type : upperTypes ) {
549+ if (c1 .equals (type ) && c2 .equals (type )) {
550+ return s1 ;
551+ }
552+ }
553+ return Object .class ;
554+ } else if (s1 == null || s2 == null ) {
555+ if (c1 .equals (c2 )) {
556+ return c1 ;
557+ }
558+ if (c1 .isInterface () && c1 .isAssignableFrom (c2 )) {
559+ return c1 ;
560+ }
561+ if (c2 .isInterface () && c2 .isAssignableFrom (c1 )) {
562+ return c2 ;
563+ }
564+ }
565+
566+ if (s1 != null ) {
567+ return mostCommonType (s1 , c2 );
568+ } else {
569+ return mostCommonType (c1 , s2 );
483570 }
484- return result ;
485571 }
486572//</editor-fold>
487573}
0 commit comments