protected EvalSession(IVault vault, IVault repository) { AppDomain.CurrentDomain.Load("Esath.Data"); _expositions.Add(vault.AssertNotNull().ExposeReadOnly()); if (repository != null) { _expositions.Add(repository.AssertNotNull().ExposeReadOnly()); } VM = new VirtualMachine(); VM.Context.Add("vault", vault); VM.Context.Add("repository", repository); VM.Context.Add("designTime", repository == null); VM.Context.Add("evalCache", new Dictionary<VPath, Object>()); VM.Context.Add("evalSession", this); VM.Context.Add("nodesInProgress", new HashSet<VPath>()); VM.Context.Add("nodeInProgress", null); }
public void SetUp() { var codebase = Path.GetDirectoryName(GetType().Assembly.Location); var possiblePlugins = Directory.GetFiles(codebase, "*.dll"); possiblePlugins.ForEach(file => { try { var asmBytes = File.ReadAllBytes(file); AppDomain.CurrentDomain.Load(asmBytes); } catch {/*ignore load failures*/} }); var elfCode = ResourceHelper.ReadFromResource("Elf.Playground.Staple.Universal.elf"); _vm = new VirtualMachine(); _toyLog = new StringBuilder(); _vm.Context["ToyLog"] = _toyLog; _vm.Load(elfCode); _ep = _vm.CreateEntryPoint("Script", "Main"); }
public UnexpectedRtimplRuntimeException(VirtualMachine vm, string message, Exception innerException) : base(message, innerException) { VM = vm; }
public UnexpectedElfRuntimeException(VirtualMachine vm, string message) : base(message) { VM = vm; }
public ErroneousScriptRuntimeException(ElfExceptionType type, VirtualMachine vm, Exception innerException) : base(type, String.Empty, innerException) { VM = vm; Thread = VM.CurrentThread; }
private void ImplementCreateProperties(CompilationContext ctx, TypeBuilder t, IBranch root) { var relevantCumulations = ctx.ScheduledCumulations.ContainsKey(root) ? ctx.ScheduledCumulations[root].Where(co => co.Subject.IsFov() || co.Subject.Parent.IsFov()) : null; var special = ctx.CumulativeCompilation && relevantCumulations != null; if (special && relevantCumulations.IsEmpty()) return; var base_cp = t.BaseType.GetMethod("CreateProperties", BF.All); var cp = t.DefineOverride(base_cp); if (!base_cp.IsAbstract) cp.il().ldarg(0).call(base_cp); ctx.CPs[t] = cp; var svd = root.GetBranches().Where(b => b.Name == "_sourceValueDeclarations"); var formulae = root.GetBranches().Where(b => b.Name == "_formulaDeclarations"); var conditions = root.GetBranches().Where(b => b.Name == "_conditions"); var nodes = root.GetBranches().Except(svd).Except(formulae).Except(conditions); var svdAndFormulae = svd.Concat(formulae).SelectMany(b => b.GetBranches()).ToArray(); if (special) svdAndFormulae = svdAndFormulae.Where(b => relevantCumulations.Any(co => co.Subject == b || co.Subject.Parent == b)).ToArray(); var propGetCache = new Dictionary<VPath, MethodInfo>(); var fieldCache = new Dictionary<VPath, FieldBuilder>(); var nameCache = new HashSet<String>(); Action<IBranch, bool> ensureProperty = (b, external) => { if (propGetCache.ContainsKey(b.VPath)) { return; } else { var typeToken = b.GetValue("type").ContentString; var propType = typeToken.GetTypeFromToken(); var baseProp = t.BaseType.GetProperties(BF.All).SingleOrDefault( p => p.HasAttr<VPathAttribute>() && p.Attr<VPathAttribute>().VPath == b.VPath); var basePropOk = baseProp != null && baseProp.PropertyType == propType; String name; if (basePropOk) { name = baseProp.Name; } else { var desiredName = b.GetPropertyName(); name = desiredName; var i = 0; while (nameCache.Contains(name)) { name = desiredName + "~" + ++i; } nameCache.Add(b.GetPropertyName()); } if (external) { if (basePropOk) { propGetCache.Add(b.VPath, baseProp.GetGetMethod(true)); } else { var p_prop = t.DefineProperty(name, PropA.None, propType, new Type[0]); p_prop.SetCustomAttribute(new CustomAttributeBuilder( typeof(VPathAttribute).GetConstructor(typeof(String).MkArray()), b.VPath.ToString().MkArray())); var get = t.DefineMethod("get_" + name, MA.ProtectedProp, propType, new Type[0]); get.il() .ldarg(0) .callvirt(typeof(CompiledNode).GetProperty("Root").GetGetMethod()) .ldstr(b.VPath.ToString()) .newobj(typeof(VPath), typeof(String)) .callvirt(typeof(ICompiledNode).GetMethod("Eval")) .ret(); p_prop.SetGetMethod(get); propGetCache.Add(b.VPath, get); } } else { var p_prop = t.DefineProperty(name, PropA.None, propType, new Type[0]); p_prop.SetCustomAttribute(new CustomAttributeBuilder( typeof(VPathAttribute).GetConstructor(typeof(String).MkArray()), b.VPath.ToString().MkArray())); MethodBuilder get; if (basePropOk) { var baseGet = baseProp.GetGetMethod(true); get = t.DefineOverride(baseGet); p_prop.SetGetMethod(get); } else { get = t.DefineMethod("get_" + name, MA.PublicProp, propType, new Type[0]); p_prop.SetGetMethod(get); } propGetCache.Add(b.VPath, get); fieldCache.Add(b.VPath, t.DefineField("_" + name.ToLower(), propType, FA.Private)); } } }; Action<IBranch> updateCp = b => { var get = propGetCache[b.VPath]; cp.il() .ldarg(0) .callvirt(typeof(CompiledNode).GetProperty("Properties").GetGetMethod()) .ldarg(0) .ldstr(b.GetPropertyName()) .ldstr(b.VPath) .newobj(typeof(VPath), typeof(String)) .ldarg(0) .ldftn(get) .newobj(typeof(Func<IEsathObject>), typeof(Object), typeof(IntPtr)) .newobj(typeof(CompiledProperty), typeof(CompiledNode), typeof(String), typeof(VPath), typeof(Func<IEsathObject>)) .callvirt(typeof(CompiledPropertyCollection).GetMethod("Add")); }; // handle deleted flae and svds i.e. create CompiledNode.Eval-like crash if (special) { foreach (IBranch deleted in relevantCumulations.Where(co => co.Reason == EventReason.Remove).Select(co => co.Subject)) { ensureProperty(deleted, false); var get = (MethodBuilder)propGetCache[deleted.VPath]; get.il() .ldstr(String.Format("There's no compiled property at VPath '{0}'.", deleted.VPath)) .@throw(typeof(NotImplementedException), typeof(String)); updateCp(deleted); } } // define all properties in advance so that we can reference them when needed svdAndFormulae.ForEach(b => ensureProperty(b, false)); // implement defined properties foreach (var b in svdAndFormulae) { var typeToken = b.GetValue("type").ContentString; var propType = typeToken.GetTypeFromToken(); var f_prop = fieldCache[b.VPath]; var get = (MethodBuilder)propGetCache[b.VPath]; // if a formula has just been created (i.e. has null elfCode), then we just generate notimplemented stuff // todo. this is a particular case of graceful dealing with invalid elf code // a solid approach would also handle such stuff as: non-existing references, resolving to invalid methods // and i think something else (needs thorough checking) // note. when implementing that stuff, be sure to burn the failboat elf code + the failure reason right into the assembly code // so that one can analyze the formula by him/herself and find the reason of the failure if (b.IsFormula()) { var host = b.GetValue("elfCode"); var code = host == null ? null : host.ContentString; var elfCode = code == null ? null : code.ToCanonicalElf(); if (elfCode == null) { get.il().@throw(typeof(NotImplementedException)); updateCp(b); continue; } } Label cacheOk; LocalBuilder loc_cache, loc_vpath, loc_result; get.il() .ldarg(0) .callvirt(typeof(CompiledNode).GetProperty("Root").GetGetMethod()) .ldfld(typeof(CompiledScenario).GetField("CachedPropertiesRegistry", BF.All)) .def_local(typeof(HashSet<VPath>), out loc_cache) .stloc(loc_cache) .ldstr(b.VPath.ToString()) .newobj(typeof(VPath), typeof(String)) .def_local(typeof(VPath), out loc_vpath) .stloc(loc_vpath) .ldloc(loc_cache) .ldloc(loc_vpath) .callvirt(typeof(HashSet<VPath>).GetMethod("Contains")) .def_label(out cacheOk) .brtrue(cacheOk) // here svd and flae codegen will store the evaluation result .def_local(propType, out loc_result); if (b.IsSvd()) { Label isRuntime, stlocRuntime, isDesignTime, stlocDesignTime, coalesce; LocalBuilder runtime, designTime; get.il() // runtime -> value is stored in the repository .ldarg(0) .callvirt(typeof(CompiledNode).GetProperty("Repository", BF.All).GetGetMethod(true)) .def_label(out stlocRuntime) .def_label(out isRuntime) .def_local(typeof(String), out runtime) .brtrue_s(isRuntime) .ldnull() .br_s(stlocRuntime) .label(isRuntime) .ldarg(0) .callvirt(typeof(CompiledNode).GetProperty("Repository", BF.All).GetGetMethod(true)) .ldarg(0) .callvirt(typeof(CompiledNode).GetProperty("Scenario", BF.All).GetGetMethod(true)) .ldstr(b.VPath.ToString()) .newobj(typeof(VPath), typeof(String)) .callvirt(typeof(CachedVault).GetMethod("GetBranch")) .ldstr("repositoryValue") .newobj(typeof(VPath), typeof(String)) .callvirt(typeof(IBranch).GetMethod("GetValue")) .callvirt(typeof(IValue).GetProperty("ContentString").GetGetMethod()) .newobj(typeof(VPath), typeof(String)) .callvirt(typeof(CachedVault).GetMethod("GetValue")) .callvirt(typeof(IValue).GetProperty("ContentString").GetGetMethod()) .label(stlocRuntime) .stloc(runtime) // design time -> value is stored directly in the scenario next to the node .ldarg(0) .callvirt(typeof(CompiledNode).GetProperty("Repository", BF.All).GetGetMethod(true)) .def_label(out stlocDesignTime) .def_label(out isDesignTime) .def_local(typeof(String), out designTime) .brfalse_s(isDesignTime) .ldnull() .br_s(stlocDesignTime) .label(isDesignTime) .ldarg(0) .callvirt(typeof(CompiledNode).GetProperty("Scenario", BF.All).GetGetMethod(true)) .ldstr(b.VPath.ToString()) .newobj(typeof(VPath), typeof(String)) .callvirt(typeof(CachedVault).GetMethod("GetBranch")) .ldstr("valueForTesting") .newobj(typeof(VPath), typeof(String)) .callvirt(typeof(IBranch).GetMethod("GetValue")) .callvirt(typeof(IValue).GetProperty("ContentString").GetGetMethod()) .label(stlocDesignTime) .stloc(designTime) // prepare for convert .ldtoken(propType) .callvirt(typeof(Type).GetMethod("GetTypeFromHandle")) .callvirt(typeof(Elf.Helpers.ReflectionHelper).GetMethod("ElfDeserializer")) // coalesce designtime and runtime values .ldloc(designTime) .dup() .def_label(out coalesce) .brtrue_s(coalesce) .pop() .ldloc(runtime) .label(coalesce) // convert the string to esath object .callvirt(typeof(Func<String, IElfObject>).GetMethod("Invoke")) .stloc(loc_result); } else if (b.IsFormula()) { var host = b.GetValue("elfCode"); var code = host == null ? null : host.ContentString; var elfCode = code == null ? null : code.ToCanonicalElf(); elfCode.AssertNotNull(); // this is guaranteed by the check above (at the start of this method) Label retTarget; get.il().def_label(out retTarget); var vm = new VirtualMachine(); vm.Load(elfCode); var evis = ((NativeMethod)vm.Classes.Last().Methods.Single()).Body; Func<String, VPath> idToVpath = elfid => { try { return elfid.FromElfIdentifier(); } catch { return null; } }; Func<String, IEsathObject> elfStrToEsath = elfStr => { try { return elfStr.FromStorageString(); } catch { return null; } }; var il = get.il(); var evalStack = new Stack<Type>(); Type auxResultType = null; for (var j = 0; j < evis.Length; j++) { var evi = evis[j]; if (evi is Decl) { throw new NotSupportedException( String.Format("The 'decl' instructions is not supported.")); } else if (evi is Dup) { if (j < evis.Length - 1 && evis[j + 1] is PopRef) { // compile [dup, popref, pop] combo as simply [popref] // since so far constructs like a = b = c are not used } else { var dupe = evalStack.Peek(); evalStack.Push(dupe); il.dup(); } } else if (evi is Enter) { // do nothing } else if (evi is Invoke) { var invoke = (Invoke)evi; var args = new Type[invoke.Argc]; for (var i = invoke.Argc - 1; i >= 0; --i) args[i] = evalStack.Pop(); var resolved = DefaultInvocationResolver.Resolve( vm, invoke.Name, vm.Classes.Last(), args.Select(arg => vm.Classes.Single(c => c.Name == Elf.Helpers.ReflectionHelper.RtimplOf(arg))).ToArray()); if (resolved == null) { throw new NotSupportedException(String.Format( "The '{0}' instruction is not supported. " + "Cannot resolve invocation '{1}({2}).", invoke, invoke.Name, args.Select(arg => Elf.Helpers.ReflectionHelper.RtimplOf(arg)).StringJoin())); } else { if (!(resolved is ClrMethod)) { throw new NotSupportedException(String.Format( "The '{0}' instruction is not supported. " + "Invocation '{1}({2}) has been resolved to a native method '{3}'.", invoke, invoke.Name, args.Select(arg => Elf.Helpers.ReflectionHelper.RtimplOf(arg)).StringJoin(), resolved)); } else { var clrMethod = (MethodInfo)((ClrMethod)resolved).Rtimpl; if (clrMethod.ReturnType == typeof(void)) { throw new NotSupportedException(String.Format( "The '{0}' instruction is not supported. " + "Invocation '{1}({2}) has been resolved to a void-returning method '{3}'.", invoke, invoke.Name, args.Select(arg => Elf.Helpers.ReflectionHelper.RtimplOf(arg)).StringJoin(), clrMethod)); } else { il.callvirt(clrMethod); evalStack.Push(clrMethod.ReturnType); } } } } else if (evi is Jf) { throw new NotSupportedException( String.Format("The 'jf' instruction is not supported.")); } else if (evi is Jt) { throw new NotSupportedException( String.Format("The 'jt' instruction is not supported.")); } else if (evi is Elf.Core.Assembler.Label) { throw new NotSupportedException( String.Format("The 'label' instruction is not supported.")); } else if (evi is Leave) { // do nothing } else if (evi is Pop) { if (j > 0 && evis[j - 1] is PopRef) { // compile [dup, popref, pop] combo as simply [popref] // since so far constructs like a = b = c are not used } else { il.pop(); evalStack.Pop(); } } else if (evi is PopAll) { evalStack.ForEach(t1 => { evalStack.Pop(); il.pop(); }); } else if (evi is PopRef) { var popref = (PopRef)evi; var vpath = idToVpath(popref.Ref); if (vpath == null) { throw new NotSupportedException(String.Format( "The '{0}' instruction is not supported.", popref)); } else { if (vpath != b.VPath) { throw new NotSupportedException(String.Format( "The 'popref <vpath>' instruction is supported only " + "when vpath represents the current node. Current instruction " + "'{0}' is not supported", popref)); } else { auxResultType = evalStack.Pop(); // todo. ensure that nothing significant follows this instruction } } } else if (evi is PushRef) { var pushref = (PushRef)evi; var vpath = idToVpath(pushref.Ref); if (vpath == null) { throw new NotSupportedException(String.Format( "The '{0}' instruction is not supported.", pushref)); } else { if (!propGetCache.ContainsKey(vpath)) { var branch = Vault.GetBranch(vpath); if (branch == null) { throw new NotSupportedException(String.Format( "The 'pushref <vpath>' instruction is supported only " + "when vpath represents the svd or flae node. Current vpath '{0}' " + "doesn't reference any node in the scenario being compiled.", vpath)); } if (!branch.IsFov()) { throw new NotSupportedException(String.Format( "The 'pushref <vpath>' instruction is supported only " + "when vpath represents an svd or a flae node. Current branch " + "'{0}' at vpath '{1}' is not supported.", branch.Name, branch.VPath)); } ensureProperty(branch, true); } var prop = propGetCache[vpath]; il.ldarg(0).callvirt(prop); evalStack.Push(prop.ReturnType); } } else if (evi is PushVal) { var pushval = (PushVal)evi; if (!(pushval.Val is ElfStringLiteral) || (elfStrToEsath(((ElfStringLiteral)pushval.Val).Val)) == null) { throw new NotSupportedException(String.Format( "The 'pushval <val>' instruction is supported only " + "when val represents correctly encoded esath object. Current instruction " + "'{0}' is not supported", pushval)); } else { var storageString = ((ElfStringLiteral)pushval.Val).Val; var match = Regex.Match(storageString, @"^\[\[(?<token>.*?)\]\](?<content>.*)$"); match.Success.AssertTrue(); if (match.Success) { var token = match.Result("${token}"); var content = match.Result("${content}"); il.ldtoken(token.GetTypeFromToken()) .callvirt(typeof(Type).GetMethod("GetTypeFromHandle")) .callvirt(typeof(Elf.Helpers.ReflectionHelper).GetMethod("ElfDeserializer")) .ldstr(content) .callvirt(typeof(Func<String, IElfObject>).GetMethod("Invoke")); evalStack.Push(token.GetTypeFromToken()); } } } else if (evi is Ret) { evalStack.IsEmpty().AssertTrue(); il.br_s(retTarget); } else { throw new NotSupportedException(String.Format( "The '{0}' instruction is not supported.", evi)); } } if (auxResultType == propType) { il.label(retTarget) .stloc(loc_result); } else { LocalBuilder auxResult; var valPropGet = auxResultType.GetProperty("Val").GetGetMethod(); il.label(retTarget) .def_local(auxResultType, out auxResult) .stloc(auxResult) .ldloc(auxResult) .callvirt(valPropGet); if (typeof(ElfNumber).IsAssignableFrom(auxResultType) && propType == typeof(EsathPercent)) { // ldc_r8 is a must, since ldc_i4 performs integer multiplication // and fails stuff like 1.2 * 100 (the result will be 100) il.ldc_r8(100) .mul(); } il.convert(valPropGet.ReturnType, propType) .stloc(loc_result); } } else { throw new NotSupportedException( String.Format("Properties of type '{0}' are not supported", b)); } get.il() // the value is stored in a local after svd or flae codegen .ldarg(0) .ldloc(loc_result) .stfld(f_prop) .ldloc(loc_cache) .ldloc(loc_vpath) .callvirt(typeof(HashSet<VPath>).GetMethod("Add")) .pop() // if the value is cached, just execute this .label(cacheOk) .ldarg(0) .ldfld(f_prop) .ret(); // finally register the property just compiled in the CreateProperties updateCp(b); } cp.il().ret(); }
public ElfInteractive() { VM = new VirtualMachine(); VM.Context.Add("iactx", new PropertyBag()); }
public CocaContext(ColaNode cap) : base(cap) { VM = new VirtualMachine(); }
public void SetUp() { _vm = new VirtualMachine(); _toyLog = new StringBuilder(); _vm.Context["ToyLog"] = _toyLog; }
private void FillFxtypesList() { _fxTypeButton.DropDownItems.Clear(); var vm = new VirtualMachine(); var fx = vm.Classes.SelectMany(c => c.Methods.OfType<ClrMethod>()).Concat(vm.HelperMethods); var fxn = fx.Select(m => m.Rtimpl.RtimplOf()).Distinct().OrderBy(n => n); new []{"="}.Concat(fxn).ForEach(fxnn => { if (fxnn == "||" || fxnn == "&&" || fxnn == "!=" || fxnn == "==") return; var ddi = _fxTypeButton.DropDownItems.Add("pew"); ddi.Text = fxnn; ddi.Click += (o, e) => { var curr = _selectedSub.Children.Count(); var vargs = fxnn.GuessArgc() ?? curr; if (vargs < curr && !this.Confirm()) return; var head = _selectedSub.Children.Take(Math.Min(curr, vargs)); var tail = Enumerable.Range(0, Math.Max(0, vargs - curr)) .Select(i => new VariableExpression("?")).Cast<AstNode>(); var chi = head.Concat(tail).Cast<Expression>(); if (fxnn == "=") { var target = (VariableExpression)chi.ElementAt(0); var expr = chi.ElementAt(1); ReplaceSubThenSelectItAndRedraw(_selectedSub, new AssignmentExpression(target, expr)); } else { ReplaceSubThenSelectItAndRedraw(_selectedSub, new InvocationExpression(fxnn, chi)); } OnSelectFxPanel(); }; if (fxnn == "=") _fxEq = ddi; }); }