Esempio n. 1
0
		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);
		}
Esempio n. 2
0
        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;
 }
Esempio n. 6
0
        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();
        }
Esempio n. 7
0
 public ElfInteractive()
 {
     VM = new VirtualMachine();
     VM.Context.Add("iactx", new PropertyBag());
 }
Esempio n. 8
0
 public CocaContext(ColaNode cap) 
     : base(cap) 
 {
     VM = new VirtualMachine();
 }
Esempio n. 9
0
 public void SetUp()
 {
     _vm = new VirtualMachine();
     _toyLog = new StringBuilder();
     _vm.Context["ToyLog"] = _toyLog;
 }
Esempio n. 10
0
        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;
            });
        }