예제 #1
0
 public void CallExpression(ExpressionSymbol expressionid)
 {
     if (m_Anim != null)
     {
         m_Anim.SetBool(m_ExpressionArray[(int)expressionid].name, true);
     }
 }
예제 #2
0
        public void Create_GlobalTable_TestInput()
        {
            GlobalTable globalTable = new GlobalTable();

            TextInputSymbol textInputSymbol = new TextInputSymbol(new ErrorReport(), "@authorName", "Author Name", "Description", "Rob Blake", true);

            List <BaseFunction> functionArguments = new List <BaseFunction> {
                new VariableFunction(new FuncInfo("stub", 1, 1), globalTable, "@authorName")
            };
            ExpressionSymbol expressionSymbol = new ExpressionSymbol(new ErrorReport(), "@upperAuthorName", "Upper Author Name", "Description", true, true, new UpperCaseFunction(new FuncInfo("stub", 1, 1), globalTable, functionArguments));

            globalTable.AddSymbol(textInputSymbol);
            globalTable.AddSymbol(expressionSymbol);

            string textOutput_A = globalTable.GetValueOfSymbol("@authorName");
            string exprOutput_A = globalTable.GetValueOfSymbol("@upperAuthorName");

            globalTable.Input("@authorName", "John Doe");

            string textOutput_B = globalTable.GetValueOfSymbol("@authorName");
            string exprOutput_B = globalTable.GetValueOfSymbol("@upperAuthorName");

            Assert.AreEqual("Rob Blake", textOutput_A);
            Assert.AreEqual("ROB BLAKE", exprOutput_A);

            Assert.AreEqual("John Doe", textOutput_B);
            Assert.AreEqual("JOHN DOE", exprOutput_B);
        }
예제 #3
0
        public void IfDecissionFunction_GivenSelectedOption_ReturnsCorrectValue()
        {
            // BEFORE REMOVING THIS TEST METHOD YOU NEED TO WRITE TESTS FOR ALL ITS POSSIBILITIES IN THE NEW STYLE BELOW

            GlobalTable globalTable = new GlobalTable();

            OptionInputSymbol optionInputSymbol = new OptionInputSymbol(new ErrorReport(), "@databaseOptions", "Database Options", "Description", "ADVWORKS");

            optionInputSymbol.AddOption("ADVWORKS", "Adventure Works Database");
            optionInputSymbol.AddOption("PUBBOOKS", "Published Books Database");

            IfDecissionFunction decissionFunc = new IfDecissionFunction(new FuncInfo("stub", 1, 1), globalTable, "@databaseOptions");

            decissionFunc.AddFunction("ADVWORKS", new TextFunction(new FuncInfo("stub", 1, 1), globalTable, "You chose DM"));
            decissionFunc.AddFunction("PUBBOOKS", new TextFunction(new FuncInfo("stub", 1, 1), globalTable, "You chose Published Books Database"));

            ExpressionSymbol expressionSymbol = new ExpressionSymbol(new ErrorReport(), "@selectedDatabase", "Selected Database", "Description", true, true, decissionFunc);

            globalTable.AddSymbol(optionInputSymbol);
            globalTable.AddSymbol(expressionSymbol);

            Assert.AreEqual("ADVWORKS", globalTable.GetValueOfSymbol("@databaseOptions"));
            Assert.AreEqual("You chose DM", globalTable.GetValueOfSymbol("@selectedDatabase"));

            globalTable.Input("@databaseOptions", "1");

            Assert.IsTrue(expressionSymbol.IsPlaceholder);
            Assert.IsTrue(expressionSymbol.IsVisibleToEditor);

            Assert.AreEqual("PUBBOOKS", globalTable.GetValueOfSymbol("@databaseOptions"));
            Assert.AreEqual("You chose Published Books Database", globalTable.GetValueOfSymbol("@selectedDatabase"));
        }
