Exemplo n.º 1
0
 /// <summary>
 /// Constructs an incomplete phi.
 /// </summary>
 /// <param name="variableRef">The referenced variable.</param>
 /// <param name="phiBuilder">The phi builder.</param>
 public IncompletePhi(
     TVariable variableRef,
     PhiValue.Builder phiBuilder)
 {
     VariableRef = variableRef;
     PhiBuilder  = phiBuilder;
 }
Exemplo n.º 2
0
            //
            // Implements an adapted version of the SSA-construction algorithm from the paper:
            // Simple and Efficient Construction of Static Single Assignment Form
            //

            /// <summary>
            /// Returns the value of the given variable by asking the predecessors.
            /// This method recursively constructs required phi nodes to break cycles.
            /// </summary>
            /// <param name="var">The variable reference.</param>
            /// <param name="markerProvider">A provider of new marker values.</param>
            /// <returns>The value of the given variable.</returns>
            private Value GetValueRecursive(TVariable var, ref MarkerProvider markerProvider)
            {
                Debug.Assert(Node.NumPredecessors > 0);
                Value value;

                if (Node.NumPredecessors == 1 && IsSealed)
                {
                    var valueContainer = Parent[Node.Predecessors[0]];
                    value = valueContainer.GetValue(var, ref markerProvider);
                }
                else
                {
                    // Insert the actual phi param
                    var peekedValue = PeekValue(var, markerProvider.CreateMarker());
                    var phiBuilder  = Builder.CreatePhi(peekedValue.Type);
                    value = phiBuilder.PhiValue;

                    var incompletePhi = new IncompletePhi(var, phiBuilder);
                    if (IsSealed)
                    {
                        SetValue(var, value);
                        value = SetupPhiArguments(incompletePhi, ref markerProvider);
                    }
                    else
                    {
                        incompletePhis[var] = incompletePhi;
                    }
                }
                SetValue(var, value);
                return(value);
            }
Exemplo n.º 3
0
        /// <summary>
        /// Attempts to find a TNumber value for the TType given. If there is no error, but the TNumber reference
        /// given is still null after calling, then the TType is a TString (i.e. some arithmetic will work (+)).
        /// </summary>
        /// <param name="interpreter">The interpreter that the method is being called from.</param>
        /// <param name="number">The TNumber reference to assign the result to.</param>
        /// <param name="value">The TType to get a TNumber out of.</param>
        /// <returns>An exception if there was an error, otherwise null.</returns>
        private static TException AssignNumberValue(Interpreter interpreter, out TNumber number, TType value)
        {
            // Attempt to cast the TType 'value' argument to a TNumber. Failing that, check if it's a TString.
            // If the value is a TNumber or a TString, return null (i.e. no exception). If it's a TVariable then
            // work on the value of the TVariable, otherwise return an exception.


            number = value as TNumber;
            if ((number != null) || (value is TString))
            {
                return(null);
            }

            TVariable variable = value as TVariable;

            if (variable != null)
            {
                value  = variable.Value;
                number = value as TNumber;
                if ((number != null) || (value is TString))
                {
                    return(null);
                }
                return(new TException(interpreter, "Value of '" + variable.Identifier + "' is not a number",
                                      "it is of type '" + value.TypeName + "'"));
            }

            return(new TException(interpreter, "'" + value.ToCSString() + "' is not a number",
                                  "it is of type '" + value.TypeName + "'"));
        }
Exemplo n.º 4
0
        public void TestRegExReplace()
        {
            var tstr = new TVariable("")
            {
                regex_pattern = new Regex(@"(\S+)а,\s*(\S+)"),
                regex_replace = "район $2 города $1ы"
            };

            tstr.Set("Москва, ЦАО");
            Assert.AreEqual("район ЦАО города Москвы", tstr.value);


            var tnumeric = new TNumeric("")
            {
                regex_pattern = new Regex(@"(\d)(\d)(\d)"),
                regex_replace = "$2$3$1"
            };

            ((TVariable)tnumeric).Set("123");
            Assert.AreEqual(231f, tnumeric.value);


            var tdate = new TDate("")
            {
                regex_pattern = new Regex(@".* (\d{4}) года за (\d) месяц"),
                regex_replace = "1.$2.$1",
                format        = "d.M.yyyy",
                lastday       = true
            };

            tdate.Set("отчёт 2020 года за 2 месяц");
            Assert.AreEqual(new DateTime(2020, 2, 29), tdate.value);
        }
