Skip to content
This repository
tree: 2d14b99510
Fetching contributors…

Cannot retrieve contributors at this time

file 262 lines (240 sloc) 10.585 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
using System;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace Niecza {
    public abstract class CallReceiver : MarshalByRefObject, IDictionary {
        public bool IsFixedSize { get { return false; } }
        public bool IsReadOnly { get { return false; } }
        public bool IsSynchronized { get { return false; } }
        public int Count { get { return 0; } }
        public object SyncRoot { get { return null; } }
        public ICollection Keys { get { return null; } }
        public ICollection Values { get { return null; } }
        public void Add(object a, object b) { }
        public void Clear() { }
        public IDictionaryEnumerator GetEnumerator() { return null; }
        IEnumerator IEnumerable.GetEnumerator() { return null; }
        public bool Contains(object a) { return false; }
        public void CopyTo(Array a, int offs) { }
        public void Remove(object a) { }
        public abstract object this[object i] { get; set; }
    }

    public class UpcallReceiver : CallReceiver {
        public override object this[object i] {
            set { }
            get {
                object[] ia = (object[]) i;
                Variable[] va = new Variable[ia.Length];
                for (int ix = 0; ix < ia.Length; ix++)
                    va[ix] = Downcaller.DCResult(ia[ix]);
                try {
                    Variable vr = Kernel.RunInferior(
                            Downcaller.upcall_cb.Fetch().Invoke(
                                Kernel.GetInferiorRoot(), va, null));
                    return Downcaller.DCArg(vr);
                } catch (Exception ex) {
                    return new Exception(ex.ToString());
                }
            }
        }
    }

    public class Downcaller {
        internal static Variable upcall_cb;
        static IDictionary responder;
        static P6any UnitP, StaticSubP, TypeP, ParamP, ValueP;
        static string obj_dir;

        // let the CLR load assemblies from obj/ too
        static Assembly ObjLoader(object source, ResolveEventArgs e) {
            string name = e.Name;
            if (name.IndexOf(',') >= 0)
                name = name.Substring(0, name.IndexOf(','));
            string file = Path.Combine(obj_dir, name + ".dll");
            if (File.Exists(file))
                return Assembly.LoadFrom(file);
            else
                return null;
        }
        // Better, but still fudgy. Relies too much on path structure.
        public static void InitSlave(Variable cb, Variable unit,
                Variable staticSub, Variable type, Variable param, Variable value) {
            if (responder != null) return;

            UnitP = unit.Fetch();
            StaticSubP = staticSub.Fetch();
            TypeP = type.Fetch();
            ParamP = param.Fetch();
            ValueP = value.Fetch();

            obj_dir = Path.GetFullPath(Path.Combine(
                        AppDomain.CurrentDomain.BaseDirectory,
                        Path.Combine("..", "obj")));
            AppDomain.CurrentDomain.AssemblyResolve += ObjLoader;

            upcall_cb = cb;
            responder = (IDictionary) Activator.CreateInstance(Type.GetType(
                    "Niecza.CLRBackend.DowncallReceiver,Run.Kernel", true));
            RawDowncall("set_binding", obj_dir, new UpcallReceiver());
        }
        public static object RawDowncall(params object[] args) {
            return responder[args];
        }

        internal static object DCArg(Variable v) {
            P6any o = v.Fetch();
            if (o is BoxObject<object>)
                return Kernel.UnboxAny<object>(o);
            else if (o.IsDefined()) {
                if (o.Isa(Kernel.StrMO))
                    return (string) o.mo.mro_raw_Str.Get(v);
                else if (o.Isa(Kernel.BoolMO))
                    return (bool) o.mo.mro_raw_Bool.Get(v);
                else if (o.Isa(Kernel.NumMO)) {
                    double d = Kernel.UnboxAny<double>(o);
                    if ((d % 1) == 0 && d <= int.MaxValue && d >= int.MinValue)
                        return (object)(int)d;
                    return (object)d;
                } else if (o.Isa(Kernel.ListMO)) {
                    VarDeque it = o.mo.mro_raw_iterator.Get(v);
                    var lo = new List<object>();
                    while (Kernel.IterHasFlat(it, true))
                        lo.Add(DCArg(it.Shift()));
                    return lo.ToArray();
                } else
                    return (int) o.mo.mro_raw_Numeric.Get(v);
            } else
                return null;
        }

        public static Variable DownCall(Variable list) {
            List<object> lo = new List<object>();
            VarDeque it = Builtins.start_iter(list);
            while (Kernel.IterHasFlat(it, true))
                lo.Add(DCArg(it.Shift()));

            return DCResult(RawDowncall(lo.ToArray()));
        }

        internal static Variable DCResult(object r) {
            if (r == null) return Kernel.AnyP;
            else if (r is string) return Kernel.BoxAnyMO((string)r, Kernel.StrMO);
            else if (r is int) return Builtins.MakeInt((int)r);
            else if (r is bool) return ((bool)r) ? Kernel.TrueV : Kernel.FalseV;
            else if (r is Exception) throw new NieczaException(((Exception)r).Message);
            else if (r is object[]) {
                object[] ra = (object[])r;
                Variable[] ba = new Variable[ra.Length];
                for (int i = 0; i < ba.Length; i++) ba[i] = DCResult(ra[i]);
                return Builtins.MakeParcel(ba);
            }
            else {
                string t = (string)RawDowncall("gettype", r);
                P6any pr = (t == "type") ? TypeP :
                    (t == "sub") ? StaticSubP :
                    (t == "param") ? ParamP :
                    (t == "value") ? ValueP :
                    (t == "unit") ? UnitP : Kernel.AnyP;
                return Kernel.BoxAnyMO(r, pr.mo);
            }
        }

        static void SerializeNam(Variable v, StringBuilder sb,
                List<object> refs) {

            P6any o = v.Fetch();
            if (o is BoxObject<int>) { /* includes bool */
                sb.Append(Kernel.UnboxAny<int>(o));
            } else if (o is BoxObject<double>) {
                sb.Append(Utils.N2S(Kernel.UnboxAny<double>(o)));
            } else if (o is BoxObject<string>) {
                string s = Kernel.UnboxAny<string>(o);
                sb.Append('"');
                foreach (char c in s) {
                    if (c >= ' ' && c <= '~' && c != '\\' && c != '"')
                        sb.Append(c);
                    else {
                        sb.Append("\\u");
                        sb.AppendFormat("{0:X4}", (int)c);
                    }
                }
                sb.Append('"');
            } else if (!o.IsDefined()) {
                sb.Append("null");
            } else if (o.Isa(Kernel.ListMO)) {
                VarDeque d = o.mo.mro_raw_iterator.Get(v);
                bool comma = false;
                sb.Append('[');
                while (Kernel.IterHasFlat(d, true)) {
                    if (comma) sb.Append(',');
                    SerializeNam(d.Shift(), sb, refs);
                    comma = true;
                }
                sb.Append(']');
            } else if (o is BoxObject<object>) {
                sb.Append('!');
                sb.Append(refs.Count);
                refs.Add(Kernel.UnboxAny<object>(o));
            } else {
                throw new NieczaException("weird object in sub_finish " + o.mo.name);
            }
        }

        public static Variable Finish(Variable si, Variable nam) {
            StringBuilder sb = new StringBuilder();
            List<object> refs = new List<object>();
            SerializeNam(nam, sb, refs);
            object[] args = new object[refs.Count + 3];
            args[0] = "sub_finish";
            args[1] = Kernel.UnboxAny<object>(si.Fetch());
            args[2] = sb.ToString();
            refs.CopyTo(args, 3);
            return DCResult(RawDowncall(args));
        }

        public static string DoHash(string input) {
            HashAlgorithm sha = SHA256.Create();
            byte[] ibytes = new UTF8Encoding().GetBytes(input);
            byte[] hash = sha.ComputeHash(ibytes);
            char[] buf = new char[hash.Length * 2];
            for (int i = 0; i < hash.Length; i++) {
                buf[i*2] = "0123456789abcdef"[hash[i] >> 4];
                buf[i*2+1] = "0123456789abcdef"[hash[i] & 15];
            }
            return new string(buf);
        }

        public static string ExecName() {
            return Assembly.GetEntryAssembly().Location;
        }

        static Dictionary<P6any,Dictionary<P6any,Variable>> role_cache =
            new Dictionary<P6any,Dictionary<P6any,Variable>>();
        public static Variable CachedBut(P6any but, Variable v1, Variable v2) {
            P6any a1 = v1.Fetch();
            P6any a2 = v2.Fetch();
            Dictionary<P6any,Variable> subcache;
            if (!role_cache.TryGetValue(a1, out subcache))
                role_cache[a1] = subcache = new Dictionary<P6any,Variable>();
            Variable var;
            if (subcache.TryGetValue(a2, out var))
                return var;

            // Mega-Hack - stop lots of internal data from being retained by
            // CALLER pointers
            Kernel.SetTopFrame(null);

            var = Kernel.RunInferior(but.Invoke(Kernel.GetInferiorRoot(),
                new [] { v1, v2 }, null));
            return subcache[a2] = var;
        }

        public static Variable PruneMatch(Variable vr) {
            Cursor c = (Cursor)vr.Fetch();
            // remove as much as possible - don't call this if you still need
            // the match!
            if (c.feedback != null) {
                c.feedback.CommitRule();
                c.feedback.bt = null;
                c.feedback.st = new State();
                c.feedback.ast = null;
            }

            for (CapInfo it = c.captures; it != null; it = it.prev) {
                if (it.cap != null && it.cap.Fetch() is Cursor)
                    PruneMatch(it.cap);
            }

            c.captures = null;
            c.feedback = null;
            c.ast = null;
            c.xact = null;
            c.nstate = null;
            return vr;
        }
    }
}
Something went wrong with that request. Please try again.