예제 #4
0
    internal static string GenerateSymbolExpression(
        Dictionary <string, ExpressionSymbol> symbolTable,
        Dictionary <string, string> reverseSymbolTable,
        string expression,
        bool isFunction)
    {
        if (reverseSymbolTable.TryGetValue(
                expression,
                out var itemName))
        {
            return(itemName);
        }

        itemName = $"item{symbolTable.Count.ToString(CultureInfo.InvariantCulture).PadLeft(4, '0')}";
        ExpressionSymbol symb = isFunction
            ? ExpressionSymbol.GenerateFunctionCall(
            itemName,
            expression)
            : ExpressionSymbol.GenerateSymbol(
            itemName,
            expression);

        symbolTable.Add(
            itemName,
            symb);
        reverseSymbolTable.Add(
            symb.Expression,
            itemName);

        return(itemName);
    }
예제 #5
0
 public void ValidateSymbol(ExpressionSymbol <T> sequenceSymbol, ISequenceSymbol nextSymbol)
 {
     if (!this.allowedSymbolsAfterExpression.Contains(nextSymbol?.GetType()))
     {
         throw new ParseException(
                   ValidationErrorResources.SequenceOfSymbols_AfterExpressionThereMustBeLogicalOperatorOrClosingParenthesis,
                   sequenceSymbol.QueryPartIndex);
     }
 }
예제 #6
0
        public void CamelCaseFunction_InputPascalCase_OutputsCamelCase_1()
        {
            // BEFORE REMOVING THIS TEST METHOD YOU NEED TO WRITE TESTS FOR ALL ITS POSSIBILITIES IN THE NEW STYLE BELOW
            GlobalTable globalTable = new GlobalTable();

            List <BaseFunction> functionArguments = new List <BaseFunction>();

            functionArguments.Add(new TextFunction(new FuncInfo("stub", 1, 1), globalTable, "LiteralText"));

            ExpressionSymbol expressionSymbol = new ExpressionSymbol(new ErrorReport(), "@classInstance", "Class Instance", "Description", true, true, new CamelCaseFunction(new FuncInfo("stub", 1, 1), globalTable, functionArguments));

            Assert.AreEqual("@classInstance", expressionSymbol.Symbol);
            Assert.AreEqual("@{classInstance}", expressionSymbol.Placeholder);
            Assert.AreEqual("Class Instance", expressionSymbol.Title);

            Assert.AreEqual("literalText", expressionSymbol.Value);
        }
예제 #7
0
        public void RemovePunctuationFunction_InputPunctuatedText_OutputPunctuationRemoved_1()
        {
            // BEFORE REMOVING THIS TEST METHOD YOU NEED TO WRITE TESTS FOR ALL ITS POSSIBILITIES IN THE NEW STYLE BELOW
            GlobalTable globalTable = new GlobalTable();

            List <BaseFunction> functionArguments = new List <BaseFunction>();

            functionArguments.Add(new TextFunction(new FuncInfo("stub", 1, 1), globalTable, "LITERAL?!..TEXT."));

            ExpressionSymbol expressionSymbol = new ExpressionSymbol(new ErrorReport(), "@removePunctuation", "Remove Punctuation Function", "Remove Punctuation Function", true, true, new RemovePunctuationFunction(new FuncInfo("stub", 1, 1), globalTable, functionArguments));

            Assert.AreEqual("@removePunctuation", expressionSymbol.Symbol);
            Assert.AreEqual("@{removePunctuation}", expressionSymbol.Placeholder);
            Assert.AreEqual("Remove Punctuation Function", expressionSymbol.Title);

            Assert.AreEqual("LITERALTEXT", expressionSymbol.Value);
        }
