PageRenderTime 65ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/src/sys/dotnet/fan/sys/Method.cs

https://bitbucket.org/bedlaczech/fan-1.0
C# | 595 lines | 442 code | 69 blank | 84 comment | 130 complexity | 7c376faaa7519bf0984dd7faa2cbf033 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  1. //
  2. // Copyright (c) 2006, Brian Frank and Andy Frank
  3. // Licensed under the Academic Free License version 3.0
  4. //
  5. // History:
  6. // 27 Sep 06 Andy Frank Creation
  7. //
  8. using System;
  9. using System.Reflection;
  10. using System.Text;
  11. using Fanx.Fcode;
  12. using Fanx.Util;
  13. namespace Fan.Sys
  14. {
  15. /// <summary>
  16. /// Method is an invocable operation on a Type.
  17. /// </summary>
  18. public class Method : Slot
  19. {
  20. //////////////////////////////////////////////////////////////////////////
  21. // C# Constructor
  22. //////////////////////////////////////////////////////////////////////////
  23. /// <summary>
  24. /// Constructor used by Type.reflect.
  25. /// </summary>
  26. public Method(Type parent, string name, int flags, Facets facets, int lineNum, Type returns, Type inheritedReturns, List pars)
  27. : this(parent, name, flags, facets, lineNum, returns, inheritedReturns, pars, null)
  28. {
  29. }
  30. /// <summary>
  31. /// Constructor used by GenericType and we are given the generic
  32. /// method that is being parameterized.
  33. /// </summary>
  34. public Method(Type parent, string name, int flags, Facets facets, int lineNum, Type returns, Type inheritedReturns, List pars, Method generic)
  35. : base(parent, name, flags, facets, lineNum)
  36. {
  37. List fparams = pars.ro();
  38. if ((flags & (FConst.Static|FConst.Ctor)) == 0)
  39. {
  40. object[] temp = new object[pars.sz()+1];
  41. temp[0] = new Param("this", parent, 0);
  42. pars.copyInto(temp, 1, pars.sz());
  43. fparams = new List(Sys.ParamType, temp);
  44. }
  45. this.m_func = new MethodFunc(this, returns, fparams);
  46. this.m_params = pars;
  47. this.m_inheritedReturns = inheritedReturns;
  48. this.m_mask = (generic != null) ? 0 : toMask(parent, returns, pars);
  49. this.m_generic = generic;
  50. }
  51. /// <summary>
  52. /// Compute if the method signature contains generic parameter types.
  53. /// </summary>
  54. private static int toMask(Type parent, Type returns, List pars)
  55. {
  56. // we only use generics in Sys
  57. if (parent.pod() != Sys.m_sysPod) return 0;
  58. int p = returns.isGenericParameter() ? 1 : 0;
  59. for (int i=0; i<pars.sz(); ++i)
  60. p |= ((Param)pars.get(i)).m_type.isGenericParameter() ? 1 : 0;
  61. int mask = 0;
  62. if (p != 0) mask |= GENERIC;
  63. return mask;
  64. }
  65. //////////////////////////////////////////////////////////////////////////
  66. // Methods
  67. //////////////////////////////////////////////////////////////////////////
  68. public override Type @typeof() { return Sys.MethodType; }
  69. public Type returns() { return m_func.returns(); }
  70. public Type inheritedReturns() { return m_inheritedReturns; }
  71. public List @params() { return m_params.ro(); }
  72. public Func func() { return m_func; }
  73. public override string signature()
  74. {
  75. StringBuilder s = new StringBuilder();
  76. s.Append(m_func.returns()).Append(' ').Append(m_name).Append('(');
  77. for (int i=0; i<m_params.sz(); ++i)
  78. {
  79. if (i > 0) s.Append(", ");
  80. Param p = (Param)m_params.get(i);
  81. s.Append(p.m_type).Append(' ').Append(p.m_name);
  82. }
  83. s.Append(')');
  84. return s.ToString();
  85. }
  86. public override object trap(string name, List args)
  87. {
  88. // private undocumented access
  89. if (name == "inheritedReturnType")
  90. return m_inheritedReturns;
  91. else
  92. return base.trap(name, args);
  93. }
  94. //////////////////////////////////////////////////////////////////////////
  95. // Generics
  96. //////////////////////////////////////////////////////////////////////////
  97. /// <summary>
  98. /// Return if this method contains generic parameters in it's signature.
  99. /// </summary>
  100. public bool isGenericMethod()
  101. {
  102. return (m_mask & GENERIC) != 0;
  103. }
  104. /// <summary>
  105. /// Return if this method is the parameterization of a generic method,
  106. /// with all the generic parameters filled in with real types.
  107. /// </summary>
  108. public bool isGenericInstance()
  109. {
  110. return m_generic != null;
  111. }
  112. /// <summary>
  113. /// If isGenericInstance is true, then return the generic method which
  114. /// this method instantiates. The generic method may be used to access
  115. /// the actual signatures used in the Java code (via getRawType). If
  116. /// this method is not a generic instance, return null.
  117. /// </summary>
  118. public Method getGenericMethod()
  119. {
  120. return m_generic;
  121. }
  122. //////////////////////////////////////////////////////////////////////////
  123. // Call Conveniences
  124. //////////////////////////////////////////////////////////////////////////
  125. public object callList(List args) { return m_func.callList(args); }
  126. public object callOn(object target, List args) { return m_func.callOn(target, args); }
  127. public object call() { return m_func.call(); }
  128. public object call(object a) { return m_func.call(a); }
  129. public object call(object a, object b) { return m_func.call(a,b); }
  130. public object call(object a, object b, object c) { return m_func.call(a,b,c); }
  131. public object call(object a, object b, object c, object d) { return m_func.call(a,b,c,d); }
  132. public object call(object a, object b, object c, object d, object e) { return m_func.call(a,b,c,d,e); }
  133. 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); }
  134. 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); }
  135. 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); }
  136. //////////////////////////////////////////////////////////////////////////
  137. // MethodFunc
  138. //////////////////////////////////////////////////////////////////////////
  139. internal class MethodFunc : Func
  140. {
  141. internal MethodFunc(Method method, Type returns, List pars)
  142. {
  143. this.m = method;
  144. this.m_returns = returns;
  145. this.m_params = pars;
  146. }
  147. private Method m;
  148. private Type m_returns;
  149. private List m_params;
  150. public override Type returns() { return m_returns; }
  151. public override long arity() { return m_params.size(); }
  152. public override List @params() { return m_params; }
  153. public override Method method() { return m; }
  154. public override bool isImmutable() { return true; }
  155. public override object callList(List args)
  156. {
  157. int argsSize = args == null ? 0 : args.sz();
  158. bool isStatic = _isStatic();
  159. int p = checkArgs(argsSize, isStatic, false);
  160. object[] a = new object[p];
  161. if (isStatic)
  162. {
  163. if (args != null && a.Length > 0) args.toArray(a, 0, a.Length);
  164. return m.invoke(null, a);
  165. }
  166. else
  167. {
  168. object i = args.get(0);
  169. if (a.Length > 0) args.toArray(a, 1, a.Length);
  170. return m.invoke(i, a);
  171. }
  172. }
  173. public override object callOn(object target, List args)
  174. {
  175. int argsSize = args == null ? 0 : args.sz();
  176. bool dotnetStatic = _isStatic();
  177. bool fanStatic = ((m.m_flags & (FConst.Static|FConst.Ctor)) != 0);
  178. if (dotnetStatic && !fanStatic)
  179. {
  180. // if Java static doesn't match Fantom static, then this is
  181. // a FanXXX method which we need to call as Java static
  182. int p = checkArgs(argsSize, false, true);
  183. object[] a = new object[p+1];
  184. a[0] = target;
  185. if (args != null && a.Length > 0) args.copyInto(a, 1, a.Length-1);
  186. return m.invoke(null, a);
  187. }
  188. else
  189. {
  190. // we don't include target as part of arguments
  191. int p = checkArgs(argsSize, dotnetStatic, true);
  192. object[] a = new object[p];
  193. if (args != null && a.Length > 0) args.toArray(a, 0, a.Length);
  194. return m.invoke(target, a);
  195. }
  196. }
  197. public override object call()
  198. {
  199. bool isStatic = _isStatic();
  200. checkArgs(0, isStatic, false);
  201. return m.invoke(null, noArgs);
  202. }
  203. public override object call(object a)
  204. {
  205. bool isStatic = _isStatic();
  206. int p = checkArgs(1, isStatic, false);
  207. object[] args;
  208. if (isStatic)
  209. {
  210. args = new object[p];
  211. if (p > 0) args[0] = a;
  212. return m.invoke(null, args);
  213. }
  214. else
  215. {
  216. args = new object[p];
  217. return m.invoke(a, args);
  218. }
  219. }
  220. public override object call(object a, object b)
  221. {
  222. bool isStatic = _isStatic();
  223. int p = checkArgs(2, isStatic, false);
  224. object[] args;
  225. if (isStatic)
  226. {
  227. args = new object[p];
  228. if (p > 0) args[0] = a;
  229. if (p > 1) args[1] = b;
  230. return m.invoke(null, args);
  231. }
  232. else
  233. {
  234. args = new object[p];
  235. if (p > 0) args[0] = b;
  236. return m.invoke(a, args);
  237. }
  238. }
  239. public override object call(object a, object b, object c)
  240. {
  241. bool isStatic = _isStatic();
  242. int p = checkArgs(3, isStatic, false);
  243. object[] args;
  244. if (isStatic)
  245. {
  246. args = new object[p];
  247. if (p > 0) args[0] = a;
  248. if (p > 1) args[1] = b;
  249. if (p > 2) args[2] = c;
  250. return m.invoke(null, args);
  251. }
  252. else
  253. {
  254. args = new object[p];
  255. if (p > 0) args[0] = b;
  256. if (p > 1) args[1] = c;
  257. return m.invoke(a, args);
  258. }
  259. }
  260. public override object call(object a, object b, object c, object d)
  261. {
  262. bool isStatic = _isStatic();
  263. int p = checkArgs(4, isStatic, false);
  264. object[] args;
  265. if (isStatic)
  266. {
  267. args = new object[p];
  268. if (p > 0) args[0] = a;
  269. if (p > 1) args[1] = b;
  270. if (p > 2) args[2] = c;
  271. if (p > 3) args[3] = d;
  272. return m.invoke(null, args);
  273. }
  274. else
  275. {
  276. args = new object[p];
  277. if (p > 0) args[0] = b;
  278. if (p > 1) args[1] = c;
  279. if (p > 2) args[2] = d;
  280. return m.invoke(a, args);
  281. }
  282. }
  283. public override object call(object a, object b, object c, object d, object e)
  284. {
  285. bool isStatic = _isStatic();
  286. int p = checkArgs(5, isStatic, false);
  287. object[] args;
  288. if (isStatic)
  289. {
  290. args = new object[p];
  291. if (p > 0) args[0] = a;
  292. if (p > 1) args[1] = b;
  293. if (p > 2) args[2] = c;
  294. if (p > 3) args[3] = d;
  295. if (p > 4) args[4] = e;
  296. return m.invoke(null, args);
  297. }
  298. else
  299. {
  300. args = new object[p];
  301. if (p > 0) args[0] = b;
  302. if (p > 1) args[1] = c;
  303. if (p > 2) args[2] = d;
  304. if (p > 3) args[3] = e;
  305. return m.invoke(a, args);
  306. }
  307. }
  308. public override object call(object a, object b, object c, object d, object e, object f)
  309. {
  310. bool isStatic = _isStatic();
  311. int p = checkArgs(6, isStatic, false);
  312. object[] args;
  313. if (isStatic)
  314. {
  315. args = new object[p];
  316. if (p > 0) args[0] = a;
  317. if (p > 1) args[1] = b;
  318. if (p > 2) args[2] = c;
  319. if (p > 3) args[3] = d;
  320. if (p > 4) args[4] = e;
  321. if (p > 5) args[5] = f;
  322. return m.invoke(null, args);
  323. }
  324. else
  325. {
  326. args = new object[p];
  327. if (p > 0) args[0] = b;
  328. if (p > 1) args[1] = c;
  329. if (p > 2) args[2] = d;
  330. if (p > 3) args[3] = e;
  331. if (p > 4) args[4] = f;
  332. return m.invoke(a, args);
  333. }
  334. }
  335. public override object call(object a, object b, object c, object d, object e, object f, object g)
  336. {
  337. bool isStatic = _isStatic();
  338. int p = checkArgs(7, isStatic, false);
  339. object[] args;
  340. if (isStatic)
  341. {
  342. args = new object[p];
  343. if (p > 0) args[0] = a;
  344. if (p > 1) args[1] = b;
  345. if (p > 2) args[2] = c;
  346. if (p > 3) args[3] = d;
  347. if (p > 4) args[4] = e;
  348. if (p > 5) args[5] = f;
  349. if (p > 6) args[6] = g;
  350. return m.invoke(null, args);
  351. }
  352. else
  353. {
  354. args = new object[p];
  355. if (p > 0) args[0] = b;
  356. if (p > 1) args[1] = c;
  357. if (p > 2) args[2] = d;
  358. if (p > 3) args[3] = e;
  359. if (p > 4) args[4] = f;
  360. if (p > 5) args[5] = g;
  361. return m.invoke(a, args);
  362. }
  363. }
  364. public override object call(object a, object b, object c, object d, object e, object f, object g, object h)
  365. {
  366. bool isStatic = _isStatic();
  367. int p = checkArgs(8, isStatic, false);
  368. object[] args;
  369. if (isStatic)
  370. {
  371. args = new object[p];
  372. if (p > 0) args[0] = a;
  373. if (p > 1) args[1] = b;
  374. if (p > 2) args[2] = c;
  375. if (p > 3) args[3] = d;
  376. if (p > 4) args[4] = e;
  377. if (p > 5) args[5] = f;
  378. if (p > 6) args[6] = g;
  379. if (p > 7) args[7] = h;
  380. return m.invoke(null, args);
  381. }
  382. else
  383. {
  384. args = new object[p];
  385. if (p > 0) args[0] = b;
  386. if (p > 1) args[1] = c;
  387. if (p > 2) args[2] = d;
  388. if (p > 3) args[3] = e;
  389. if (p > 4) args[4] = f;
  390. if (p > 5) args[5] = g;
  391. if (p > 6) args[6] = h;
  392. return m.invoke(a, args);
  393. }
  394. }
  395. private bool _isStatic()
  396. {
  397. try
  398. {
  399. // ensure parent has finished emitting so that reflect is populated
  400. m.m_parent.finish();
  401. // return if .NET method(s) is static
  402. return m.m_reflect[0].IsStatic;
  403. }
  404. catch (Exception)
  405. {
  406. throw Err.make("Method not mapped to System.Reflection correctly " + m.qname()).val;
  407. }
  408. }
  409. private int checkArgs(int args, bool isStatic, bool isCallOn)
  410. {
  411. // compuate min/max parameters - reflect contains all the method versions
  412. // with full pars at index zero, and full defaults at reflect.Length-1
  413. int max = m_params.sz();
  414. if (!isStatic) max--;
  415. int min = max-m.m_reflect.Length+1;
  416. // do checking
  417. if (isStatic || isCallOn)
  418. {
  419. if (args < min) throw ArgErr.make("Too few arguments: " + args + " < " + min+".."+max).val;
  420. }
  421. else
  422. {
  423. if (args < min+1) throw ArgErr.make("Too few arguments: " + args + " < instance+" + min+".."+max).val;
  424. args--;
  425. }
  426. // return size of arguments to pass to java method
  427. return args <= max ? args : max;
  428. }
  429. }
  430. //////////////////////////////////////////////////////////////////////////
  431. // Reflection
  432. //////////////////////////////////////////////////////////////////////////
  433. public int minParams()
  434. {
  435. if (m_minParams < 0)
  436. {
  437. int min = 0;
  438. for (; min<m_params.sz(); ++min)
  439. if (((Param)m_params.get(min)).hasDefault()) break;
  440. m_minParams = min;
  441. }
  442. return m_minParams;
  443. }
  444. private bool isInstance() { return (m_flags & (FConst.Static|FConst.Ctor)) == 0; }
  445. internal object invoke(object instance, object[] args)
  446. {
  447. if (m_reflect == null) m_parent.finish();
  448. try
  449. {
  450. // zero index is full signature up to using max defaults
  451. int index = m_params.sz()-args.Length;
  452. if (m_parent.dotnetRepr() && isInstance()) index++;
  453. if (index < 0) index = 0;
  454. MethodInfo m = m_reflect[index];
  455. //System.Console.WriteLine(">>> " + m_reflect.Length + "/" + index);
  456. //System.Console.WriteLine(m_reflect[index]);
  457. //System.Console.WriteLine("---");
  458. //for (int i=0; i<m_reflect.Length; i++)
  459. // System.Console.WriteLine(m_reflect[i]);
  460. // TODO - not sure how this should work entirely yet, but we need
  461. // to be responsible for "boxing" Fantom wrappers and primitives
  462. // box the parameters
  463. ParameterInfo[] pars = m.GetParameters();
  464. for (int i=0; i<args.Length; i++)
  465. {
  466. System.Type pt = pars[i].ParameterType;
  467. if (pt == boolPrimitive && args[i] is Fan.Sys.Boolean)
  468. {
  469. args[i] = (args[i] as Fan.Sys.Boolean).booleanValue();
  470. }
  471. else if (pt == doublePrimitive && args[i] is Fan.Sys.Double)
  472. {
  473. args[i] = (args[i] as Fan.Sys.Double).doubleValue();
  474. }
  475. else if (pt == longPrimitive && args[i] is Fan.Sys.Long)
  476. {
  477. args[i] = (args[i] as Fan.Sys.Long).longValue();
  478. }
  479. }
  480. // invoke method
  481. object ret = m.Invoke(instance, args);
  482. // box the return value
  483. return FanUtil.box(ret);
  484. }
  485. catch (ArgumentException e)
  486. {
  487. throw ArgErr.make(e).val;
  488. }
  489. catch (TargetInvocationException e)
  490. {
  491. Err err = Err.make(e.InnerException);
  492. err.m_stack = e.InnerException.StackTrace;
  493. throw err.val;
  494. }
  495. catch (Exception e)
  496. {
  497. if (m_reflect == null)
  498. throw Err.make("Method not mapped to System.Reflection.MethodInfo correctly " + m_qname).val;
  499. /*
  500. System.Console.WriteLine("ERROR: " + signature());
  501. System.Console.WriteLine(" instance: " + instance);
  502. System.Console.WriteLine(" args: " + (args == null ? "null" : ""+args.Length));
  503. for (int i=0; args != null && i<args.Length; ++i)
  504. System.Console.WriteLine(" args[" + i + "] = " + args[i]);
  505. Err.dumpStack(e);
  506. */
  507. throw Err.make("Cannot call '" + this + "': " + e).val;
  508. }
  509. }
  510. private static System.Type boolPrimitive = System.Type.GetType("System.Boolean");
  511. private static System.Type doublePrimitive = System.Type.GetType("System.Double");
  512. private static System.Type longPrimitive = System.Type.GetType("System.Int64");
  513. //////////////////////////////////////////////////////////////////////////
  514. // Fields
  515. //////////////////////////////////////////////////////////////////////////
  516. internal static readonly int GENERIC = 0x01; // is this a generic method
  517. internal static readonly object[] noArgs = new object[0];
  518. internal Func m_func;
  519. internal List m_params; // might be different from func.params is instance method
  520. internal Type m_inheritedReturns; // for covariance
  521. internal int m_mask;
  522. internal Method m_generic;
  523. internal MethodInfo[] m_reflect;
  524. private int m_minParams = -1;
  525. }
  526. }