Exemplo n.º 5
0
 public AssertionObligation(APC pc, EdgeTag tag, TVariable cond, bool isAssume)
 {
     this.Apc       = pc;
     this.Tag       = tag;
     this.Condition = cond;
     this.IsAssume  = isAssume;
 }
Exemplo n.º 6
0
 /// <summary>
 /// Returns the value of the given variable.
 /// </summary>
 /// <param name="var">The variable reference.</param>
 /// <param name="markerProvider">A provider of new marker values.</param>
 /// <returns>The value of the given variable.</returns>
 public Value GetValue(TVariable var, ref MarkerProvider markerProvider)
 {
     if (values.TryGetValue(var, out Value value))
     {
         return(value);
     }
     return(GetValueRecursive(var, ref markerProvider));
 }
Exemplo n.º 7
0
 public TVariable(TVariable origin)
 {
     evaluated   = origin.evaluated;
     unevaluated = origin.unevaluated;
     ident       = origin.ident;
     name        = origin.name;
     scope       = origin.scope;
     status      = origin.status;
     persistence = origin.persistence;
     prev        = origin.prev;
 }
Exemplo n.º 8
0
        public void TestOverrided()
        {
            var var         = new TVariable("TEST");
            var var_same    = new TVariable("TEST");
            var var_another = new TVariable("TEST_NEW");

            Assert.IsTrue(var.Equals(var_same));
            Assert.IsFalse(var.Equals(var_another));
            Assert.IsFalse(var.Equals(null));
            Assert.AreEqual(var.GetHashCode(), var.name.GetHashCode());
        }
Exemplo n.º 9
0
        private protected void DefProperty(TVariable uvar, Project project)
        {
            if (uvar.status != ValStatus.Started)
            {
                SetGlobalProperty(project, uvar.ident, GetUVarValue(uvar.ident));
                return;
            }

            if (uvar.prev != null && ((TVariable)uvar.prev).unevaluated != null)
            {
                TVariable prev = (TVariable)uvar.prev;
                SetGlobalProperty(project, uvar.ident, prev.evaluated ?? prev.unevaluated);
            }
        }
Exemplo n.º 10
0
        public void TestAction()
        {
            TVariable  test = new TVariable("test");
            TInterrupt stop = new TInterrupt(TInterrupt.Action.STOP_LOOP);

            TCondition cond = new TCondition
            {
                x      = 15,
                mustBe = "25"
            };

            cond.onFalse.Add(test);
            cond.onTrue.Add(stop);
        }
Exemplo n.º 11
0
 /// <summary>
 /// Peeks a value recursively. This method only retrieves a value
 /// from a predecessor but does not build any phi nodes.
 /// </summary>
 /// <param name="var">The variable reference.</param>
 /// <param name="marker">The current marker to break cycles.</param>
 /// <returns></returns>
 private Value PeekValue(TVariable var, int marker)
 {
     if (!IsProcessed || !Mark(marker))
     {
         return(null);
     }
     if (values.TryGetValue(var, out Value value))
     {
         return(value);
     }
     foreach (var predecessor in Block.Predecessors)
     {
         var   valueContainer = Parent[predecessor];
         Value result;
         if ((result = valueContainer.PeekValue(var, marker)) != null)
         {
             return(result);
         }
     }
     return(null);
 }
Exemplo n.º 12
0
        public static Dictionary <string, TVariable> getVariables()
        {
            Dictionary <string, TVariable> data = new Dictionary <string, TVariable>();

            var tvariable = new TVariable("FIO");

            tvariable.Set("Ivanov Ivan Ivanovich");
            data.Add(tvariable.name, tvariable);

            var tnumeric = new TNumeric("SUMMA");

            tnumeric.Set(12.3456f);
            data.Add(tnumeric.name, tnumeric);

            var tdate = new TDate("DATE");

            tdate.Set("22.11.2001");
            data.Add(tdate.name, tdate);

            return(data);
        }