예제 #8
0
        public void ProperCaseFunction_InputUpperCase_OutputsProperCase_1()
        {
            // BEFORE REMOVING THIS TEST METHOD YOU NEED TO WRITE TESTS FOR ALL ITS POSSIBILITIES IN THE NEW STYLE BELOW

            GlobalTable globalTable = new GlobalTable();

            List <BaseFunction> functionArguments = new List <BaseFunction>();

            functionArguments.Add(new TextFunction(new FuncInfo("stub", 1, 1), globalTable, "LITERAL TEXT"));

            ExpressionSymbol expressionSymbol = new ExpressionSymbol(new ErrorReport(), "@toProperCase", "Proper Case Function", "Proper Case Function", true, true, new ProperCaseFunction(new FuncInfo("stub", 1, 1), globalTable, functionArguments));

            Assert.AreEqual("@toProperCase", expressionSymbol.Symbol);
            Assert.AreEqual("@{toProperCase}", expressionSymbol.Placeholder);
            Assert.AreEqual("Proper Case Function", expressionSymbol.Title);

            Assert.AreEqual("Literal Text", expressionSymbol.Value);
        }
예제 #9
0
        public void ConcatenateFunction_Input3Strings_ConcatenatesToSingleString_1()
        {
            // BEFORE REMOVING THIS TEST METHOD YOU NEED TO WRITE TESTS FOR ALL ITS POSSIBILITIES IN THE NEW STYLE BELOW
            GlobalTable globalTable = new GlobalTable();

            ConcatenateFunction concatFunc = new ConcatenateFunction(new FuncInfo("stub", 1, 1), globalTable);

            concatFunc.AddFunction(new TextFunction(new FuncInfo("stub", 1, 1), globalTable, "hello"));
            concatFunc.AddFunction(new TextFunction(new FuncInfo("stub", 1, 1), globalTable, " "));
            concatFunc.AddFunction(new TextFunction(new FuncInfo("stub", 1, 1), globalTable, "world"));

            ExpressionSymbol expressionSymbol = new ExpressionSymbol(new ErrorReport(), "@concat", "Concatenated String", "Description", true, true, concatFunc);

            Assert.AreEqual("@concat", expressionSymbol.Symbol);
            Assert.AreEqual("@{concat}", expressionSymbol.Placeholder);
            Assert.AreEqual("Concatenated String", expressionSymbol.Title);

            Assert.AreEqual("hello world", expressionSymbol.Value);
        }
예제 #10
0
        public void CurrentDateFunction_RequestDate_ReturnsCurrentDate_1()
        {
            // BEFORE REMOVING THIS TEST METHOD YOU NEED TO WRITE TESTS FOR ALL ITS POSSIBILITIES IN THE NEW STYLE BELOW
            GlobalTable globalTable = new GlobalTable();

            List <BaseFunction> functionArguments = new List <BaseFunction>();

            functionArguments.Add(new TextFunction(new FuncInfo("stub", 1, 1), globalTable, "dd/MM/yyyy"));

            ExpressionSymbol expressionSymbol = new ExpressionSymbol(new ErrorReport(), "@currentDate", "Current Date", "Description", true, true, new CurrentDateFunction(new FuncInfo("stub", 1, 1), globalTable, functionArguments));

            Assert.AreEqual("@currentDate", expressionSymbol.Symbol);
            Assert.AreEqual("@{currentDate}", expressionSymbol.Placeholder);
            Assert.AreEqual("Current Date", expressionSymbol.Title);

            DateTime dateTime = DateTime.Now;

            Assert.AreEqual(DateTime.Now.ToString("dd/MM/yyyy"), expressionSymbol.Value);
        }
