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

/src/CompilerBlob.cs

http://github.com/sorear/niecza
C# | 274 lines | 257 code | 16 blank | 1 comment | 45 complexity | 15eabb4bddbc7c8e5cc1124d06fb5372 MD5 | raw file
Possible License(s): AGPL-3.0
  1. using System;
  2. using System.Reflection;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Text;
  6. using System.Security.Cryptography;
  7. using System.IO;
  8. namespace Niecza {
  9. public abstract class CallReceiver : MarshalByRefObject, IDictionary {
  10. public bool IsFixedSize { get { return false; } }
  11. public bool IsReadOnly { get { return false; } }
  12. public bool IsSynchronized { get { return false; } }
  13. public int Count { get { return 0; } }
  14. public object SyncRoot { get { return null; } }
  15. public ICollection Keys { get { return null; } }
  16. public ICollection Values { get { return null; } }
  17. public void Add(object a, object b) { }
  18. public void Clear() { }
  19. public IDictionaryEnumerator GetEnumerator() { return null; }
  20. IEnumerator IEnumerable.GetEnumerator() { return null; }
  21. public bool Contains(object a) { return false; }
  22. public void CopyTo(Array a, int offs) { }
  23. public void Remove(object a) { }
  24. public abstract object this[object i] { get; set; }
  25. }
  26. public class UpcallReceiver : CallReceiver {
  27. public override object this[object i] {
  28. set { }
  29. get {
  30. object[] ia = (object[]) i;
  31. Variable[] va = new Variable[ia.Length];
  32. for (int ix = 0; ix < ia.Length; ix++)
  33. va[ix] = Downcaller.DCResult(ia[ix]);
  34. try {
  35. Variable vr = Kernel.RunInferior(
  36. Downcaller.upcall_cb.Fetch().Invoke(
  37. Kernel.GetInferiorRoot(), va, null));
  38. return Downcaller.DCArg(vr);
  39. } catch (Exception ex) {
  40. return new Exception(ex.ToString());
  41. }
  42. }
  43. }
  44. }
  45. public class Downcaller {
  46. internal static Variable upcall_cb;
  47. static Variable TrueV, FalseV;
  48. static IDictionary responder;
  49. static P6any UnitP, StaticSubP, TypeP, ParamP, ValueP;
  50. static STable StrMO, NumMO, ListMO, AnyMO, BoolMO;
  51. static string obj_dir;
  52. // Better, but still fudgy. Relies too much on path structure.
  53. public static void InitSlave(Variable cb, P6any cmd_obj_dir, Variable unit,
  54. Variable staticSub, Variable type, Variable param, Variable value,
  55. Variable str, Variable num, Variable @true, Variable @false,
  56. Variable list, Variable any, Variable @bool) {
  57. if (responder != null) return;
  58. UnitP = unit.Fetch();
  59. StaticSubP = staticSub.Fetch();
  60. TypeP = type.Fetch();
  61. ParamP = param.Fetch();
  62. ValueP = value.Fetch();
  63. StrMO = str.Fetch().mo;
  64. NumMO = num.Fetch().mo;
  65. TrueV = @true;
  66. FalseV = @false;
  67. ListMO = list.Fetch().mo;
  68. AnyMO = any.Fetch().mo;
  69. BoolMO = @bool.Fetch().mo;
  70. obj_dir = Path.GetFullPath(cmd_obj_dir.IsDefined() ?
  71. cmd_obj_dir.mo.mro_raw_Str.Get(cmd_obj_dir) :
  72. Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
  73. "NieczaModuleCache"));
  74. Directory.CreateDirectory(obj_dir); // like mkdir -p
  75. if (!File.Exists(Path.Combine(obj_dir, "Run.Kernel.dll"))) {
  76. File.Copy(
  77. Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Run.Kernel.dll"),
  78. Path.Combine(obj_dir, "Run.Kernel.dll")
  79. );
  80. }
  81. var down_asm = Assembly.LoadFrom(Path.Combine(obj_dir, "Run.Kernel.dll"));
  82. upcall_cb = cb;
  83. responder = (IDictionary) down_asm.CreateInstance("Niecza.CLRBackend.DowncallReceiver");
  84. }
  85. public static void InitCompartment(Variable c) {
  86. RawDowncall("set_binding", DCArg(c), obj_dir, new UpcallReceiver());
  87. }
  88. public static object RawDowncall(params object[] args) {
  89. return responder[args];
  90. }
  91. internal static object DCArg(Variable v) {
  92. P6any o = v.Fetch();
  93. if (o is BoxObject<object>)
  94. return Kernel.UnboxAny<object>(o);
  95. else if (o.IsDefined()) {
  96. if (o.Isa(StrMO))
  97. return (string) o.mo.mro_raw_Str.Get(v);
  98. else if (o.Isa(BoolMO))
  99. return (bool) o.mo.mro_raw_Bool.Get(v);
  100. else if (o.Isa(NumMO)) {
  101. double d = Kernel.UnboxAny<double>(o);
  102. if ((d % 1) == 0 && d <= int.MaxValue && d >= int.MinValue)
  103. return (object)(int)d;
  104. return (object)d;
  105. } else if (o.Isa(ListMO)) {
  106. VarDeque it = o.mo.mro_raw_iterator.Get(v);
  107. var lo = new List<object>();
  108. while (Kernel.IterHasFlat(it, true))
  109. lo.Add(DCArg(it.Shift()));
  110. return lo.ToArray();
  111. } else
  112. return (int) o.mo.mro_raw_Numeric.Get(v);
  113. } else
  114. return null;
  115. }
  116. public static Variable DownCall(Variable list) {
  117. List<object> lo = new List<object>();
  118. VarDeque it = Builtins.start_iter(list);
  119. while (Kernel.IterHasFlat(it, true))
  120. lo.Add(DCArg(it.Shift()));
  121. return DCResult(RawDowncall(lo.ToArray()));
  122. }
  123. internal static Variable DCResult(object r) {
  124. if (r == null) return AnyMO.typeObj;
  125. else if (r is string) return Kernel.BoxAnyMO((string)r, StrMO);
  126. else if (r is int) return Builtins.MakeInt((int)r);
  127. else if (r is bool) return ((bool)r) ? TrueV : FalseV;
  128. else if (r is Exception) throw new NieczaException(((Exception)r).Message);
  129. else if (r is object[]) {
  130. object[] ra = (object[])r;
  131. Variable[] ba = new Variable[ra.Length];
  132. for (int i = 0; i < ba.Length; i++) ba[i] = DCResult(ra[i]);
  133. return Builtins.MakeParcel(ba);
  134. }
  135. else {
  136. string t = (string)RawDowncall("gettype", r);
  137. P6any pr = (t == "type") ? TypeP :
  138. (t == "sub") ? StaticSubP :
  139. (t == "param") ? ParamP :
  140. (t == "value") ? ValueP :
  141. (t == "unit") ? UnitP : AnyMO.typeObj;
  142. return Kernel.BoxAnyMO(r, pr.mo);
  143. }
  144. }
  145. static void SerializeNam(Variable v, StringBuilder sb,
  146. List<object> refs) {
  147. P6any o = v.Fetch();
  148. if (o is BoxObject<int>) { /* includes bool */
  149. sb.Append(Kernel.UnboxAny<int>(o));
  150. } else if (o is BoxObject<double>) {
  151. sb.Append(Utils.N2S(Kernel.UnboxAny<double>(o)));
  152. } else if (o is BoxObject<string>) {
  153. string s = Kernel.UnboxAny<string>(o);
  154. sb.Append('"');
  155. foreach (char c in s) {
  156. if (c >= ' ' && c <= '~' && c != '\\' && c != '"')
  157. sb.Append(c);
  158. else {
  159. sb.Append("\\u");
  160. sb.AppendFormat("{0:X4}", (int)c);
  161. }
  162. }
  163. sb.Append('"');
  164. } else if (!o.IsDefined()) {
  165. sb.Append("null");
  166. } else if (o.Isa(ListMO)) {
  167. VarDeque d = o.mo.mro_raw_iterator.Get(v);
  168. bool comma = false;
  169. sb.Append('[');
  170. while (Kernel.IterHasFlat(d, true)) {
  171. if (comma) sb.Append(',');
  172. SerializeNam(d.Shift(), sb, refs);
  173. comma = true;
  174. }
  175. sb.Append(']');
  176. } else if (o is BoxObject<object>) {
  177. sb.Append('!');
  178. sb.Append(refs.Count);
  179. refs.Add(Kernel.UnboxAny<object>(o));
  180. } else {
  181. throw new NieczaException("weird object in sub_finish " + o.mo.name);
  182. }
  183. }
  184. public static Variable Finish(Variable si, Variable nam) {
  185. StringBuilder sb = new StringBuilder();
  186. List<object> refs = new List<object>();
  187. SerializeNam(nam, sb, refs);
  188. object[] args = new object[refs.Count + 3];
  189. args[0] = "sub_finish";
  190. args[1] = Kernel.UnboxAny<object>(si.Fetch());
  191. args[2] = sb.ToString();
  192. refs.CopyTo(args, 3);
  193. return DCResult(RawDowncall(args));
  194. }
  195. public static string DoHash(string input) {
  196. HashAlgorithm sha = SHA256.Create();
  197. byte[] ibytes = new UTF8Encoding().GetBytes(input);
  198. byte[] hash = sha.ComputeHash(ibytes);
  199. char[] buf = new char[hash.Length * 2];
  200. for (int i = 0; i < hash.Length; i++) {
  201. buf[i*2] = "0123456789abcdef"[hash[i] >> 4];
  202. buf[i*2+1] = "0123456789abcdef"[hash[i] & 15];
  203. }
  204. return new string(buf);
  205. }
  206. public static string ExecName() {
  207. return Assembly.GetEntryAssembly().Location;
  208. }
  209. static Dictionary<P6any,Dictionary<P6any,Variable>> role_cache =
  210. new Dictionary<P6any,Dictionary<P6any,Variable>>();
  211. public static Variable CachedBut(P6any but, Variable v1, Variable v2) {
  212. P6any a1 = v1.Fetch();
  213. P6any a2 = v2.Fetch();
  214. Dictionary<P6any,Variable> subcache;
  215. if (!role_cache.TryGetValue(a1, out subcache))
  216. role_cache[a1] = subcache = new Dictionary<P6any,Variable>();
  217. Variable var;
  218. if (subcache.TryGetValue(a2, out var))
  219. return var;
  220. // Mega-Hack - stop lots of internal data from being retained by
  221. // CALLER pointers
  222. Kernel.SetTopFrame(null);
  223. var = Kernel.RunInferior(but.Invoke(Kernel.GetInferiorRoot(),
  224. new [] { v1, v2 }, null));
  225. return subcache[a2] = var;
  226. }
  227. public static Variable PruneMatch(Variable vr) {
  228. Cursor c = (Cursor)vr.Fetch();
  229. // remove as much as possible - don't call this if you still need
  230. // the match!
  231. if (c.feedback != null) {
  232. c.feedback.CommitRule();
  233. c.feedback.bt = null;
  234. c.feedback.st = new State();
  235. c.feedback.ast = null;
  236. }
  237. for (CapInfo it = c.captures; it != null; it = it.prev) {
  238. if (it.cap != null && it.cap.Fetch() is Cursor)
  239. PruneMatch(it.cap);
  240. }
  241. c.captures = null;
  242. c.feedback = null;
  243. c.ast = null;
  244. c.xact = null;
  245. c.nstate = null;
  246. return vr;
  247. }
  248. }
  249. }