Exemplo n.º 13
0
        public void TestRegEx()
        {
            var tstr = new TVariable("")
            {
                regex_pattern = new Regex("(\\S+) округа города (\\S+)"),
                regex_group   = 2
            };

            tstr.Set("Центрального округа города Москвы");
            Assert.AreEqual("Москвы", tstr.value);

            tstr.Set("Не подходящий условию текст");
            Assert.AreEqual("", tstr.value);

            tstr.regex_group = 4;
            tstr.Set("Центрального округа города Москвы");
            Assert.AreEqual("", tstr.value);


            var tnumeric = new TNumeric("")
            {
                regex_pattern = new Regex("Итого (\\S+)р.")
            };

            ((TVariable)tnumeric).Set("Итого 800,45р. начислено");
            Assert.AreEqual(800.45f, tnumeric.value);


            var tdate = new TDate("")
            {
                regex_pattern = new Regex("основан (.*) год"),
                format        = "dd MMMM yyyy"
            };

            ((TVariable)tdate).Set("Санкт-Петербург был основан 27 мая 1703 года");
            Assert.AreEqual(new DateTime(1703, 05, 27), tdate.value);
        }
Exemplo n.º 14
0
            //
            // Implements an adapted version of the SSA-construction algorithm from the
            // paper: Simple and Efficient Construction of Static Single Assignment Form
            //

            /// <summary>
            /// Returns the value of the given variable by asking the predecessors.
            /// This method recursively constructs required phi nodes to break cycles.
            /// </summary>
            /// <param name="var">The variable reference.</param>
            /// <param name="markerProvider">A provider of new marker values.</param>
            /// <returns>The value of the given variable.</returns>
            private Value GetValueRecursive(
                TVariable var,
                ref MarkerProvider markerProvider)
            {
                Block.Assert(Block.Predecessors.Length > 0);
                Value value;

                if (Block.Predecessors.Length == 1 && IsSealed)
                {
                    var valueContainer = Parent[Block.Predecessors[0]];
                    value = valueContainer.GetValue(var, ref markerProvider);
                }
                else
                {
                    // Insert the actual phi value
                    var peekedValue = PeekValue(var, markerProvider.CreateMarker());
                    // Let the phi point to the beginning of the current block
                    var phiBuilder = Builder.CreatePhi(
                        blockBuilder.BasicBlock.Location,
                        peekedValue.Type);
                    value = phiBuilder.PhiValue;

                    var incompletePhi = new IncompletePhi(var, phiBuilder);
                    if (IsSealed)
                    {
                        SetValue(var, value);
                        value = SetupPhiArguments(incompletePhi, ref markerProvider);
                    }
                    else
                    {
                        incompletePhis[var] = incompletePhi;
                    }
                }
                SetValue(var, value);
                return(value);
            }
 /// <summary>
 ///    Indexer used to retrieve the address where a variable has been injected, through a call
 ///    to <see cref="Injector{TMemoryAlterationSetID, TCodeCave, TVariable}"/>.GetInjectedVariableAddress().
 /// </summary>
 /// <param name="variableID">The identifier of the variable whose injected address is to be retrieved.</param>
 /// <returns>Returns the address where the given variable has been injected.</returns>
 public IntPtr this[TVariable variableID]
 {
     get { return(m_injector.GetInjectedVariableAddress(variableID).Address); }
     internal set { this.SendPropertyChangedNotification(DEFAULT_INDEXER_PROPERTY_NAME); }
 }
