PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/sys/dotnet/fan/sys/Pod.cs

https://bitbucket.org/bedlaczech/fan-1.0
C# | 507 lines | 324 code | 65 blank | 118 comment | 71 complexity | b445fce55440e52188f1089d4aee1d07 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. // 24 Sep 06 Andy Frank Creation
  7. //
  8. using System;
  9. using System.Collections;
  10. using System.IO;
  11. using DirectoryInfo = System.IO.DirectoryInfo;
  12. using FileInfo = System.IO.FileInfo;
  13. using Fanx.Emit;
  14. using Fanx.Fcode;
  15. using Fanx.Util;
  16. using ICSharpCode.SharpZipLib.Zip;
  17. namespace Fan.Sys
  18. {
  19. /// <summary>
  20. /// Pod is a module containing Types. A Pod is always backed by a FPod
  21. /// instance which defines all the definition tables. Usually the FPod
  22. /// is in turn backed by a FStore for the pod's zip file. However in the
  23. /// case of memory-only pods defined by the compiler, the fpod.store field
  24. /// will be null.
  25. ///
  26. /// Pods is loaded as soon as it is constructed:
  27. /// 1) All the types defined by the fpod are mapped into hollow Types.
  28. /// 2) It is emitted as a Java class called "fan.{podName}.$Pod". The
  29. /// emitted class is basically a manifestation of the literal tables,
  30. /// after which we can clear the fpod data structures.
  31. /// </summary>
  32. public class Pod : FanObj
  33. {
  34. //////////////////////////////////////////////////////////////////////////
  35. // Management
  36. //////////////////////////////////////////////////////////////////////////
  37. public static Pod of(object obj)
  38. {
  39. return Type.of(obj).pod();
  40. }
  41. public static Pod find(string name) { return doFind(name, true, null); }
  42. public static Pod find(string name, bool check) { return doFind(name, check, null); }
  43. public static Pod doFind(string name, bool check, FPod fpod)
  44. {
  45. try
  46. {
  47. lock (m_podsByName)
  48. {
  49. // TODO - .NET does not have soft references, so how could
  50. // we implement this? See the Pod.java for the java impl.
  51. Pod pod = (Pod)m_podsByName[name];
  52. if (pod == null)
  53. {
  54. // if fpod is non-null, then we are "creating" this pod in
  55. // memory direct from the compiler, otherwise we need to
  56. // find the pod zip file and load it's meta-data
  57. if (fpod == null) fpod = readFPod(name);
  58. // sanity check
  59. if (fpod.m_podName != name)
  60. throw new Exception("Mismatched pod name b/w pod.def and pod zip filename: " + fpod.m_podName + " != " + name);
  61. // create the pod and register it
  62. pod = new Pod(fpod);
  63. m_podsByName[name] = pod;
  64. }
  65. return pod;
  66. }
  67. }
  68. catch (UnknownPodErr.Val e)
  69. {
  70. if (!check) return null;
  71. throw e;
  72. }
  73. catch (Exception e)
  74. {
  75. Err.dumpStack(e);
  76. if (!check) return null;
  77. throw UnknownPodErr.make(name, e).val;
  78. }
  79. }
  80. public static Pod load(InStream @in)
  81. {
  82. FPod fpod = null;
  83. try
  84. {
  85. fpod = new FPod(null, null);
  86. fpod.readFully(new ZipInputStream(SysInStream.dotnet(@in)));
  87. }
  88. catch (Exception e)
  89. {
  90. throw Err.make(e).val;
  91. }
  92. string name = fpod.m_podName;
  93. lock (m_podsByName)
  94. {
  95. // check for duplicate pod name
  96. if (m_podsByName[name] != null)
  97. throw Err.make("Duplicate pod name: " + name).val;
  98. // create Pod and add to master table
  99. Pod pod = new Pod(fpod);
  100. m_podsByName[name] = pod; //new SoftReference(pod);
  101. return pod;
  102. }
  103. }
  104. public static FPod readFPod(string name)
  105. {
  106. FStore store = null;
  107. // handle sys specially for bootstrapping the VM
  108. if (name == "sys")
  109. {
  110. store = new FStore(new ZipFile(FileUtil.combine(Sys.m_podsDir, name + ".pod")));
  111. }
  112. // otherwise delegate to Env.cur to find the pod file
  113. else
  114. {
  115. FileSystemInfo file = null;
  116. Fan.Sys.File f = Env.cur().findPodFile(name);
  117. if (f != null) file = ((LocalFile)f).m_file;
  118. // if null or doesn't exist then its a no go
  119. if (file == null || !file.Exists) throw UnknownPodErr.make(name).val;
  120. // verify case since Windoze is case insensitive
  121. String actualName = file.Name; //getCanonicalFile().getName();
  122. actualName = actualName.Substring(0, actualName.Length-4);
  123. if (actualName != name) throw UnknownPodErr.make("Mismatch case: " + name + " != " + actualName).val;
  124. store = new FStore(new ZipFile(file.FullName));
  125. }
  126. // read in the FPod tables
  127. FPod fpod = new FPod(name, store);
  128. fpod.read();
  129. return fpod;
  130. }
  131. public static List list()
  132. {
  133. lock (m_podsByName)
  134. {
  135. // TODO - eventually we need a faster way to load
  136. // pod meta-data into memory without actually loading
  137. // every pod into memory
  138. if (m_allPodsList == null)
  139. {
  140. List names = Env.cur().findAllPodNames();
  141. List pods = new List(Sys.PodType);
  142. for (int i=0; i<names.sz(); ++i)
  143. {
  144. string name = (string)names.get(i);
  145. try
  146. {
  147. pods.add(doFind(name, true, null));
  148. }
  149. catch (Exception e)
  150. {
  151. System.Console.WriteLine("ERROR: Invalid pod file: " + name);
  152. Err.dumpStack(e);
  153. }
  154. }
  155. m_allPodsList = pods.ro();
  156. }
  157. return m_allPodsList;
  158. }
  159. }
  160. //////////////////////////////////////////////////////////////////////////
  161. // Constructor
  162. //////////////////////////////////////////////////////////////////////////
  163. internal Pod(FPod fpod)
  164. {
  165. this.m_name = fpod.m_podName;
  166. load(fpod);
  167. }
  168. //////////////////////////////////////////////////////////////////////////
  169. // Methods
  170. //////////////////////////////////////////////////////////////////////////
  171. public override Type @typeof() { return Sys.PodType; }
  172. public string name() { return m_name; }
  173. public Version version()
  174. {
  175. if (m_version == null)
  176. m_version = Version.fromStr(fpod.m_podVersion);
  177. return m_version;
  178. }
  179. public List depends()
  180. {
  181. if (m_depends == null)
  182. m_depends = (List)new List(Sys.DependType, fpod.m_depends).toImmutable();
  183. return m_depends;
  184. }
  185. public Uri uri()
  186. {
  187. if (m_uri == null) m_uri = Uri.fromStr("fan://" + m_name);
  188. return m_uri;
  189. }
  190. public override string toStr() { return m_name; }
  191. public Map meta()
  192. {
  193. if (m_meta == null)
  194. {
  195. try
  196. {
  197. if (fpod.m_meta != null) m_meta = (Map)fpod.m_meta;
  198. else
  199. {
  200. InStream input = new SysInStream(fpod.m_store.read("meta.props"));
  201. m_meta = (Map)input.readProps().toImmutable();
  202. input.close();
  203. }
  204. }
  205. catch (Exception e)
  206. {
  207. Err.dumpStack(e);
  208. m_meta = Sys.m_emptyStrStrMap;
  209. }
  210. }
  211. return m_meta;
  212. }
  213. //////////////////////////////////////////////////////////////////////////
  214. // Types
  215. //////////////////////////////////////////////////////////////////////////
  216. public List types() { return new List(Sys.TypeType, m_types); }
  217. public Type type(string name) { return type(name, true); }
  218. public Type type(string name, bool check)
  219. {
  220. Type type = (Type)typesByName[name];
  221. if (type != null) return type;
  222. if (check) throw UnknownTypeErr.make(this.m_name + "::" + name).val;
  223. return null;
  224. }
  225. //////////////////////////////////////////////////////////////////////////
  226. // Documentation
  227. //////////////////////////////////////////////////////////////////////////
  228. public string doc()
  229. {
  230. if (!m_docLoaded)
  231. {
  232. try
  233. {
  234. Stream input = fpod.m_store.read("doc/pod.fandoc");
  235. if (input != null) m_doc = SysInStream.make(input, Long.valueOf(1024L)).readAllStr();
  236. }
  237. catch (Exception e)
  238. {
  239. Err.dumpStack(e);
  240. }
  241. m_docLoaded = true;
  242. }
  243. return m_doc;
  244. }
  245. //////////////////////////////////////////////////////////////////////////
  246. // Files
  247. //////////////////////////////////////////////////////////////////////////
  248. public List files()
  249. {
  250. loadFiles();
  251. return m_filesList;
  252. }
  253. public Fan.Sys.File file(Uri uri) { return file(uri, true); }
  254. public Fan.Sys.File file(Uri uri, bool check)
  255. {
  256. loadFiles();
  257. if (!uri.isPathAbs())
  258. throw ArgErr.make("Pod.files Uri must be path abs: " + uri).val;
  259. if (uri.auth() != null && !uri.toStr().StartsWith(this.uri().toStr()))
  260. throw ArgErr.make("Invalid base uri `" + uri + "` for `" + this.uri() + "`").val;
  261. else
  262. uri = this.uri().plus(uri);
  263. Fan.Sys.File f = (Fan.Sys.File)m_filesMap[uri];
  264. if (f != null || !check) return f;
  265. throw UnresolvedErr.make(uri.toStr()).val;
  266. }
  267. private void loadFiles()
  268. {
  269. lock (m_filesMap)
  270. {
  271. if (m_filesList != null) return;
  272. this.m_filesList = (List)fpod.m_store.podFiles(uri()).toImmutable();
  273. for (int i=0; i<m_filesList.sz(); ++i)
  274. {
  275. Fan.Sys.File f = (Fan.Sys.File)m_filesList.get(i);
  276. m_filesMap[f.uri()] = f;
  277. }
  278. }
  279. }
  280. //////////////////////////////////////////////////////////////////////////
  281. // Utils
  282. //////////////////////////////////////////////////////////////////////////
  283. public Log log()
  284. {
  285. if (m_log == null) m_log = Log.get(m_name);
  286. return m_log;
  287. }
  288. public Map props(Uri uri, Duration maxAge)
  289. {
  290. return Env.cur().props(this, uri, maxAge);
  291. }
  292. public string config(string key)
  293. {
  294. return Env.cur().config(this, key);
  295. }
  296. public string config(string key, string def)
  297. {
  298. return Env.cur().config(this, key, def);
  299. }
  300. public string locale(string key)
  301. {
  302. return Env.cur().locale(this, key);
  303. }
  304. public string locale(string key, string def)
  305. {
  306. return Env.cur().locale(this, key, def);
  307. }
  308. //////////////////////////////////////////////////////////////////////////
  309. // Load
  310. //////////////////////////////////////////////////////////////////////////
  311. internal void load(FPod fpod)
  312. {
  313. this.fpod = fpod;
  314. this.typesByName = new Hashtable();
  315. // create a hollow Type for each FType (this requires two steps,
  316. // because we don't necessary have all the Types created for
  317. // superclasses until this loop completes)
  318. m_types = new ClassType[fpod.m_types.Length];
  319. for (int i=0; i<fpod.m_types.Length; i++)
  320. {
  321. // create type instance
  322. ClassType type = new ClassType(this, fpod.m_types[i]);
  323. // add to my data structures
  324. m_types[i] = type;
  325. if (typesByName[type.m_name] != null)
  326. throw Err.make("Invalid pod: " + m_name + " type already defined: " + type.m_name).val;
  327. typesByName[type.m_name] = type;
  328. }
  329. // get TypeType to use for mixin List (we need to handle case
  330. // when loading sys itself - and lookup within my own pod)
  331. Type typeType = Sys.TypeType;
  332. if (typeType == null)
  333. typeType = (Type)typesByName["Type"];
  334. // now that everthing is mapped, we can fill in the super
  335. // class fields (unless something is wacked, this will only
  336. // use Types in my pod or in pods already loaded)
  337. for (int i=0; i<fpod.m_types.Length; i++)
  338. {
  339. FType ftype = fpod.m_types[i];
  340. ClassType type = m_types[i];
  341. type.m_base = findType(ftype.m_base);
  342. List mixins = new List(typeType, ftype.m_mixins.Length);
  343. for (int j=0; j<ftype.m_mixins.Length; j++)
  344. mixins.add(findType(ftype.m_mixins[j]));
  345. type.m_mixins = mixins.ro();
  346. }
  347. }
  348. /*
  349. synchronized Class emit()
  350. {
  351. if (cls == null)
  352. cls = FPodEmit.emitAndLoad(fpod);
  353. return cls;
  354. }
  355. synchronized void precompiled(Class cls)
  356. throws Exception
  357. {
  358. this.cls = cls;
  359. FPodEmit.initFields(fpod, cls);
  360. }
  361. */
  362. internal Type findType(int qname)
  363. {
  364. if (qname == 0xFFFF || qname == -1) return null;
  365. // lookup type with typeRef index
  366. FTypeRef reference = fpod.typeRef(qname);
  367. // if generic instance, then this type must be used in a method
  368. // signature, not type meta-data (b/c I can't subclass generic types),
  369. // so it's safe that my pod has been loaded and is now registered (in
  370. // case the generic type is parameterized via types in my pod)
  371. if (reference.isGenericInstance())
  372. return TypeParser.load(reference.signature, true, this);
  373. // otherwise I need to handle if I am loading my own pod, because
  374. // I might not yet be added to the system namespace if I'm just
  375. // loading my own hollow types
  376. string podName = reference.podName;
  377. string typeName = reference.typeName;
  378. Pod pod = podName == m_name ? this : doFind(podName, true, null);
  379. Type type = pod.type(typeName, false);
  380. if (type != null)
  381. {
  382. if (reference.isNullable()) type = type.toNullable();
  383. return type;
  384. }
  385. // handle generic parameter types (for sys pod only)
  386. if (m_name == "sys")
  387. {
  388. type = Sys.genericParamType(typeName);
  389. if (type != null)
  390. {
  391. if (reference.isNullable()) type = type.toNullable();
  392. return type;
  393. }
  394. }
  395. // lost cause
  396. throw UnknownTypeErr.make(podName + "::" + typeName).val;
  397. }
  398. /// <summary>
  399. /// Close the pod which should release any locks on the pod
  400. /// file. This method exists only for testing, and should
  401. /// not otherwise be used.
  402. /// </summary>
  403. public void close()
  404. {
  405. fpod.m_store.close();
  406. }
  407. //////////////////////////////////////////////////////////////////////////
  408. // Compiler Support
  409. //////////////////////////////////////////////////////////////////////////
  410. //TODO
  411. /*
  412. // stub is used when sys.pod is not found, so that we can stub
  413. // enough to do self tests and compile sys itself
  414. internal Type stub(Type type)
  415. {
  416. if (typesByName == null) typesByName = new Hashtable();
  417. typesByName[type.name()] = type;
  418. return type;
  419. }
  420. */
  421. //////////////////////////////////////////////////////////////////////////
  422. // Fields
  423. //////////////////////////////////////////////////////////////////////////
  424. internal static Hashtable m_podsByName = new Hashtable();
  425. internal static List m_allPodsList = null;
  426. internal readonly string m_name;
  427. internal Uri m_uri;
  428. internal FPod fpod;
  429. internal Version m_version;
  430. internal List m_depends;
  431. internal ClassType[] m_types;
  432. internal Hashtable typesByName;
  433. internal List m_filesList;
  434. internal Hashtable m_filesMap = new Hashtable(11);
  435. internal Map m_meta;
  436. internal Hashtable locales = new Hashtable(4);
  437. internal Log m_log;
  438. internal bool m_docLoaded;
  439. public string m_doc;
  440. }
  441. }