예제 #11
0
        public void ReplaceFunction_InputText_ReplacesCorrectly_1()
        {
            // BEFORE REMOVING THIS TEST METHOD YOU NEED TO WRITE TESTS FOR ALL ITS POSSIBILITIES IN THE NEW STYLE BELOW

            GlobalTable globalTable = new GlobalTable();

            List <BaseFunction> functionArguments = new List <BaseFunction>();

            functionArguments.Add(new TextFunction(new FuncInfo("stub", 1, 1), globalTable, "Dashboard Usage"));
            functionArguments.Add(new TextFunction(new FuncInfo("stub", 1, 1), globalTable, " "));
            functionArguments.Add(new TextFunction(new FuncInfo("stub", 1, 1), globalTable, "_"));

            ExpressionSymbol expressionSymbol = new ExpressionSymbol(new ErrorReport(), "@classInstance", "Class Instance", "Description", true, true, new ReplaceFunction(new FuncInfo("stub", 1, 1), globalTable, functionArguments));

            Assert.AreEqual("@classInstance", expressionSymbol.Symbol);
            Assert.AreEqual("@{classInstance}", expressionSymbol.Placeholder);
            Assert.AreEqual("Class Instance", expressionSymbol.Title);

            Assert.AreEqual("Dashboard_Usage", expressionSymbol.Value);
        }
