private object Eval (Action<StringBuilder, Dictionary<Type, int>> expr, Func<StringParser, object> import) { var sb1 = new StringBuilder(); var toBeLoaded = new Dictionary<Type, int>(); sb1.Append("(function(){try{"); if (import != null) { sb1.Append("return "); expr(sb1, toBeLoaded); sb1.Append(';'); } else { expr(sb1, toBeLoaded); sb1.Append("return \"undefined\""); } sb1.Append("}catch(e){return "); sb1.Append(database.RootExpression); sb1.Append(".ImportException("); sb1.Append(TypeIndex(toBeLoaded, typeof(JSObject))); sb1.Append(",e);}})()"); var sb2 = default(StringBuilder); if (toBeLoaded.Count > 0) { sb2 = new StringBuilder(); AppendLoadRequiredTypes(sb2, toBeLoaded); } var res = default(string); bridge.InJavaScriptContext (() => { if (sb2 != null) { Log("! " + sb2.ToString()); bridge.EvalStatementString(sb2.ToString()); } Log("> " + sb1.ToString()); res = bridge.EvalExpressionString(sb1.ToString()); Log("< " + res); }); var sp = new StringParser(res); sp.SkipWS(); if (sp.TryConsumeChar('~')) throw MakeInvalidCastException(); else if (sp.TryConsumeChar('!')) { var ops = FindInteropOps(typeof(Exception)); throw (Exception)ops.Import(sp); } else if (sp.TryConsumeChar('#')) { var ops = FindInteropOps(typeof (JSObject)); var underlyingException = (JSObject)ops.Import(sp); throw MakeJSException(underlyingException); } else if (import != null) return import(sp); else if (sp.TryConsumeLit("undefined")) return null; else throw new InvalidOperationException("unexpected result of statement execution"); }
private static Type ConsumeType(StringParser sp) { sp.SkipWS(); sp.ConsumeChar('['); var assmName = sp.ConsumeUntilChar(']'); sp.ConsumeChar(']'); var typeName = sp.ConsumeUntilChar('<'); var args = default(List<Type>); if (sp.TryConsumeChar('<')) { args = new List<Type>(); while (true) { if (sp.Failed) break; args.Add(ConsumeType(sp)); sp.SkipWS(); if (sp.TryConsumeChar('>')) break; sp.ConsumeChar(','); } } if (sp.Failed) throw new InvalidOperationException("syntax error in qualified type name"); var assm = default(Assembly); try { assm = Assembly.Load(assmName); } catch (FileNotFoundException) { throw new InvalidOperationException("no such assembly"); } var hkType = assm.GetType(typeName); if (hkType == null) throw new InvalidOperationException("no such type"); if (args == null) return hkType; else { try { return hkType.MakeGenericType(args.ToArray()); } catch (InvalidOperationException) { throw new InvalidOperationException("type is not higher-kinded"); } catch (ArgumentException) { throw new InvalidOperationException("mismatched type arity"); } } }
// XREF1451 public override object Import(StringParser sp) { sp.SkipWS(); if (sp.TryConsumeLit("null")) return null; else { sp.ConsumeChar('['); sp.SkipWS(); if (sp.TryConsumeChar(']')) return Array.CreateInstance(elemInteropOps.type, 0); var objs = new List<object>(); while (true) { if (sp.Failed) throw new InvalidOperationException("invalid response"); objs.Add(elemInteropOps.Import(sp)); sp.SkipWS(); if (sp.TryConsumeChar(']')) { var res = Array.CreateInstance(elemInteropOps.type, objs.Count); for (var i = 0; i < objs.Count; i++) res.SetValue(objs[i], i); return res; } sp.ConsumeChar(','); } } }