/src/sys/dotnet/fan/sys/Method.cs
C# | 595 lines | 442 code | 69 blank | 84 comment | 130 complexity | 7c376faaa7519bf0984dd7faa2cbf033 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
- //
- // Copyright (c) 2006, Brian Frank and Andy Frank
- // Licensed under the Academic Free License version 3.0
- //
- // History:
- // 27 Sep 06 Andy Frank Creation
- //
- using System;
- using System.Reflection;
- using System.Text;
- using Fanx.Fcode;
- using Fanx.Util;
- namespace Fan.Sys
- {
- /// <summary>
- /// Method is an invocable operation on a Type.
- /// </summary>
- public class Method : Slot
- {
- //////////////////////////////////////////////////////////////////////////
- // C# Constructor
- //////////////////////////////////////////////////////////////////////////
- /// <summary>
- /// Constructor used by Type.reflect.
- /// </summary>
- public Method(Type parent, string name, int flags, Facets facets, int lineNum, Type returns, Type inheritedReturns, List pars)
- : this(parent, name, flags, facets, lineNum, returns, inheritedReturns, pars, null)
- {
- }
- /// <summary>
- /// Constructor used by GenericType and we are given the generic
- /// method that is being parameterized.
- /// </summary>
- public Method(Type parent, string name, int flags, Facets facets, int lineNum, Type returns, Type inheritedReturns, List pars, Method generic)
- : base(parent, name, flags, facets, lineNum)
- {
- List fparams = pars.ro();
- if ((flags & (FConst.Static|FConst.Ctor)) == 0)
- {
- object[] temp = new object[pars.sz()+1];
- temp[0] = new Param("this", parent, 0);
- pars.copyInto(temp, 1, pars.sz());
- fparams = new List(Sys.ParamType, temp);
- }
- this.m_func = new MethodFunc(this, returns, fparams);
- this.m_params = pars;
- this.m_inheritedReturns = inheritedReturns;
- this.m_mask = (generic != null) ? 0 : toMask(parent, returns, pars);
- this.m_generic = generic;
- }
- /// <summary>
- /// Compute if the method signature contains generic parameter types.
- /// </summary>
- private static int toMask(Type parent, Type returns, List pars)
- {
- // we only use generics in Sys
- if (parent.pod() != Sys.m_sysPod) return 0;
- int p = returns.isGenericParameter() ? 1 : 0;
- for (int i=0; i<pars.sz(); ++i)
- p |= ((Param)pars.get(i)).m_type.isGenericParameter() ? 1 : 0;
- int mask = 0;
- if (p != 0) mask |= GENERIC;
- return mask;
- }
- //////////////////////////////////////////////////////////////////////////
- // Methods
- //////////////////////////////////////////////////////////////////////////
- public override Type @typeof() { return Sys.MethodType; }
- public Type returns() { return m_func.returns(); }
- public Type inheritedReturns() { return m_inheritedReturns; }
- public List @params() { return m_params.ro(); }
- public Func func() { return m_func; }
- public override string signature()
- {
- StringBuilder s = new StringBuilder();
- s.Append(m_func.returns()).Append(' ').Append(m_name).Append('(');
- for (int i=0; i<m_params.sz(); ++i)
- {
- if (i > 0) s.Append(", ");
- Param p = (Param)m_params.get(i);
- s.Append(p.m_type).Append(' ').Append(p.m_name);
- }
- s.Append(')');
- return s.ToString();
- }
- public override object trap(string name, List args)
- {
- // private undocumented access
- if (name == "inheritedReturnType")
- return m_inheritedReturns;
- else
- return base.trap(name, args);
- }
- //////////////////////////////////////////////////////////////////////////
- // Generics
- //////////////////////////////////////////////////////////////////////////
- /// <summary>
- /// Return if this method contains generic parameters in it's signature.
- /// </summary>
- public bool isGenericMethod()
- {
- return (m_mask & GENERIC) != 0;
- }
- /// <summary>
- /// Return if this method is the parameterization of a generic method,
- /// with all the generic parameters filled in with real types.
- /// </summary>
- public bool isGenericInstance()
- {
- return m_generic != null;
- }
- /// <summary>
- /// If isGenericInstance is true, then return the generic method which
- /// this method instantiates. The generic method may be used to access
- /// the actual signatures used in the Java code (via getRawType). If
- /// this method is not a generic instance, return null.
- /// </summary>
- public Method getGenericMethod()
- {
- return m_generic;
- }
- //////////////////////////////////////////////////////////////////////////
- // Call Conveniences
- //////////////////////////////////////////////////////////////////////////
- public object callList(List args) { return m_func.callList(args); }
- public object callOn(object target, List args) { return m_func.callOn(target, args); }
- public object call() { return m_func.call(); }
- public object call(object a) { return m_func.call(a); }
- public object call(object a, object b) { return m_func.call(a,b); }
- public object call(object a, object b, object c) { return m_func.call(a,b,c); }
- public object call(object a, object b, object c, object d) { return m_func.call(a,b,c,d); }
- public object call(object a, object b, object c, object d, object e) { return m_func.call(a,b,c,d,e); }
- public object call(object a, object b, object c, object d, object e, object f) { return m_func.call(a,b,c,d,e,f); }
- public object call(object a, object b, object c, object d, object e, object f, object g) { return m_func.call(a,b,c,d,e,f,g); }
- public object call(object a, object b, object c, object d, object e, object f, object g, object h) { return m_func.call(a,b,c,d,e,f,g,h); }
- //////////////////////////////////////////////////////////////////////////
- // MethodFunc
- //////////////////////////////////////////////////////////////////////////
- internal class MethodFunc : Func
- {
- internal MethodFunc(Method method, Type returns, List pars)
- {
- this.m = method;
- this.m_returns = returns;
- this.m_params = pars;
- }
- private Method m;
- private Type m_returns;
- private List m_params;
- public override Type returns() { return m_returns; }
- public override long arity() { return m_params.size(); }
- public override List @params() { return m_params; }
- public override Method method() { return m; }
- public override bool isImmutable() { return true; }
- public override object callList(List args)
- {
- int argsSize = args == null ? 0 : args.sz();
- bool isStatic = _isStatic();
- int p = checkArgs(argsSize, isStatic, false);
- object[] a = new object[p];
- if (isStatic)
- {
- if (args != null && a.Length > 0) args.toArray(a, 0, a.Length);
- return m.invoke(null, a);
- }
- else
- {
- object i = args.get(0);
- if (a.Length > 0) args.toArray(a, 1, a.Length);
- return m.invoke(i, a);
- }
- }
- public override object callOn(object target, List args)
- {
- int argsSize = args == null ? 0 : args.sz();
- bool dotnetStatic = _isStatic();
- bool fanStatic = ((m.m_flags & (FConst.Static|FConst.Ctor)) != 0);
- if (dotnetStatic && !fanStatic)
- {
- // if Java static doesn't match Fantom static, then this is
- // a FanXXX method which we need to call as Java static
- int p = checkArgs(argsSize, false, true);
- object[] a = new object[p+1];
- a[0] = target;
- if (args != null && a.Length > 0) args.copyInto(a, 1, a.Length-1);
- return m.invoke(null, a);
- }
- else
- {
- // we don't include target as part of arguments
- int p = checkArgs(argsSize, dotnetStatic, true);
- object[] a = new object[p];
- if (args != null && a.Length > 0) args.toArray(a, 0, a.Length);
- return m.invoke(target, a);
- }
- }
- public override object call()
- {
- bool isStatic = _isStatic();
- checkArgs(0, isStatic, false);
- return m.invoke(null, noArgs);
- }
- public override object call(object a)
- {
- bool isStatic = _isStatic();
- int p = checkArgs(1, isStatic, false);
- object[] args;
- if (isStatic)
- {
- args = new object[p];
- if (p > 0) args[0] = a;
- return m.invoke(null, args);
- }
- else
- {
- args = new object[p];
- return m.invoke(a, args);
- }
- }
- public override object call(object a, object b)
- {
- bool isStatic = _isStatic();
- int p = checkArgs(2, isStatic, false);
- object[] args;
- if (isStatic)
- {
- args = new object[p];
- if (p > 0) args[0] = a;
- if (p > 1) args[1] = b;
- return m.invoke(null, args);
- }
- else
- {
- args = new object[p];
- if (p > 0) args[0] = b;
- return m.invoke(a, args);
- }
- }
- public override object call(object a, object b, object c)
- {
- bool isStatic = _isStatic();
- int p = checkArgs(3, isStatic, false);
- object[] args;
- if (isStatic)
- {
- args = new object[p];
- if (p > 0) args[0] = a;
- if (p > 1) args[1] = b;
- if (p > 2) args[2] = c;
- return m.invoke(null, args);
- }
- else
- {
- args = new object[p];
- if (p > 0) args[0] = b;
- if (p > 1) args[1] = c;
- return m.invoke(a, args);
- }
- }
- public override object call(object a, object b, object c, object d)
- {
- bool isStatic = _isStatic();
- int p = checkArgs(4, isStatic, false);
- object[] args;
- if (isStatic)
- {
- args = new object[p];
- if (p > 0) args[0] = a;
- if (p > 1) args[1] = b;
- if (p > 2) args[2] = c;
- if (p > 3) args[3] = d;
- return m.invoke(null, args);
- }
- else
- {
- args = new object[p];
- if (p > 0) args[0] = b;
- if (p > 1) args[1] = c;
- if (p > 2) args[2] = d;
- return m.invoke(a, args);
- }
- }
- public override object call(object a, object b, object c, object d, object e)
- {
- bool isStatic = _isStatic();
- int p = checkArgs(5, isStatic, false);
- object[] args;
- if (isStatic)
- {
- args = new object[p];
- if (p > 0) args[0] = a;
- if (p > 1) args[1] = b;
- if (p > 2) args[2] = c;
- if (p > 3) args[3] = d;
- if (p > 4) args[4] = e;
- return m.invoke(null, args);
- }
- else
- {
- args = new object[p];
- if (p > 0) args[0] = b;
- if (p > 1) args[1] = c;
- if (p > 2) args[2] = d;
- if (p > 3) args[3] = e;
- return m.invoke(a, args);
- }
- }
- public override object call(object a, object b, object c, object d, object e, object f)
- {
- bool isStatic = _isStatic();
- int p = checkArgs(6, isStatic, false);
- object[] args;
- if (isStatic)
- {
- args = new object[p];
- if (p > 0) args[0] = a;
- if (p > 1) args[1] = b;
- if (p > 2) args[2] = c;
- if (p > 3) args[3] = d;
- if (p > 4) args[4] = e;
- if (p > 5) args[5] = f;
- return m.invoke(null, args);
- }
- else
- {
- args = new object[p];
- if (p > 0) args[0] = b;
- if (p > 1) args[1] = c;
- if (p > 2) args[2] = d;
- if (p > 3) args[3] = e;
- if (p > 4) args[4] = f;
- return m.invoke(a, args);
- }
- }
- public override object call(object a, object b, object c, object d, object e, object f, object g)
- {
- bool isStatic = _isStatic();
- int p = checkArgs(7, isStatic, false);
- object[] args;
- if (isStatic)
- {
- args = new object[p];
- if (p > 0) args[0] = a;
- if (p > 1) args[1] = b;
- if (p > 2) args[2] = c;
- if (p > 3) args[3] = d;
- if (p > 4) args[4] = e;
- if (p > 5) args[5] = f;
- if (p > 6) args[6] = g;
- return m.invoke(null, args);
- }
- else
- {
- args = new object[p];
- if (p > 0) args[0] = b;
- if (p > 1) args[1] = c;
- if (p > 2) args[2] = d;
- if (p > 3) args[3] = e;
- if (p > 4) args[4] = f;
- if (p > 5) args[5] = g;
- return m.invoke(a, args);
- }
- }
- public override object call(object a, object b, object c, object d, object e, object f, object g, object h)
- {
- bool isStatic = _isStatic();
- int p = checkArgs(8, isStatic, false);
- object[] args;
- if (isStatic)
- {
- args = new object[p];
- if (p > 0) args[0] = a;
- if (p > 1) args[1] = b;
- if (p > 2) args[2] = c;
- if (p > 3) args[3] = d;
- if (p > 4) args[4] = e;
- if (p > 5) args[5] = f;
- if (p > 6) args[6] = g;
- if (p > 7) args[7] = h;
- return m.invoke(null, args);
- }
- else
- {
- args = new object[p];
- if (p > 0) args[0] = b;
- if (p > 1) args[1] = c;
- if (p > 2) args[2] = d;
- if (p > 3) args[3] = e;
- if (p > 4) args[4] = f;
- if (p > 5) args[5] = g;
- if (p > 6) args[6] = h;
- return m.invoke(a, args);
- }
- }
- private bool _isStatic()
- {
- try
- {
- // ensure parent has finished emitting so that reflect is populated
- m.m_parent.finish();
- // return if .NET method(s) is static
- return m.m_reflect[0].IsStatic;
- }
- catch (Exception)
- {
- throw Err.make("Method not mapped to System.Reflection correctly " + m.qname()).val;
- }
- }
- private int checkArgs(int args, bool isStatic, bool isCallOn)
- {
- // compuate min/max parameters - reflect contains all the method versions
- // with full pars at index zero, and full defaults at reflect.Length-1
- int max = m_params.sz();
- if (!isStatic) max--;
- int min = max-m.m_reflect.Length+1;
- // do checking
- if (isStatic || isCallOn)
- {
- if (args < min) throw ArgErr.make("Too few arguments: " + args + " < " + min+".."+max).val;
- }
- else
- {
- if (args < min+1) throw ArgErr.make("Too few arguments: " + args + " < instance+" + min+".."+max).val;
- args--;
- }
- // return size of arguments to pass to java method
- return args <= max ? args : max;
- }
- }
- //////////////////////////////////////////////////////////////////////////
- // Reflection
- //////////////////////////////////////////////////////////////////////////
- public int minParams()
- {
- if (m_minParams < 0)
- {
- int min = 0;
- for (; min<m_params.sz(); ++min)
- if (((Param)m_params.get(min)).hasDefault()) break;
- m_minParams = min;
- }
- return m_minParams;
- }
- private bool isInstance() { return (m_flags & (FConst.Static|FConst.Ctor)) == 0; }
- internal object invoke(object instance, object[] args)
- {
- if (m_reflect == null) m_parent.finish();
- try
- {
- // zero index is full signature up to using max defaults
- int index = m_params.sz()-args.Length;
- if (m_parent.dotnetRepr() && isInstance()) index++;
- if (index < 0) index = 0;
- MethodInfo m = m_reflect[index];
- //System.Console.WriteLine(">>> " + m_reflect.Length + "/" + index);
- //System.Console.WriteLine(m_reflect[index]);
- //System.Console.WriteLine("---");
- //for (int i=0; i<m_reflect.Length; i++)
- // System.Console.WriteLine(m_reflect[i]);
- // TODO - not sure how this should work entirely yet, but we need
- // to be responsible for "boxing" Fantom wrappers and primitives
- // box the parameters
- ParameterInfo[] pars = m.GetParameters();
- for (int i=0; i<args.Length; i++)
- {
- System.Type pt = pars[i].ParameterType;
- if (pt == boolPrimitive && args[i] is Fan.Sys.Boolean)
- {
- args[i] = (args[i] as Fan.Sys.Boolean).booleanValue();
- }
- else if (pt == doublePrimitive && args[i] is Fan.Sys.Double)
- {
- args[i] = (args[i] as Fan.Sys.Double).doubleValue();
- }
- else if (pt == longPrimitive && args[i] is Fan.Sys.Long)
- {
- args[i] = (args[i] as Fan.Sys.Long).longValue();
- }
- }
- // invoke method
- object ret = m.Invoke(instance, args);
- // box the return value
- return FanUtil.box(ret);
- }
- catch (ArgumentException e)
- {
- throw ArgErr.make(e).val;
- }
- catch (TargetInvocationException e)
- {
- Err err = Err.make(e.InnerException);
- err.m_stack = e.InnerException.StackTrace;
- throw err.val;
- }
- catch (Exception e)
- {
- if (m_reflect == null)
- throw Err.make("Method not mapped to System.Reflection.MethodInfo correctly " + m_qname).val;
- /*
- System.Console.WriteLine("ERROR: " + signature());
- System.Console.WriteLine(" instance: " + instance);
- System.Console.WriteLine(" args: " + (args == null ? "null" : ""+args.Length));
- for (int i=0; args != null && i<args.Length; ++i)
- System.Console.WriteLine(" args[" + i + "] = " + args[i]);
- Err.dumpStack(e);
- */
- throw Err.make("Cannot call '" + this + "': " + e).val;
- }
- }
- private static System.Type boolPrimitive = System.Type.GetType("System.Boolean");
- private static System.Type doublePrimitive = System.Type.GetType("System.Double");
- private static System.Type longPrimitive = System.Type.GetType("System.Int64");
- //////////////////////////////////////////////////////////////////////////
- // Fields
- //////////////////////////////////////////////////////////////////////////
- internal static readonly int GENERIC = 0x01; // is this a generic method
- internal static readonly object[] noArgs = new object[0];
- internal Func m_func;
- internal List m_params; // might be different from func.params is instance method
- internal Type m_inheritedReturns; // for covariance
- internal int m_mask;
- internal Method m_generic;
- internal MethodInfo[] m_reflect;
- private int m_minParams = -1;
- }
- }