예제 #12
0
        static void ReplaceOneFunction(
            string key,
            string outerOpenParenthesisSymbol,
            string outerCloseParenthesisSymbol,
            string outerParameterSeparatorSymbol,
            Dictionary <string, ConstantNodeBase> outerConstantsTableReference,
            Dictionary <string, string> outerReverseConstantsTableReference,
            Dictionary <string, ExpressionSymbol> outerSymbolTableReference,
            Dictionary <string, string> outerReverseSymbolTableReference,
            LevelDictionary <Type, IConstantInterpreter> interpreters,
            IParameterRegistry outerParametersTableReference,
            string outerExpressionSymbol,
            string[] outerAllSymbolsSymbols)
        {
            ExpressionSymbol symbol = outerSymbolTableReference[key];

            if (symbol.IsFunctionCall)
            {
                return;
            }

            var replaced = symbol.Expression;

            while (replaced != null)
            {
                outerSymbolTableReference[key].Expression = replaced;
                replaced = ReplaceFunctionsLocal(
                    replaced,
                    outerOpenParenthesisSymbol,
                    outerCloseParenthesisSymbol,
                    outerParameterSeparatorSymbol,
                    outerConstantsTableReference,
                    outerReverseConstantsTableReference,
                    outerSymbolTableReference,
                    outerReverseSymbolTableReference,
                    interpreters,
                    outerParametersTableReference,
                    outerExpressionSymbol,
                    outerAllSymbolsSymbols);
            }
예제 #13
0
        public void Placeholder_NotAvailable_When_IsPlaceholder_False()
        {
            GlobalTable globalTable = new GlobalTable();

            List <BaseFunction> functionArguments = new List <BaseFunction>();

            functionArguments.Add(new TextFunction(new FuncInfo("stub", 1, 1), globalTable, "dd/MM/yyyy"));

            CurrentDateFunction currentDateFunction = new CurrentDateFunction(new FuncInfo("stub", 1, 1), globalTable, functionArguments);
            UpperCaseFunction   upperCaseFunction   = new UpperCaseFunction(new FuncInfo("stub", 1, 1), globalTable, functionArguments);


            ExpressionSymbol expressionSymbol1 = new ExpressionSymbol(new ErrorReport(), "@currentDate", "Current Date", "Description", false, true, currentDateFunction);
            ExpressionSymbol expressionSymbol2 = new ExpressionSymbol(new ErrorReport(), "@camelCase", "Camel Cased", "Description", true, true, upperCaseFunction);

            globalTable.AddSymbol(expressionSymbol1);
            globalTable.AddSymbol(expressionSymbol2);

            Assert.AreEqual(1, globalTable.Placeholders.Length);
            Assert.AreEqual("@{camelCase}", globalTable.Placeholders[0]);
            Assert.AreEqual("DD/MM/YYYY", globalTable.GetValueOfSymbol("@camelCase"));
        }
예제 #14
0
    internal static ComputationBody CreateBody(WorkingExpressionSet workingSet)
    {
        if (workingSet.CancellationToken.IsCancellationRequested)
        {
            return(ComputationBody.Empty);
        }

        foreach (Type extractorType in workingSet.Extractors.KeysByLevel.OrderBy(p => p.Key)
                 .SelectMany(p => p.Value).ToArray())
        {
            workingSet.Expression = workingSet.Extractors[extractorType].ExtractAllConstants(
                workingSet.Expression,
                workingSet.ConstantsTable,
                workingSet.ReverseConstantsTable,
                workingSet.Definition);

            if (workingSet.CancellationToken.IsCancellationRequested)
            {
                return(ComputationBody.Empty);
            }
        }

        workingSet.Expression = workingSet.Expression.Trim().Replace(
            " ",
            string.Empty);

        // Start preparing expression
        workingSet.SymbolTable.Add(
            string.Empty,
            ExpressionSymbol.GenerateSymbol(
                string.Empty,
                workingSet.Expression));

        // Prepares expression and takes care of operators to ensure that they are all OK and usable
        workingSet.Initialize();

        workingSet.SymbolTable[string.Empty].Expression = workingSet.Expression;

        if (workingSet.CancellationToken.IsCancellationRequested)
        {
            return(ComputationBody.Empty);
        }

        // Break expression based on function calls
        FunctionsExtractor.ReplaceFunctions(
            workingSet.Definition.Parentheses.Left,
            workingSet.Definition.Parentheses.Right,
            workingSet.Definition.ParameterSeparator,
            workingSet.ConstantsTable,
            workingSet.ReverseConstantsTable,
            workingSet.SymbolTable,
            workingSet.ReverseSymbolTable,
            workingSet.Interpreters,
            workingSet.ParameterRegistry,
            workingSet.SymbolTable[string.Empty].Expression,
            workingSet.AllSymbols);

        if (workingSet.CancellationToken.IsCancellationRequested)
        {
            return(ComputationBody.Empty);
        }

        // We save a split expression for determining parameter order
        var splitExpression = workingSet.Expression.Split(
            workingSet.AllSymbols.ToArray(),
            StringSplitOptions.RemoveEmptyEntries);

        // Break by parentheses
        ParenthesesParser.FormatParentheses(
            workingSet.Definition.Parentheses.Left,
            workingSet.Definition.Parentheses.Right,
            workingSet.Definition.ParameterSeparator,
            workingSet.AllOperatorsInOrder,
            workingSet.SymbolTable,
            workingSet.ReverseSymbolTable);

        if (workingSet.CancellationToken.IsCancellationRequested)
        {
            return(ComputationBody.Empty);
        }

        // Populating symbol tables
        foreach (var p in workingSet.SymbolTable.Where(p => !p.Value.IsFunctionCall)
                 .Select(p => p.Value.Expression))
        {
            TablePopulationGenerator.PopulateTables(
                p,
                workingSet.ConstantsTable,
                workingSet.ReverseConstantsTable,
                workingSet.SymbolTable,
                workingSet.ReverseSymbolTable,
                workingSet.ParameterRegistry,
                workingSet.Interpreters,
                workingSet.Expression,
                workingSet.Definition.Parentheses.Left,
                workingSet.AllSymbols);
        }

        // For each parameter from the table we've just populated, see where it's first used, and fill in that index as the order
        foreach (ParameterContext paramForOrdering in workingSet.ParameterRegistry.Dump())
        {
            paramForOrdering.Order = Array.IndexOf(
                splitExpression,
                paramForOrdering.Name);
        }

        if (workingSet.CancellationToken.IsCancellationRequested)
        {
            return(ComputationBody.Empty);
        }

        // Generate expressions
        NodeBase?body;

        try
        {
            body = GenerateExpression(
                workingSet.SymbolTable[string.Empty].Expression,
                workingSet);
        }
        catch
        {
            body = null;
        }

        if (body == null || workingSet.CancellationToken.IsCancellationRequested)
        {
            return(ComputationBody.Empty);
        }

        if (body is ConstantNodeBase && workingSet.ParameterRegistry.Populated)
        {
            return(ComputationBody.Empty);
        }

        workingSet.Success = true;

        return(new ComputationBody(
                   body,
                   workingSet.ParameterRegistry));
    }
    internal static void FormatParentheses(
        string openParenthesis,
        string closeParenthesis,
        string parameterSeparator,
        string[] allOperatorsInOrder,
        Dictionary <string, ExpressionSymbol> symbolTable,
        Dictionary <string, string> reverseSymbolTable)
    {
        var itemsToProcess = new List <string>();

        KeyValuePair <string, ExpressionSymbol> itemToProcess;

        // Select the first expression that hasn't already been parsed
        while ((itemToProcess = symbolTable.Where(
                    (
                        p,
                        itemsToProcessL1) => !itemsToProcessL1.Contains(p.Key) && !p.Value.IsFunctionCall,
                    itemsToProcess).FirstOrDefault()).Value != null)
        {
            try
            {
                FormatParenthesis(
                    itemToProcess.Key,
                    openParenthesis,
                    closeParenthesis,
                    parameterSeparator,
                    allOperatorsInOrder,
                    symbolTable,
                    reverseSymbolTable);
            }
            finally
            {
                itemsToProcess.Add(itemToProcess.Key);
            }
        }

        void FormatParenthesis(
            string key,
            string openParenthesisL1,
            string closeParenthesisL1,
            string parameterSeparatorL1,
            string[] allOperatorsInOrderL1,
            Dictionary <string, ExpressionSymbol> symbolTableL1,
            Dictionary <string, string> reverseSymbolTableL1)
        {
            ExpressionSymbol symbol = symbolTableL1[key];

            if (symbol.IsFunctionCall)
            {
                return;
            }

            var replacedPreviously = string.Empty;
            var replaced           = symbol.Expression;

            while (replaced != replacedPreviously)
            {
                symbolTableL1[key].Expression = replaced;
                replacedPreviously            = replaced;
                replaced = ReplaceParenthesis(
                    replaced,
                    openParenthesisL1,
                    closeParenthesisL1,
                    parameterSeparatorL1,
                    allOperatorsInOrderL1,
                    symbolTableL1,
                    reverseSymbolTableL1);
            }

            string ReplaceParenthesis(
                string?source,
                string openParenthesisL2,
                string closeParenthesisL2,
                string parameterSeparatorSymbolL2,
                string[] allOperatorsInOrderSymbolsL2,
                Dictionary <string, ExpressionSymbol> symbolTableL2,
                Dictionary <string, string> reverseSymbolTableL2)
            {
                if (string.IsNullOrWhiteSpace(source))
                {
                    return(string.Empty);
                }

                var src = source !;

                var openingParenthesisLocation = src.InvariantCultureIndexOf(
                    openParenthesisL2);
                var closingParenthesisLocation = src.InvariantCultureIndexOf(
                    closeParenthesisL2);

beginning:
                if (openingParenthesisLocation != -1)
                {
                    if (closingParenthesisLocation == -1)
                    {
                        throw new InvalidOperationException();
                    }

                    if (openingParenthesisLocation < closingParenthesisLocation)
                    {
                        var resultingSubExpression = ReplaceParenthesis(
                            src.Substring(openingParenthesisLocation + openParenthesisL2.Length),
                            openParenthesisL2,
                            closeParenthesisL2,
                            parameterSeparatorSymbolL2,
                            allOperatorsInOrderSymbolsL2,
                            symbolTableL2,
                            reverseSymbolTableL2);

                        if (openingParenthesisLocation == 0)
                        {
                            src = resultingSubExpression;
                        }
                        else
                        {
                            var expr4 = src.Substring(
                                0,
                                openingParenthesisLocation);

                            if (!allOperatorsInOrderSymbolsL2.Any(
                                    (
                                        p,
                                        expr4L1) => expr4L1.InvariantCultureEndsWith(p),
                                    expr4))
                            {
                                // We have a function call
#pragma warning disable HAA0603 // Delegate allocation from a method group - Unavoidable
                                var inx = allOperatorsInOrderSymbolsL2.Max(expr4.LastIndexOf);
#pragma warning restore HAA0603 // Delegate allocation from a method group
                                var expr5 = inx == -1 ? expr4 : expr4.Substring(inx);
                                var op1   = allOperatorsInOrderSymbolsL2.OrderByDescending(p => p.Length)
                                            .FirstOrDefault(
                                    (
                                        p,
                                        expr5L1) => expr5L1.InvariantCultureStartsWith(p),
                                    expr5);
                                var expr6 = op1 == null ? expr5 : expr5.Substring(op1.Length);

                                // ReSharper disable once AssignmentIsFullyDiscarded - We're interested only in having the symbol in the table, and nothing more
                                _ = SymbolExpressionGenerator.GenerateSymbolExpression(
                                    symbolTableL2,
                                    reverseSymbolTableL2,
                                    $"{expr6}{openParenthesisL2}item{(symbolTableL2.Count - 1).ToString(CultureInfo.InvariantCulture)}{closeParenthesisL2}",
                                    false);

                                expr4 = expr6 == expr4
                                    ? string.Empty
                                    : expr4.Substring(
                                    0,
                                    expr4.Length - expr6.Length);

                                resultingSubExpression = resultingSubExpression.Replace(
                                    $"item{(symbolTableL2.Count - 1).ToString(CultureInfo.InvariantCulture)}",
                                    $"item{symbolTableL2.Count.ToString(CultureInfo.InvariantCulture)}");
                            }

                            src = $"{expr4}{resultingSubExpression}";
                        }

                        openingParenthesisLocation = src.InvariantCultureIndexOf(
                            openParenthesisL2);
                        closingParenthesisLocation = src.InvariantCultureIndexOf(
                            closeParenthesisL2);

                        goto beginning;
                    }

                    return(ProcessSubExpression(
                               closingParenthesisLocation,
                               closeParenthesisL2,
                               src,
                               parameterSeparatorSymbolL2,
                               symbolTableL2,
                               reverseSymbolTableL2));
                }

                if (closingParenthesisLocation == -1)
                {
                    return(src);
                }

                return(ProcessSubExpression(
                           closingParenthesisLocation,
                           closeParenthesisL2,
                           src,
                           parameterSeparatorSymbolL2,
                           symbolTableL2,
                           reverseSymbolTableL2));

                string ProcessSubExpression(
                    int cp,
                    string closeParenthesisL3,
                    string sourceL3,
                    string parameterSeparatorL3,
                    Dictionary <string, ExpressionSymbol> symbolTableL3,
                    Dictionary <string, string> reverseSymbolTableL3)
                {
                    var expr1 = sourceL3.Substring(
                        0,
                        cp);

                    string[] parameters = expr1.Split(
                        new[] { parameterSeparatorL3 },
                        StringSplitOptions.None);

                    var parSymbols = new List <string>(parameters.Length);

                    // ReSharper disable once LoopCanBeConvertedToQuery - We are looking for best-performance linearity here
                    foreach (var s in parameters)
                    {
                        parSymbols.Add(
                            SymbolExpressionGenerator.GenerateSymbolExpression(
                                symbolTableL3,
                                reverseSymbolTableL3,
                                s,
                                false));
                    }

                    var k = cp + closeParenthesisL3.Length;

                    return
                        ($"{string.Join(parameterSeparatorL3, parSymbols)}{(sourceL3.Length == k ? string.Empty : sourceL3.Substring(k))}");
                }
            }
        }
    }