PageRenderTime 57ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/sys/dotnet/fan/sys/ClassType.cs

https://bitbucket.org/bedlaczech/fan-1.0
C# | 670 lines | 411 code | 80 blank | 179 comment | 100 complexity | 449ec6f54ff36391cf12d1eb9e1abd00 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. // 14 Sep 06 Andy Frank Creation
  7. //
  8. using System;
  9. using System.Collections;
  10. using System.IO;
  11. using System.Reflection;
  12. using System.Runtime.CompilerServices;
  13. using Fanx.Emit;
  14. using Fanx.Fcode;
  15. using Fanx.Serial;
  16. using Fanx.Util;
  17. namespace Fan.Sys
  18. {
  19. /// <summary>
  20. /// ClassType models a static type definition for an Obj class:
  21. ///
  22. /// 1) Hollow: in this state we know basic identity of the type, and
  23. /// it's inheritance hierarchy. A type is setup to be hollow during
  24. /// Pod.load().
  25. /// 2) Reflected: in this state we read all the slot definitions from the
  26. /// fcode to populate the slot tables used to for reflection. At this
  27. /// point clients can discover the signatures of the Type.
  28. /// 3) Emitted: the final state of loading a Type is to emit to a .NET
  29. /// class called "Fan.{pod}.{type}". Once emitted we can instantiate
  30. /// the type or call it's methods.
  31. /// 4) Finished: once we have reflected the slots into memory and emitted
  32. /// the .NET class, the last stage is to bind the all the System.Reflection
  33. /// representations to the Slots for dynamic dispatch. We delay this
  34. /// until needed by Method or Field for a reflection invocation
  35. /// </summary>
  36. public class ClassType : Type
  37. {
  38. //////////////////////////////////////////////////////////////////////////
  39. // Constructor
  40. //////////////////////////////////////////////////////////////////////////
  41. internal ClassType(Pod pod, FType ftype)
  42. {
  43. this.m_pod = pod;
  44. this.m_ftype = ftype;
  45. this.m_name = pod.fpod.typeRef(ftype.m_self).typeName;
  46. this.m_qname = pod.m_name + "::" + m_name;
  47. this.m_nullable = new NullableType(this);
  48. this.m_flags = ftype.m_flags;
  49. if (Debug) Console.WriteLine("-- init: " + m_qname);
  50. }
  51. // parameterized type constructor
  52. public ClassType(Pod pod, string name, int flags, Facets facets)
  53. {
  54. this.m_pod = pod;
  55. this.m_name = name;
  56. this.m_qname = pod.m_name + "::" + name;
  57. this.m_nullable = new NullableType(this);
  58. this.m_flags = flags;
  59. this.m_facets = facets;
  60. }
  61. //////////////////////////////////////////////////////////////////////////
  62. // Naming
  63. //////////////////////////////////////////////////////////////////////////
  64. public override Pod pod() { return m_pod; }
  65. public override string name() { return m_name; }
  66. public override string qname() { return m_qname; }
  67. public override string signature() { return m_qname; }
  68. public override sealed Type toNullable() { return m_nullable; }
  69. //////////////////////////////////////////////////////////////////////////
  70. // Flags
  71. //////////////////////////////////////////////////////////////////////////
  72. internal override int flags() { return m_flags; }
  73. public override object trap(string name, List args)
  74. {
  75. // private undocumented access
  76. if (name == "lineNumber") { reflect(); return Long.valueOf(m_lineNum); }
  77. if (name == "sourceFile") { reflect(); return m_sourceFile; }
  78. return base.trap(name, args);
  79. }
  80. //////////////////////////////////////////////////////////////////////////
  81. // Slots
  82. //////////////////////////////////////////////////////////////////////////
  83. public override sealed List fields() { return ((ClassType)reflect()).m_fields.ro(); }
  84. public override sealed List methods() { return ((ClassType)reflect()).m_methods.ro(); }
  85. public override sealed List slots() { return ((ClassType)reflect()).m_slots.ro(); }
  86. public override sealed Slot slot(string name, bool check)
  87. {
  88. Slot slot = (Slot)((ClassType)reflect()).m_slotsByName[name];
  89. if (slot != null) return slot;
  90. if (check) throw UnknownSlotErr.make(this.m_qname + "." + name).val;
  91. return null;
  92. }
  93. public override sealed object make(List args)
  94. {
  95. return base.make(args);
  96. }
  97. //////////////////////////////////////////////////////////////////////////
  98. // Inheritance
  99. //////////////////////////////////////////////////////////////////////////
  100. public override Type @base() { return m_base; }
  101. public override List mixins() { return m_mixins; }
  102. public override List inheritance()
  103. {
  104. if (m_inheritance == null)
  105. {
  106. Hashtable map = new Hashtable();
  107. List acc = new List(Sys.TypeType);
  108. // handle Void as a special case
  109. if (this == Sys.VoidType)
  110. {
  111. acc.add(this);
  112. return m_inheritance = acc.trim();
  113. }
  114. // add myself
  115. map[m_qname] = this;
  116. acc.add(this);
  117. // add my direct inheritance inheritance
  118. addInheritance(@base(), acc, map);
  119. List m = mixins();
  120. for (int i=0; i<m.sz(); i++)
  121. addInheritance((Type)m.get(i), acc, map);
  122. m_inheritance = acc.trim().ro();
  123. }
  124. return m_inheritance;
  125. }
  126. private void addInheritance(Type t, List acc, Hashtable map)
  127. {
  128. if (t == null) return;
  129. List ti = t.inheritance();
  130. for (int i=0; i<ti.sz(); i++)
  131. {
  132. Type x = (Type)ti.get(i);
  133. if (map[x.qname()] == null)
  134. {
  135. map[x.qname()] = x;
  136. acc.add(x);
  137. }
  138. }
  139. }
  140. public override bool @is(Type type)
  141. {
  142. // we don't take nullable into account for fits
  143. if (type is NullableType)
  144. type = ((NullableType)type).m_root;
  145. if (type == this || (type == Sys.ObjType && this != Sys.VoidType))
  146. return true;
  147. List inherit = inheritance();
  148. for (int i=0; i<inherit.sz(); ++i)
  149. if (inherit.get(i) == type) return true;
  150. return false;
  151. }
  152. //TODO
  153. /*
  154. /// <summary>
  155. /// Given a list of objects, compute the most specific type which they all
  156. /// share,or at worst return sys::Obj. This method does not take into
  157. /// account interfaces, only extends class inheritance.
  158. /// </summary>
  159. public static Type common(object[] objs, int n)
  160. {
  161. if (objs.Length == 0) return Sys.ObjType;
  162. Type best = type(objs[0]);
  163. for (int i=1; i<n; ++i)
  164. {
  165. object obj = objs[i];
  166. if (obj == null) continue;
  167. Type t = type(obj);
  168. while (!t.@is(best))
  169. {
  170. best = best.m_base;
  171. if (best == null) return Sys.ObjType;
  172. }
  173. }
  174. return best;
  175. }
  176. */
  177. //////////////////////////////////////////////////////////////////////////
  178. // Facets
  179. //////////////////////////////////////////////////////////////////////////
  180. public override List facets()
  181. {
  182. return ((ClassType)reflect()).m_facets.list();
  183. }
  184. public override Facet facet(Type t, bool c)
  185. {
  186. return ((ClassType)reflect()).m_facets.get(t, c);
  187. }
  188. //////////////////////////////////////////////////////////////////////////
  189. // Documentation
  190. //////////////////////////////////////////////////////////////////////////
  191. public override string doc()
  192. {
  193. if (!m_docLoaded)
  194. {
  195. try
  196. {
  197. Stream input = m_pod.fpod.m_store.read("doc/" + m_name + ".apidoc");
  198. if (input != null)
  199. {
  200. try { FDoc.read(input, this); } finally { input.Close(); }
  201. }
  202. }
  203. catch (Exception e)
  204. {
  205. Err.dumpStack(e);
  206. }
  207. m_docLoaded = true;
  208. }
  209. return m_doc;
  210. }
  211. //////////////////////////////////////////////////////////////////////////
  212. // Conversion
  213. //////////////////////////////////////////////////////////////////////////
  214. //TODO
  215. /*
  216. public void encode(ObjEncoder @out)
  217. {
  218. @out.w(m_qname).w("#");
  219. }
  220. */
  221. //////////////////////////////////////////////////////////////////////////
  222. // Reflection
  223. //////////////////////////////////////////////////////////////////////////
  224. [MethodImpl(MethodImplOptions.Synchronized)]
  225. public override Type reflect()
  226. {
  227. // short circuit if already reflected
  228. if (m_slotsByName != null) return this;
  229. if (Debug) Console.WriteLine("-- reflect: " + m_qname + " " + m_slotsByName);
  230. // do it
  231. doReflect();
  232. // return this
  233. return this;
  234. }
  235. private void doReflect()
  236. {
  237. // if the ftype is non-null, that means it was passed in non-hollow
  238. // ftype (in-memory compile), otherwise we need to read it from the pod
  239. if (m_ftype.m_hollow)
  240. {
  241. try
  242. {
  243. m_ftype.read();
  244. }
  245. catch (IOException e)
  246. {
  247. Err.dumpStack(e);
  248. throw IOErr.make("Cannot read " + m_qname + " from pod", e).val;
  249. }
  250. }
  251. // these are working accumulators used to build the
  252. // data structures of my defined and inherited slots
  253. List slots = new List(Sys.SlotType, 64);
  254. Hashtable nameToSlot = new Hashtable(); // String -> Slot
  255. Hashtable nameToIndex = new Hashtable(); // String -> Long
  256. // merge in base class and mixin classes
  257. for (int i=0; i<m_mixins.sz(); i++) merge((Type)m_mixins.get(i), slots, nameToSlot, nameToIndex);
  258. merge(m_base, slots, nameToSlot, nameToIndex);
  259. // merge in all my slots
  260. FPod fpod = this.m_pod.fpod;
  261. FType ftype = this.m_ftype;
  262. for (int i=0; i<ftype.m_fields.Length; i++)
  263. {
  264. Field f = map(fpod, ftype.m_fields[i]);
  265. merge(f, slots, nameToSlot, nameToIndex);
  266. }
  267. for (int i=0; i<ftype.m_methods.Length; i++)
  268. {
  269. Method m = map(fpod, ftype.m_methods[i]);
  270. merge(m, slots, nameToSlot, nameToIndex);
  271. }
  272. // break out into fields and methods
  273. List fields = new List(Sys.FieldType, slots.sz());
  274. List methods = new List(Sys.MethodType, slots.sz());
  275. for (int i=0; i<slots.sz(); i++)
  276. {
  277. Slot slot = (Slot)slots.get(i);
  278. if (slot is Field)
  279. fields.add(slot);
  280. else
  281. methods.add(slot);
  282. }
  283. this.m_slots = slots.trim();
  284. this.m_fields = fields.trim();
  285. this.m_methods = methods.trim();
  286. this.m_slotsByName = nameToSlot;
  287. this.m_facets = Facets.mapFacets(m_pod, ftype.m_attrs.m_facets);
  288. // facets
  289. this.m_lineNum = m_ftype.m_attrs.m_lineNum;
  290. this.m_sourceFile = m_ftype.m_attrs.m_sourceFile;
  291. }
  292. /// <summary>
  293. /// Merge the inherit's slots into my slot maps.
  294. /// slots: Slot[] by order
  295. /// nameToSlot: String name -> Slot
  296. /// nameToIndex: String name -> Long index of slots
  297. /// </summary>
  298. private void merge(Type inheritedType, List slots, Hashtable nameToSlot, Hashtable nameToIndex)
  299. {
  300. if (inheritedType == null) return;
  301. List inheritedSlots = inheritedType.reflect().slots();
  302. for (int i=0; i<inheritedSlots.sz(); ++i)
  303. merge((Slot)inheritedSlots.get(i), slots, nameToSlot, nameToIndex);
  304. }
  305. /// <summary>
  306. /// Merge the inherited slot into my slot maps. Assume this slot
  307. /// trumps any previous definition (because we process inheritance
  308. /// and my slots in the right order)
  309. /// slots: Slot[] by order
  310. /// nameToSlot: String name -> Slot
  311. /// nameToIndex: String name -> Long index of slots
  312. /// </summary>
  313. private void merge(Slot slot, List slots, Hashtable nameToSlot, Hashtable nameToIndex)
  314. {
  315. // skip constructors which aren't mine
  316. if (slot.isCtor() && slot.m_parent != this) return;
  317. string name = slot.m_name;
  318. if (nameToIndex[name] != null)
  319. {
  320. int dup = (int)nameToIndex[name];
  321. // if the slot is inherited from Obj, then we can
  322. // safely ignore it as an override - the dup is most
  323. // likely already the same Obj method inherited from
  324. // a mixin; but the dup might actually be a more specific
  325. // override in which case we definitely don't want to
  326. // override with the sys::Obj version
  327. if (slot.parent() == Sys.ObjType)
  328. return;
  329. // if given the choice between two *inherited* slots where
  330. // one is concrete and abstract, then choose the concrete one
  331. Slot dupSlot = (Slot)slots.get(dup);
  332. if (slot.parent() != this && slot.isAbstract() && !dupSlot.isAbstract())
  333. return;
  334. // check if this is a Getter or Setter, in which case the Field
  335. // trumps and we need to cache the method on the Field
  336. // Note: this works because we assume the compiler always generates
  337. // the field before the getter and setter in fcode
  338. if ((slot.m_flags & (FConst.Getter|FConst.Setter)) != 0)
  339. {
  340. Field field = (Field)slots.get(dup);
  341. if ((slot.m_flags & FConst.Getter) != 0)
  342. field.m_getter = (Method)slot;
  343. else
  344. field.m_setter = (Method)slot;
  345. return;
  346. }
  347. nameToSlot[name] = slot;
  348. slots.set(dup, slot);
  349. }
  350. else
  351. {
  352. nameToSlot[name] = slot;
  353. slots.add(slot);
  354. nameToIndex[name] = slots.sz()-1;
  355. }
  356. }
  357. /// <summary>
  358. /// Map fcode field to a sys::Field.
  359. /// </summary>
  360. private Field map(FPod fpod, FField f)
  361. {
  362. string name = String.Intern(f.m_name);
  363. Type fieldType = m_pod.findType(f.m_type);
  364. Facets facets = Facets.mapFacets(m_pod, f.m_attrs.m_facets);
  365. return new Field(this, name, f.m_flags, facets, f.m_attrs.m_lineNum, fieldType);
  366. }
  367. /// <summary>
  368. /// Map fcode method to a sys::Method.
  369. /// </summary>
  370. private Method map(FPod fpod, FMethod m)
  371. {
  372. string name = String.Intern(m.m_name);
  373. Type returnType = m_pod.findType(m.m_ret);
  374. Type inheritedReturnType = m_pod.findType(m.m_inheritedRet);
  375. List pars = new List(Sys.ParamType, m.m_paramCount);
  376. for (int j=0; j<m.m_paramCount; j++)
  377. {
  378. FMethodVar p = m.m_vars[j];
  379. int pflags = (p.def == null) ? 0 : Param.HAS_DEFAULT;
  380. pars.add(new Param(String.Intern(p.name), m_pod.findType(p.type), pflags));
  381. }
  382. Facets facets = Facets.mapFacets(m_pod, m.m_attrs.m_facets);
  383. return new Method(this, name, m.m_flags, facets, m.m_attrs.m_lineNum, returnType, inheritedReturnType, pars);
  384. }
  385. //////////////////////////////////////////////////////////////////////////
  386. // Emit
  387. //////////////////////////////////////////////////////////////////////////
  388. /// <summary>
  389. /// Emit to a .NET Type.
  390. /// </summary>
  391. [MethodImpl(MethodImplOptions.Synchronized)]
  392. public System.Type emit()
  393. {
  394. if (m_type == null)
  395. {
  396. if (Debug) Console.WriteLine("-- emit: " + m_qname);
  397. // make sure we have reflected to setup slots
  398. reflect();
  399. // if sys class, just load it by name
  400. string podName = m_pod.m_name;
  401. if (podName == "sys")
  402. {
  403. try
  404. {
  405. m_dotnetRepr = FanUtil.isDotnetRepresentation(this);
  406. m_type = System.Type.GetType(FanUtil.toDotnetImplTypeName(podName, m_name));
  407. }
  408. catch (Exception e)
  409. {
  410. Err.dumpStack(e);
  411. throw Err.make("Cannot load precompiled class: " + m_qname, e).val;
  412. }
  413. }
  414. // otherwise we need to emit it
  415. else
  416. {
  417. try
  418. {
  419. System.Type[] types = FTypeEmit.emitAndLoad(m_ftype);
  420. this.m_type = types[0];
  421. if (types.Length > 1)
  422. this.m_auxType = types[1];
  423. }
  424. catch (Exception e)
  425. {
  426. Err.dumpStack(e);
  427. throw Err.make("Cannot emit: " + m_qname, e).val;
  428. }
  429. }
  430. // we are done with our ftype now, gc it
  431. this.m_ftype = null;
  432. }
  433. return m_type;
  434. }
  435. //////////////////////////////////////////////////////////////////////////
  436. // Finish
  437. //////////////////////////////////////////////////////////////////////////
  438. /// <summary>
  439. /// Finish ensures we have reflected and emitted, then does
  440. /// the final binding between slots and .NET members.
  441. /// </summary>
  442. [MethodImpl(MethodImplOptions.Synchronized)]
  443. public override void finish()
  444. {
  445. if (m_finished) return;
  446. try
  447. {
  448. // ensure reflected and emitted
  449. reflect();
  450. emit();
  451. m_finished = true;
  452. // map .NET members to my slots for reflection; if
  453. // mixin then we do this for both the interface and
  454. // the static methods only of the implementation class
  455. finishSlots(m_type, false);
  456. if (isMixin()) finishSlots(m_auxType, true);
  457. }
  458. catch (Exception e)
  459. {
  460. Err.dumpStack(e);
  461. throw Err.make("Cannot emitFinish: " + m_qname + "." + m_finishing, e).val;
  462. }
  463. finally
  464. {
  465. m_finishing = null;
  466. }
  467. }
  468. /// <summary>
  469. /// Map the Java members of the specified
  470. /// class to my slots for reflection.
  471. /// </summary>
  472. private void finishSlots(System.Type type, bool staticOnly)
  473. {
  474. // map the class's fields to my slots
  475. FieldInfo[] fields = type.GetFields();
  476. for (int i=0; i<fields.Length; i++)
  477. finishField(fields[i]);
  478. // map the class's methods to my slots
  479. MethodInfo[] methods = type.GetMethods();
  480. for (int i=0; i<methods.Length; i++)
  481. finishMethod(methods[i], staticOnly);
  482. }
  483. private void finishField(FieldInfo f)
  484. {
  485. m_finishing = f.Name;
  486. Slot s = slot(f.Name.Substring(2), false); // remove 'm_'
  487. if (s == null || !(s is Field)) return;
  488. Field field = (Field)s;
  489. if (field.m_reflect != null) return; // first one seems to give us most specific binding
  490. //f.setAccessible(true); // TODO - equiv in C# ???
  491. field.m_reflect = f;
  492. }
  493. private void finishMethod(MethodInfo m, bool staticOnly)
  494. {
  495. m_finishing = m.Name;
  496. string name = FanUtil.toFanMethodName(m.Name);
  497. Slot s = slot(name, false);
  498. if (s == null) return;
  499. if (s.parent() != this) return;
  500. if (staticOnly && !s.isStatic()) return;
  501. if (s is Method)
  502. {
  503. Method method = (Method)s;
  504. // alloc System.Reflection.MethodInfo[] array big enough
  505. // to handle all the versions with default parameters
  506. if (method.m_reflect == null)
  507. {
  508. int n = 1;
  509. for (int j=method.@params().sz()-1; j>=0; j--)
  510. {
  511. if (((Param)method.@params().get(j)).hasDefault()) n++;
  512. else break;
  513. }
  514. method.m_reflect = new MethodInfo[n];
  515. }
  516. // get parameters, if sys we need to skip the
  517. // methods that use non-Fantom signatures
  518. ParameterInfo[] pars = m.GetParameters();
  519. int numParams = pars.Length;
  520. if (m_pod == Sys.m_sysPod)
  521. {
  522. if (!checkAllFan(pars)) return;
  523. if (m_dotnetRepr)
  524. {
  525. bool dotnetStatic = m.IsStatic;
  526. if (!dotnetStatic) return;
  527. if (!method.isStatic() && !method.isCtor()) --numParams;
  528. }
  529. }
  530. // zero index is full signature up to using max defaults
  531. method.m_reflect[method.@params().sz()-numParams] = m;
  532. }
  533. else
  534. {
  535. Field field = (Field)s;
  536. if (m.ReturnType.ToString() == "System.Void")
  537. field.m_setter.m_reflect = new MethodInfo[] { m };
  538. else
  539. field.m_getter.m_reflect = new MethodInfo[] { m };
  540. }
  541. }
  542. bool checkAllFan(ParameterInfo[] pars)
  543. {
  544. for (int i=0; i<pars.Length; i++)
  545. {
  546. System.Type p = pars[i].ParameterType;
  547. if (!p.FullName.StartsWith("Fan.") && FanUtil.toFanType(p, false) == null)
  548. return false;
  549. }
  550. return true;
  551. }
  552. public override bool dotnetRepr() { return m_dotnetRepr; }
  553. //////////////////////////////////////////////////////////////////////////
  554. // Fields
  555. //////////////////////////////////////////////////////////////////////////
  556. //TODO
  557. /*
  558. internal static readonly bool Debug = false;
  559. internal static object noParams;
  560. */
  561. // available when hollow
  562. internal readonly Pod m_pod;
  563. internal readonly string m_name;
  564. internal readonly string m_qname;
  565. internal readonly int m_flags;
  566. internal readonly Type m_nullable;
  567. internal int m_lineNum;
  568. internal string m_sourceFile = "";
  569. internal Facets m_facets;
  570. internal Type m_base = null;
  571. internal List m_mixins;
  572. internal List m_inheritance;
  573. internal FType m_ftype; // we only keep this around for memory compiles
  574. internal bool m_docLoaded;
  575. public string m_doc;
  576. // available when reflected
  577. internal List m_fields;
  578. internal List m_methods;
  579. internal List m_slots;
  580. internal Hashtable m_slotsByName; // string:Slot
  581. // available when emitted
  582. internal System.Type m_type; // main .NET type representation
  583. internal System.Type m_auxType; // implementation .NET type if mixin/Err
  584. // flags to ensure we finish only once
  585. bool m_finished;
  586. string m_finishing;
  587. // misc
  588. internal bool m_dotnetRepr; // if representation a .NET type, such as Fan.Sys.Long
  589. }
  590. }