Exemplo n.º 16
0
        /// <summary>
        /// Does an equality comparison of one TType with another.
        /// </summary>
        /// <param name="interpreter">The interpreter that the method is being called from.</param>
        /// <param name="a">The left hand operand of the comparison.</param>
        /// <param name="b">The right hand operand of the comparison.</param>
        /// <param name="strict">
        /// Whether the equality should be approximate or not. Give true for exact equality comparisons, and false for
        /// approximate equality comparisons of TNumbers.
        /// </param>
        /// <returns>
        /// An TBoolean containing the result of the comparison. Returns a TException or null when there is an error.
        /// </returns>
        public static TType Equal(Interpreter interpreter, TType a, TType b, bool strict)
        {
            // If arguments are TVariable, get their value. The values of the TVariable need to be compared,
            // not the TVariable objects themselves
            TVariable variable = a as TVariable;

            if (variable != null)
            {
                a = variable.Value;
            }
            variable = b as TVariable;
            if (variable != null)
            {
                b = variable.Value;
            }

            // Make sure that each operand is of the same type. TNumbers are an exception; any TNumber derivative can
            // be compared with any other TNumber derivative
            if ((a.TypeName != b.TypeName) && !((a is TNumber) && (b is TNumber)))
            {
                return(new TException(interpreter,
                                      "Type '" + a.TypeName + "' cannot be compared with type '" + b.TypeName + "'"));
            }

            // Using 'as' syntax instead of '()' for casting, because it looks cleaner. The result of the 'as' will not
            // return null because we've done the necessary check beforehand (i.e. if 'a' is a TNumber, then 'b' must
            // also be a TNumber)
            if (a is TNumber)
            {
                bool result;
                if (strict)
                {
                    result =
                        (System.Math.Abs((a as TNumber).TRealValue - (b as TNumber).TRealValue) < 0.000001);
                }
                else
                {
                    double aVal = (a as TNumber).TRealValue, bVal = (b as TNumber).TRealValue;
                    if ((System.Math.Round(aVal) == bVal) || (System.Math.Round(bVal) == aVal))
                    {
                        result = true;
                    }
                    else
                    {
                        result = (System.Math.Abs(aVal - bVal) < 0.5);
                    }
                }
                return(new TBoolean(result));
            }
            else if (a is TBoolean)
            {
                return(new TBoolean((a as TBoolean).Value == (b as TBoolean).Value));
            }
            else if (a is TString)
            {
                return(new TBoolean((a as TString).Value == (b as TString).Value));
            }
            else if (a is TVariable) // i.e. if argument 'a' is a reference
            {
                return(new TBoolean(a == b));
            }
            else if (a is TFunction)
            {
                TFunction funcA = a as TFunction, funcB = b as TFunction;
                return(new TBoolean(
                           (funcA.HardCodedFunction == funcB.HardCodedFunction) &&
                           (funcA.CustomFunction == funcB.CustomFunction) &&
                           (funcA.Block == funcB.Block)));
            }
            else if (a is TNil)
            {
                return(new TBoolean(b is TNil));
            }

            return(null);
        }
Exemplo n.º 17
0
            /// <summary>
            /// Takes two TNumbers or two TStrings (or up to two TVariables containing TNumbers or TStrings) and
            /// adds them together.
            /// </summary>
            /// <param name="interpreter">The interpreter that the method is being called from.</param>
            /// <param name="a">The left hand operand of the operation.</param>
            /// <param name="b">The right hand operand of the operation.</param>
            /// <returns>
            /// The TType resulting from the operation. An MExcpetion or null is returned when there is an error.
            /// </returns>
            public static TType Add(Interpreter interpreter, TType a, TType b)
            {
                // Convert arguments 'a' and 'b' into either a TNumber or a TString
                TNumber numberA, numberB;
                TString strA = null, strB = null;

                TException exception = AssignNumberValue(interpreter, out numberA, a);

                if (exception != null)
                {
                    return(exception);
                }

                if (numberA == null)
                {
                    // No errors yet, and numberA is null, so argument 'a' could be a TString or a TVariable
                    // containing a TString
                    strA = a as TString;
                    if (strA == null)
                    {
                        TVariable variable = a as TVariable;
                        if (variable != null)
                        {
                            strA = variable.Value as TString;
                        }
                    }
                }
                if ((numberA == null) && (strA == null)) // Nothing useful, return a TException
                {
                    return(new TException(interpreter, "Value is not a number or string"));
                }


                // Same procedure for argument 'b'
                exception = AssignNumberValue(interpreter, out numberB, b);
                if (exception != null)
                {
                    return(exception);
                }
                if (numberB == null)
                {
                    strB = b as TString;
                    if (strB == null)
                    {
                        TVariable variable = b as TVariable;
                        if (variable != null)
                        {
                            strB = variable.Value as TString;
                        }
                    }
                }
                if ((numberB == null) && (strB == null))
                {
                    return(new TException(interpreter, "Value is not a number or string"));
                }

                // Attempt addition if both operands are the same type, otherwise return a TException
                if ((numberB == null) && (strA == null))
                {
                    return(new TException(interpreter, "Attempted addition of a string to a number"));
                }
                else if ((numberA == null) && (strB == null))
                {
                    return(new TException(interpreter, "Attempted addition of a number to a string"));
                }
                else if ((numberA == null) && (numberB == null))
                {
                    return(new TString(strA.Value + strB.Value));
                }
                else
                {
                    //The left hand operand decides the type of the returned value
                    switch (numberA.TypeName)
                    {
                    case TType.T_INTEGER_TYPENAME:
                    {
                        // If the other operand is a fraction, treat this integer as a fraction (i.e. value/1)
                        TFraction fraction = numberB as TFraction;
                        if (fraction != null)
                        {
                            // Copy the right hand fraction and add the left hand integer to it
                            fraction = new TFraction(fraction.Numerator, fraction.Denominator);
                            fraction.Add(numberA.TIntegerValue, 1);
                            return(fraction);
                        }
                        return(new TInteger(numberA.TIntegerValue + numberB.TIntegerValue));
                    }

                    case TType.T_REAL_TYPENAME:
                        return(new TReal(numberA.TRealValue + numberB.TRealValue));

                    case TType.T_FRACTION_TYPENAME:
                    {
                        // Create a copy of the left hand fraction
                        TFraction fraction = numberA as TFraction;
                        fraction = new TFraction(fraction.Numerator, fraction.Denominator);

                        // Convert the right hand operand to a fraction
                        long      numerator, denominator;
                        TFraction otherFraction = numberB as TFraction;
                        if (otherFraction != null)         // If it's a fraction, simply copy the values
                        {
                            numerator   = otherFraction.Numerator;
                            denominator = otherFraction.Denominator;
                        }
                        else
                        {
                            // Check if it's a TInteger first. It might not need to use DoubleToFraction
                            if (numberB is TInteger)
                            {
                                numerator   = numberB.TIntegerValue;
                                denominator = 1;
                            }
                            else
                            {
                                Operations.Misc.DoubleToFraction(numberB.TRealValue, out numerator,
                                                                 out denominator);
                            }
                        }

                        fraction.Add(numerator, denominator);
                        return(fraction);
                    }
                    }
                }

                return(null);
            }
