package wombat;

import java.lang.invoke.*;
import clojure.lang.*;

public class Global {
    public final static Var COMPILER_BINDINGS = RT.var("wombat.compiler", "global-bindings");
    public final static Var LOADER = RT.var("wombat.compiler", "*class-loader*");
    public final static Var JAVALIST_TO_LIST = RT.var("wombat.datatypes", "javalist->list");
    final static Keyword CALLSITE = Keyword.intern("call-site");
    
    public static CallSite getCallSite(Symbol name) {
        Atom bindAtom = (Atom) COMPILER_BINDINGS.deref();
        return (CallSite) RT.get(RT.get(bindAtom.deref(), name), CALLSITE);
    }

    public static Object getGlobal(Symbol name) {
        CallSite site = getCallSite(name);
        if (site == null)
            return null;

        try {
            return site.getTarget().invokeExact();
        } catch (Throwable t) {
            throw Util.sneakyThrow(t);
        }
    }

    public static CallSite bootstrap(MethodHandles.Lookup caller, String name, MethodType methodType, String symName) {
        CallSite site = getCallSite(Symbol.intern(symName));
        if (site == null)
            throw new IllegalStateException("Symbol " + symName + " is not defined!");

        return site;
    }

    public static Object invokeLambda(ILambda lambda, Object[] args) {
        try {
            MethodHandle handle = lambda.getHandle(args.length);
            Object ret;
            int arity = handle.type().parameterCount() - 1; // first parameter is ILambda
            if (handle.isVarargsCollector() && args.length >= arity - 1) {
                Object[] newArgs = new Object[arity];
                Object[] varArgs = new Object[args.length - arity + 1];
                System.arraycopy(args, 0, newArgs, 0, arity - 1);
                System.arraycopy(args, arity - 1, varArgs, 0, args.length - arity + 1);
                newArgs[arity - 1] = varArgs;

                ret = handle.asFixedArity().asSpreader(Object[].class, arity).invoke(lambda, newArgs);
            } else
                ret = handle.asSpreader(Object[].class, args.length).invoke(lambda, args);

            while (ret instanceof Continuation)
                ret = ((Continuation)ret).invoke();
            return ret;
        } catch (Throwable t) { throw Util.sneakyThrow(t); }
    }

}

@@ -37,16 +37,41 @@
 voke.*;%0A
+import java.util.Arrays;%0A
 import c
@@ -1255,32 +1255,37 @@
 rn site;%0A    %7D%0A%0A
+    %0A
     public stati
@@ -1328,18 +1328,19 @@
 , Object
-%5B%5D
+...
  args) %7B
@@ -1352,813 +1352,83 @@
     
-try %7B%0A            MethodHandle handle = lambda.getHandle(args.length);%0A            Object ret;%0A            int arity = handle.type().parameterCount() - 1; // first parameter is ILambda%0A            if (handle.isVarargsCollector() && args.length %3E= arity - 1) %7B%0A                Object%5B%5D newArgs = new Object%5Barity%5D;%0A                Object%5B%5D varArgs = new Object%5Bargs.length - arity + 1%5D;%0A                System.arraycopy(args, 0, newArgs, 0, arity - 1);%0A                System.arraycopy(args, arity - 1, varArgs, 0, args.length - arity + 1);%0A                newArgs%5Barity - 1%5D = varArgs;%0A%0A                ret = handle.asFixedArity().asSpreader(Object%5B%5D.class, arity).invoke(lambda, newArgs);%0A            %7D else%0A                ret = handle.asSpreader(Object%5B%5D.class, args.length).invoke(lambda, 
+Object ret = lambda.applyTo(JAVALIST_TO_LIST.invoke(Arrays.asList(
 args)
+))
 ;%0A
-%0A    
     
@@ -1479,20 +1479,16 @@
         
-   
- 
 ret = ((
@@ -1519,28 +1519,24 @@
 ();%0A        
-    
 return ret;%0A
@@ -1539,69 +1539,8 @@
 et;%0A
-        %7D catch (Throwable t) %7B throw Util.sneakyThrow(t); %7D%0A
     

update invokeLambda method