PageRenderTime 43ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/src/sys/java/fan/sys/Method.java

https://bitbucket.org/bedlaczech/fan-1.0
Java | 635 lines | 477 code | 66 blank | 92 comment | 84 complexity | 02961f0bc5d9b445eba8fe0471cd5617 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. // 4 Jan 06 Brian Frank Creation
  7. // 9 Jul 07 Brian Frank Split into Func
  8. //
  9. package fan.sys;
  10. import java.lang.reflect.*;
  11. import fanx.fcode.*;
  12. /**
  13. * Method is an invocable operation on a Type.
  14. */
  15. public class Method
  16. extends Slot
  17. {
  18. //////////////////////////////////////////////////////////////////////////
  19. // Java Constructor
  20. //////////////////////////////////////////////////////////////////////////
  21. /**
  22. * Constructor used by Type.reflect.
  23. */
  24. public Method(Type parent, String name, int flags, Facets facets, int lineNum, Type returns, Type inheritedReturns, List params)
  25. {
  26. this(parent, name, flags, facets, lineNum, returns, inheritedReturns, params, null);
  27. }
  28. /**
  29. * Constructor used by GenericType and we are given the generic
  30. * method that is being parameterized.
  31. */
  32. public Method(Type parent, String name, int flags, Facets facets, int lineNum, Type returns, Type inheritedReturns, List params, Method generic)
  33. {
  34. super(parent, name, flags, facets, lineNum);
  35. this.params = params;
  36. this.inheritedReturns = inheritedReturns;
  37. this.mask = (generic != null) ? 0 : toMask(parent, returns, params);
  38. this.generic = generic;
  39. this.func = new MethodFunc(returns);
  40. }
  41. /**
  42. * Compute if the method signature contains generic parameter types.
  43. */
  44. private static int toMask(Type parent, Type returns, List params)
  45. {
  46. // we only use generics in Sys
  47. if (parent.pod() != Sys.sysPod) return 0;
  48. int p = returns.isGenericParameter() ? 1 : 0;
  49. for (int i=0; i<params.sz(); ++i)
  50. p |= ((Param)params.get(i)).type.isGenericParameter() ? 1 : 0;
  51. int mask = 0;
  52. if (p != 0) mask |= GENERIC;
  53. return mask;
  54. }
  55. //////////////////////////////////////////////////////////////////////////
  56. // Methods
  57. //////////////////////////////////////////////////////////////////////////
  58. public Type typeof() { return Sys.MethodType; }
  59. public Type returns() { return func.returns(); }
  60. public Type inheritedReturns() { return inheritedReturns; }
  61. public List params() { return params.ro(); }
  62. public Func func() { return func; }
  63. public String signature()
  64. {
  65. StringBuilder s = new StringBuilder();
  66. s.append(returns()).append(' ').append(name).append('(');
  67. for (int i=0; i<params.sz(); ++i)
  68. {
  69. if (i > 0) s.append(", ");
  70. Param p = (Param)params.get(i);
  71. s.append(p.type).append(' ').append(p.name);
  72. }
  73. s.append(')');
  74. return s.toString();
  75. }
  76. public Object trap(String name, List args)
  77. {
  78. // private undocumented access
  79. if (name.equals("inheritedReturnType"))
  80. return inheritedReturns;
  81. else
  82. return super.trap(name, args);
  83. }
  84. //////////////////////////////////////////////////////////////////////////
  85. // Generics
  86. //////////////////////////////////////////////////////////////////////////
  87. /**
  88. * Return if this method contains generic parameters in it's signature.
  89. */
  90. public boolean isGenericMethod()
  91. {
  92. return (mask & GENERIC) != 0;
  93. }
  94. /**
  95. * Return if this method is the parameterization of a generic method,
  96. * with all the generic parameters filled in with real types.
  97. */
  98. public boolean isGenericInstance()
  99. {
  100. return generic != null;
  101. }
  102. /**
  103. * If isGenericInstance is true, then return the generic method which
  104. * this method instantiates. The generic method may be used to access
  105. * the actual signatures used in the Java code (via getRawType). If
  106. * this method is not a generic instance, return null.
  107. */
  108. public Method getGenericMethod()
  109. {
  110. return generic;
  111. }
  112. //////////////////////////////////////////////////////////////////////////
  113. // Call Conveniences
  114. //////////////////////////////////////////////////////////////////////////
  115. public final Object callList(List args) { return func.callList(args); }
  116. public final Object callOn(Object target, List args) { return func.callOn(target, args); }
  117. public final Object call() { return func.call(); }
  118. public final Object call(Object a) { return func.call(a); }
  119. public final Object call(Object a, Object b) { return func.call(a,b); }
  120. public final Object call(Object a, Object b, Object c) { return func.call(a,b,c); }
  121. public final Object call(Object a, Object b, Object c, Object d) { return func.call(a,b,c,d); }
  122. public final Object call(Object a, Object b, Object c, Object d, Object e) { return func.call(a,b,c,d,e); }
  123. public final Object call(Object a, Object b, Object c, Object d, Object e, Object f) { return func.call(a,b,c,d,e,f); }
  124. public final Object call(Object a, Object b, Object c, Object d, Object e, Object f, Object g) { return func.call(a,b,c,d,e,f,g); }
  125. public final Object call(Object a, Object b, Object c, Object d, Object e, Object f, Object g, Object h) { return func.call(a,b,c,d,e,f,g,h); }
  126. //////////////////////////////////////////////////////////////////////////
  127. // MethodFunc
  128. //////////////////////////////////////////////////////////////////////////
  129. class MethodFunc extends Func
  130. {
  131. MethodFunc(Type returns) { this.returns = returns; }
  132. public Type returns() { return returns; }
  133. private final Type returns;
  134. public long arity() { return params().size(); }
  135. public List params()
  136. {
  137. // lazy load functions param
  138. if (fparams == null)
  139. {
  140. List mparams = Method.this.params;
  141. List fparams = mparams;
  142. if ((flags & (FConst.Static|FConst.Ctor)) == 0)
  143. {
  144. Object[] temp = new Object[mparams.sz()+1];
  145. temp[0] = new Param("this", parent, 0);
  146. mparams.copyInto(temp, 1, mparams.sz());
  147. fparams = new List(Sys.ParamType, temp);
  148. }
  149. this.fparams = fparams.ro();
  150. }
  151. return fparams;
  152. }
  153. private List fparams;
  154. public Method method() { return Method.this; }
  155. public boolean isImmutable() { return true; }
  156. public Object callList(List args)
  157. {
  158. int argsSize = args == null ? 0 : args.sz();
  159. boolean isStatic = isStatic();
  160. int p = checkArgs(argsSize, isStatic, false);
  161. Object[] a = new Object[p];
  162. if (isStatic)
  163. {
  164. if (args != null && a.length > 0) args.toArray(a, 0, a.length);
  165. return invoke(null, a);
  166. }
  167. else
  168. {
  169. Object i = args.get(0);
  170. if (a.length > 0) args.toArray(a, 1, a.length);
  171. return invoke(i, a);
  172. }
  173. }
  174. public Object callOn(Object target, List args)
  175. {
  176. int argsSize = args == null ? 0 : args.sz();
  177. boolean javaStatic = isStatic();
  178. boolean fanStatic = ((flags & (FConst.Static|FConst.Ctor)) != 0);
  179. if (javaStatic && !fanStatic)
  180. {
  181. // if Java static doesn't match Fantom static, then this is
  182. // a FanXXX method which we need to call as Java static
  183. int p = checkArgs(argsSize, false, true);
  184. Object[] a = new Object[p+1];
  185. a[0] = target;
  186. if (args != null && a.length > 0) args.copyInto(a, 1, a.length-1);
  187. return invoke(null, a);
  188. }
  189. else
  190. {
  191. // we don't include target as part of arguments
  192. int p = checkArgs(argsSize, javaStatic, true);
  193. Object[] a = new Object[p];
  194. if (args != null && a.length > 0) args.toArray(a, 0, a.length);
  195. return invoke(target, a);
  196. }
  197. }
  198. public Object call()
  199. {
  200. boolean isStatic = isStatic();
  201. checkArgs(0, isStatic, false);
  202. return invoke(null, noArgs);
  203. }
  204. public Object call(Object a)
  205. {
  206. boolean isStatic = isStatic();
  207. int p = checkArgs(1, isStatic, false);
  208. Object[] args = new Object[p];
  209. if (isStatic)
  210. {
  211. switch (p)
  212. {
  213. case 1: args[0] = a;
  214. }
  215. return invoke(null, args);
  216. }
  217. else
  218. {
  219. return invoke(a, args);
  220. }
  221. }
  222. public Object call(Object a, Object b)
  223. {
  224. boolean isStatic = isStatic();
  225. int p = checkArgs(2, isStatic, false);
  226. Object[] args = new Object[p];
  227. if (isStatic)
  228. {
  229. switch (p)
  230. {
  231. case 2: args[1] = b;
  232. case 1: args[0] = a;
  233. }
  234. return invoke(null, args);
  235. }
  236. else
  237. {
  238. switch (p)
  239. {
  240. case 1: args[0] = b;
  241. }
  242. return invoke(a, args);
  243. }
  244. }
  245. public Object call(Object a, Object b, Object c)
  246. {
  247. boolean isStatic = isStatic();
  248. int p = checkArgs(3, isStatic, false);
  249. Object[] args = new Object[p];
  250. if (isStatic)
  251. {
  252. switch (p)
  253. {
  254. case 3: args[2] = c;
  255. case 2: args[1] = b;
  256. case 1: args[0] = a;
  257. }
  258. return invoke(null, args);
  259. }
  260. else
  261. {
  262. switch (p)
  263. {
  264. case 2: args[1] = c;
  265. case 1: args[0] = b;
  266. }
  267. return invoke(a, args);
  268. }
  269. }
  270. public Object call(Object a, Object b, Object c, Object d)
  271. {
  272. boolean isStatic = isStatic();
  273. int p = checkArgs(4, isStatic, false);
  274. Object[] args = new Object[p];
  275. if (isStatic)
  276. {
  277. switch (p)
  278. {
  279. case 4: args[3] = d;
  280. case 3: args[2] = c;
  281. case 2: args[1] = b;
  282. case 1: args[0] = a;
  283. }
  284. return invoke(null, args);
  285. }
  286. else
  287. {
  288. switch (p)
  289. {
  290. case 3: args[2] = d;
  291. case 2: args[1] = c;
  292. case 1: args[0] = b;
  293. }
  294. return invoke(a, args);
  295. }
  296. }
  297. public Object call(Object a, Object b, Object c, Object d, Object e)
  298. {
  299. boolean isStatic = isStatic();
  300. int p = checkArgs(5, isStatic, false);
  301. Object[] args = new Object[p];
  302. if (isStatic)
  303. {
  304. switch (p)
  305. {
  306. case 5: args[4] = e;
  307. case 4: args[3] = d;
  308. case 3: args[2] = c;
  309. case 2: args[1] = b;
  310. case 1: args[0] = a;
  311. }
  312. return invoke(null, args);
  313. }
  314. else
  315. {
  316. switch (p)
  317. {
  318. case 4: args[3] = e;
  319. case 3: args[2] = d;
  320. case 2: args[1] = c;
  321. case 1: args[0] = b;
  322. }
  323. return invoke(a, args);
  324. }
  325. }
  326. public Object call(Object a, Object b, Object c, Object d, Object e, Object f)
  327. {
  328. boolean isStatic = isStatic();
  329. int p = checkArgs(6, isStatic, false);
  330. Object[] args = new Object[p];
  331. if (isStatic)
  332. {
  333. switch (p)
  334. {
  335. case 6: args[5] = f;
  336. case 5: args[4] = e;
  337. case 4: args[3] = d;
  338. case 3: args[2] = c;
  339. case 2: args[1] = b;
  340. case 1: args[0] = a;
  341. }
  342. return invoke(null, args);
  343. }
  344. else
  345. {
  346. switch (p)
  347. {
  348. case 5: args[4] = f;
  349. case 4: args[3] = e;
  350. case 3: args[2] = d;
  351. case 2: args[1] = c;
  352. case 1: args[0] = b;
  353. }
  354. return invoke(a, args);
  355. }
  356. }
  357. public Object call(Object a, Object b, Object c, Object d, Object e, Object f, Object g)
  358. {
  359. boolean isStatic = isStatic();
  360. int p = checkArgs(7, isStatic, false);
  361. Object[] args = new Object[p];
  362. if (isStatic)
  363. {
  364. switch (p)
  365. {
  366. case 7: args[6] = g;
  367. case 6: args[5] = f;
  368. case 5: args[4] = e;
  369. case 4: args[3] = d;
  370. case 3: args[2] = c;
  371. case 2: args[1] = b;
  372. case 1: args[0] = a;
  373. }
  374. return invoke(null, args);
  375. }
  376. else
  377. {
  378. switch (p)
  379. {
  380. case 6: args[5] = g;
  381. case 5: args[4] = f;
  382. case 4: args[3] = e;
  383. case 3: args[2] = d;
  384. case 2: args[1] = c;
  385. case 1: args[0] = b;
  386. }
  387. return invoke(a, args);
  388. }
  389. }
  390. public Object call(Object a, Object b, Object c, Object d, Object e, Object f, Object g, Object h)
  391. {
  392. boolean isStatic = isStatic();
  393. int p = checkArgs(8, isStatic, false);
  394. Object[] args = new Object[p];
  395. if (isStatic)
  396. {
  397. switch (p)
  398. {
  399. case 8: args[7] = h;
  400. case 7: args[6] = g;
  401. case 6: args[5] = f;
  402. case 5: args[4] = e;
  403. case 4: args[3] = d;
  404. case 3: args[2] = c;
  405. case 2: args[1] = b;
  406. case 1: args[0] = a;
  407. }
  408. return invoke(null, args);
  409. }
  410. else
  411. {
  412. switch (p)
  413. {
  414. case 7: args[6] = h;
  415. case 6: args[5] = g;
  416. case 5: args[4] = f;
  417. case 4: args[3] = e;
  418. case 3: args[2] = d;
  419. case 2: args[1] = c;
  420. case 1: args[0] = b;
  421. }
  422. return invoke(a, args);
  423. }
  424. }
  425. private boolean isStatic()
  426. {
  427. try
  428. {
  429. // ensure parent has finished emitting so that reflect is populated
  430. parent.finish();
  431. // return if Java method(s) is static
  432. return Modifier.isStatic(reflect[0].getModifiers());
  433. }
  434. catch (Exception e)
  435. {
  436. throw Err.make("Method not mapped to java.lang.reflect correctly " + qname());
  437. }
  438. }
  439. private int checkArgs(int args, boolean isStatic, boolean isCallOn)
  440. {
  441. // don't check args for JavaTypes - we route these calls
  442. // to the JavaType to deal with method overloading
  443. // NOTE: we figure out how to package the arguments into a target
  444. // and argument array based on whether the first method overload
  445. // is static or not; this means that if a method is overloaded
  446. // with both an instance and static version that reflection may
  447. // not correctly work when using the callX methods
  448. if (parent.isJava()) return isStatic || isCallOn ? args : args - 1;
  449. // compuate min/max parameters - reflect contains all the method versions
  450. // with full params at index zero, and full defaults at reflect.length-1
  451. int max = this.params().sz();
  452. if (!isStatic) max--;
  453. int min = max-reflect.length+1;
  454. // do checking
  455. if (isStatic || isCallOn)
  456. {
  457. if (args < min) throw ArgErr.make("Too few arguments: " + args + " < " + min+".."+max);
  458. }
  459. else
  460. {
  461. if (args < min+1) throw ArgErr.make("Too few arguments: " + args + " < instance+" + min+".."+max);
  462. args--;
  463. }
  464. // return size of arguments to pass to java method
  465. return args <= max ? args : max;
  466. }
  467. }
  468. //////////////////////////////////////////////////////////////////////////
  469. // Reflection
  470. //////////////////////////////////////////////////////////////////////////
  471. public int minParams()
  472. {
  473. if (minParams < 0)
  474. {
  475. int min = 0;
  476. for (; min<params.sz(); ++min)
  477. if (((Param)params.get(min)).hasDefault()) break;
  478. minParams = min;
  479. }
  480. return minParams;
  481. }
  482. private boolean isInstance() { return (flags & (FConst.Static|FConst.Ctor)) == 0; }
  483. public Object invoke(Object instance, Object[] args)
  484. {
  485. if (reflect == null) parent.finish();
  486. java.lang.reflect.Method jm = null;
  487. try
  488. {
  489. // if parent is FFI Java class, then route to JavaType for handling
  490. if (parent.isJava()) return JavaType.invoke(this, instance, args);
  491. // zero index is full signature up to using max defaults
  492. int index = params.sz()-args.length;
  493. if (parent.javaRepr() && isInstance()) index++;
  494. if (index < 0) index = 0;
  495. // route to Java reflection
  496. jm = reflect[index];
  497. if (jm == null)
  498. {
  499. fixReflect();
  500. jm = reflect[index];
  501. }
  502. return jm.invoke(instance, args);
  503. }
  504. catch (IllegalArgumentException e)
  505. {
  506. throw ArgErr.make(e);
  507. }
  508. catch (InvocationTargetException e)
  509. {
  510. if (e.getCause() instanceof Err)
  511. throw (Err)e.getCause();
  512. else
  513. throw Err.make(e.getCause());
  514. }
  515. catch (Exception e)
  516. {
  517. if (instance == null && jm != null && !java.lang.reflect.Modifier.isStatic(jm.getModifiers()))
  518. throw Err.make("Cannot call method '" + this + "' with null instance");
  519. if (reflect == null)
  520. throw Err.make("Method not mapped to java.lang.reflect correctly " + qname());
  521. /*
  522. System.out.println("ERROR: " + signature());
  523. System.out.println(" instance: " + instance);
  524. System.out.println(" args: " + (args == null ? "null" : ""+args.length));
  525. for (int i=0; args != null && i<args.length; ++i)
  526. System.out.println(" args[" + i + "] = " + args[i]);
  527. for (int i=0; i<reflect.length; ++i)
  528. System.out.println(" reflect[" + i + "] = " + reflect[i]);
  529. e.printStackTrace();
  530. */
  531. throw Err.make("Cannot call '" + this + "': " + e);
  532. }
  533. }
  534. private void fixReflect()
  535. {
  536. // this code is used to fix up our reflect table which maps
  537. // parameter arity to java.lang.reflect.Methods; in sys code we
  538. // don't necessarily override every version of a method with default
  539. // parameters in subclasses; so if a reflection table is incomplete
  540. // then we fill in missing entries from the base type's method
  541. try
  542. {
  543. parent.base().finish();
  544. Method inherit = parent.base().method(name);
  545. for (int i=0; i<reflect.length; ++i)
  546. {
  547. if (reflect[i] == null)
  548. reflect[i] = inherit.reflect[i];
  549. }
  550. }
  551. catch (Exception e)
  552. {
  553. System.out.println("ERROR Method.fixReflect " + qname);
  554. e.printStackTrace();
  555. }
  556. }
  557. //////////////////////////////////////////////////////////////////////////
  558. // Fields
  559. //////////////////////////////////////////////////////////////////////////
  560. static final int GENERIC = 0x01; // is this a generic method
  561. static final Object[] noArgs = new Object[0];
  562. Func func;
  563. List params; // might be different from func.params is instance method
  564. Type inheritedReturns; // for covariance
  565. int mask;
  566. Method generic;
  567. java.lang.reflect.Method[] reflect;
  568. private int minParams = -1;
  569. }