Exemplo n.º 18
0
 /// <summary>
 /// Removes the value of the given variable.
 /// </summary>
 /// <param name="var">The variable reference.</param>
 public void RemoveValue(TVariable var) => values.Remove(var);
Exemplo n.º 19
0
 protected void SetVar(TVariable var, object value)
 {
     exception_var = var;
     var.Set(value);
     stepScope[var.name] = var;
 }
Exemplo n.º 20
0
 /// <summary>
 /// Sets the given variable to the given value.
 /// </summary>
 /// <param name="var">The variable reference.</param>
 /// <param name="value">The value to set.</param>
 public void SetValue(TVariable var, Value value) =>
 values[var] = value;
Exemplo n.º 21
0
 /// <summary>
 /// Returns the value of the given variable.
 /// </summary>
 /// <param name="var">The variable reference.</param>
 /// <param name="markerProvider">A provider of new marker values.</param>
 /// <returns>The value of the given variable.</returns>
 public Value GetValue(TVariable var, ref MarkerProvider markerProvider) =>
 values.TryGetValue(var, out Value value)
     ? value
     : GetValueRecursive(var, ref markerProvider);
Exemplo n.º 22
0
 protected void AddVar(IDictionary <string, TVariable> dictionary, TVariable variable)
 {
     dictionary.Add(variable.name, variable);
 }
Exemplo n.º 23
0
        protected TVariable getVar(XElement xml, bool dynamic)
        {
            var name  = xml.Attribute("name")?.Value ?? throw new NullReferenceException("Variable attribute 'name' can't be null!");
            var ctype = xml.Attribute("type")?.Value ?? "string";

            TVariable variable;

            switch (ctype)
            {
            case "numeric":
                variable = new TNumeric(name);
                break;

            case "date":
                variable = new TDate(name);
                break;

            default:
                variable = new TVariable(name);
                break;
            }

            variable.x = Int32.Parse(xml.Attribute("X")?.Value ?? throw new NullReferenceException("Variable attribute 'X' can't be null!"));
            if (!dynamic)
            {
                variable.y = Int32.Parse(xml.Attribute("Y")?.Value ?? throw new NullReferenceException("Variable attribute 'Y' can't be null!"));
            }
            variable.dynamic = dynamic;

            if (variable is TNumeric tnumeric)
            {
                var function = xml.Attribute("function");

                if (function != null)
                {
                    tnumeric.function = TNumeric.getFuncByString(function.Value);
                }
            }

            if (variable is TDate tdate)
            {
                var lastday  = xml.Attribute("lastday");
                var language = xml.Attribute("language");
                var format   = xml.Attribute("format");

                if (lastday != null)
                {
                    tdate.lastday = Boolean.Parse(lastday.Value);
                }
                if (language != null)
                {
                    tdate.language = language.Value;
                }
                if (format != null)
                {
                    tdate.format = format.Value;
                }
            }

            var regex_pattern = xml.Attribute("regex_pattern");

            if (regex_pattern != null)
            {
                variable.regex_pattern = new Regex(regex_pattern.Value, RegexOptions.Compiled);

                var regex_group = xml.Attribute("regex_group");
                variable.regex_group = int.Parse(regex_group?.Value ?? "1");
            }
            return(variable);
        }
Exemplo n.º 24
0
 public AssertionObligation(APC pc, EdgeTag tag, TVariable cond)
     : this(pc, tag, cond, false)
 {
 }
 /// <summary>Indexer used to retrieve the size of a variable, through a call to <see cref="Injector{TMemoryAlterationSetID, TCodeCave, TVariable}"/>.GetVariableSize().</summary>
 /// <param name="variableID">The identifier of the variable whose size is to be retrieved.</param>
 /// <returns>Returns the size of the given variable.</returns>
 public int this[TVariable variableID]
 {
     get { return(m_injector.GetVariableSize(variableID)); }
     internal set { this.SendPropertyChangedNotification(DEFAULT_INDEXER_PROPERTY_NAME); }
 }
Exemplo n.º 26
0
        protected void __IterateRecords(Worksheet worksheet, Action <Dictionary <string, TVariable> > callback, Action <int> guiCallback = null)
        {
            int begin = startY;
            int end   = startY + buffer;

            var maxY = worksheet.UsedRange.Rows.Count + 1;

            bool EOF = false;

            Stopwatch watch = Stopwatch.StartNew();

            stepScope.Clear();
            foreach (var var in staticVars.Values)
            {
                SetVar(var, worksheet.Cells[var.y, var.x].Value);
            }
            watch.Stop();
            Logger.debug("Заполнение массива локальных переменных: " + watch.ElapsedMilliseconds);

            int  i          = 0;
            bool skipRecord = false;
            bool stopLoop   = false;

            object[,] tmp = null;

            var engine = new Jint.Engine();

            engine.SetValue("skipRecord", (System.Action)(() => skipRecord = true));
            engine.SetValue("stopLoop", (System.Action)(() => stopLoop     = true));
            engine.SetValue("throwError", (Action <string>)((message) =>
                                                            throw new ApplicationException($"JS ошибка: {message}")));
            engine.SetValue("log", (Action <object>)Logger.info);
            engine.SetValue("info", (Action <string>)((msg) => guiLogger?.Invoke(DataLog.LogImage.INFO, msg)));
            engine.SetValue("warn", (Action <string>)((msg) => guiLogger?.Invoke(DataLog.LogImage.WARNING, msg)));
            engine.SetValue("getRow", (Func <object>)(() => tmp?.GetRow(i, 1)));
            var getCache = new Dictionary <string, object>();

            engine.SetValue("cell", (Func <int, int, object>)((y, x) =>
            {
                bool hasValue = getCache.TryGetValue($"{y}/{x}", out var obj);
                if (hasValue)
                {
                    return(obj);
                }
                obj = worksheet.Cells[y, x]?.Value;
                getCache[$"{y}/{x}"] = obj;
                return(obj);
            }));
            engine.SetValue("set", (Func <string, object, bool>)((name, value) =>
            {
                TVariable tVar = null;
                bool hasValue  = false;
                if (!hasValue)
                {
                    hasValue = dynamicVars.TryGetValue(name, out tVar);
                }
                if (!hasValue)
                {
                    hasValue = staticVars.TryGetValue(name, out tVar);
                }
                if (hasValue)
                {
                    SetVar(tVar, value);
                }
                return(hasValue);
            }));
            engine.SetValue("get", (Func <string, object>)((name) =>
            {
                TVariable tVar = null;
                bool hasValue  = false;
                if (!hasValue)
                {
                    hasValue = dynamicVars.TryGetValue(name, out tVar);
                }
                if (!hasValue)
                {
                    hasValue = staticVars.TryGetValue(name, out tVar);
                }
                if (hasValue)
                {
                    return(tVar.value);
                }
                return(null);
            }));

            JsValue scriptEveryRow = null;
            JsValue scriptBefore   = null;
            JsValue scriptAfter    = null;

            if (jScript != null)
            {
                var jVal = engine.Execute(JSHelper.decodeXMLEntities(jScript)).GetCompletionValue();
                if (jVal.IsObject())
                {
                    var jObj = jVal.AsObject();
                    scriptEveryRow = jObj.getOrDefault("row", null);
                    scriptAfter    = jObj.getOrDefault("after", null);
                    scriptBefore   = jObj.getOrDefault("before", null);
                }
            }

            Stopwatch watchTotal = Stopwatch.StartNew();

            scriptBefore?.Invoke();
            while (!EOF)
            {
                var range_start = worksheet.Cells[begin, 1];
                var range_end   = worksheet.Cells[end, endX];
                var range       = worksheet.Range[range_start, range_end];
                tmp = range.Value;

                watch = Stopwatch.StartNew();
                for (i = 1; i <= buffer; i++)
                {
                    skipRecord = false;
                    stopLoop   = false;
                    total++;
                    foreach (TCondition cond in conditions)
                    {
                        var  cellValue = tmp[i, cond.x]?.ToString() ?? "";
                        bool equal     = false;
                        if (cond.isRegex)
                        {
                            equal = Regex.Match(cellValue, cond.mustBe).Success;
                        }
                        else
                        {
                            equal = cellValue == cond.mustBe;
                        }
                        if (equal)
                        {
                            foreach (TAction item in cond.onTrue)
                            {
                                switch (item)
                                {
                                case TInterrupt tinter:
                                    switch (tinter.action)
                                    {
                                    case TInterrupt.Action.SKIP_RECORD:
                                        Logger.tracer($"Пропуск записи по условию: значение в ячейке x={cond.x} равно {cond.mustBe}");
                                        skipRecord = true;
                                        break;

                                    case TInterrupt.Action.STOP_LOOP:
                                        Logger.tracer($"Выход из цикла по условию: значение в ячейке x={cond.x} равно {cond.mustBe}");
                                        stopLoop = true;
                                        break;
                                    }
                                    continue;

                                case TVariable var:
                                    SetVar(var, tmp[i, var.x]);
                                    break;
                                }
                            }
                        }
                        else
                        {
                            foreach (TAction item in cond.onFalse)
                            {
                                switch (item)
                                {
                                case TInterrupt tinter:
                                    switch (tinter.action)
                                    {
                                    case TInterrupt.Action.SKIP_RECORD:
                                        Logger.tracer($"Пропуск записи по условию: значение в ячейке x={cond.x} равно {cond.mustBe}");
                                        skipRecord = true;
                                        break;

                                    case TInterrupt.Action.STOP_LOOP:
                                        Logger.tracer($"Выход из цикла по условию: значение в ячейке x={cond.x} равно {cond.mustBe}");
                                        stopLoop = true;
                                        break;
                                    }
                                    continue;

                                case TVariable var:
                                    SetVar(var, tmp[i, var.x]);
                                    break;
                                }
                            }
                        }
                    }

                    if (total > maxY - startY + 1)
                    {
                        Logger.warn("Попытка выйти за пределы документа, выход из цикла");
                        EOF = true;
                        break;
                    }

                    if (stopLoop)
                    {
                        Logger.debug("Выход из цикла по условию");
                        EOF = true;
                        break;
                    }
                    if (skipRecord)
                    {
                        continue;
                    }
                    foreach (var var in dynamicVars.Values)
                    {
                        SetVar(var, tmp[i, var.x]);
                    }

                    scriptEveryRow?.Invoke();
                    if (skipRecord)
                    {
                        continue;
                    }
                    if (stopLoop)
                    {
                        Logger.debug("Выход из цикла вызван JS хуком row");
                        EOF = true;
                        break;
                    }

                    callback(stepScope);
                }
                watch.Stop();
                Logger.debug($"Сегмент в {buffer} элементов (с {begin} по {end}) обработан за {watch.ElapsedMilliseconds} мс");
                guiCallback?.Invoke(total);

                begin += buffer;
                end   += buffer;
            }
            watchTotal.Stop();
            Logger.debug("Времени всего: " + watchTotal.ElapsedMilliseconds);
            Logger.debug("Строк обработано: " + total);
            Logger.debug("Размер буффера:" + buffer);
            scriptAfter?.Invoke();
        }