示例#1
0
        protected SyntaxList <SyntaxToken> Output()
        {
            var list = TokenBuilder.ToList();

            TokenBuilder.Clear();
            return(list);
        }
        // TODO(krait): Can't it render messages directly to TextWriter? But let's not change it yet..
        /// <summary>
        /// <para>Renders the template to a fully formed log message, replacing placeholders with values from <paramref name="properties"/>.</para>
        /// <para>See <see cref="LogEvent.MessageTemplate"/> for details on <paramref name="template"/> format.</para>
        /// <para>This method never throws exceptions.</para>
        /// </summary>
        /// <param name="template">A message template with zero or more placeholders to substitute.</param>
        /// <param name="properties">A dictionary of properties to be used for substitution.</param>
        public static string FormatMessage([CanBeNull] string template, [CanBeNull] IReadOnlyDictionary <string, object> properties)
        {
            if (template == null)
            {
                return(null);
            }

            if (properties == null)
            {
                return(template);
            }

            var resultBuilder     = StringBuilderCache.Acquire(template.Length * 2);
            var tokenBuilderChars = CharArrayCache.Acquire(template.Length);
            var tokenBuilder      = new TokenBuilder(tokenBuilderChars);

            for (var i = 0; i < template.Length; i++)
            {
                var currentChar = template[i];

                if (currentChar != '{' && currentChar != '}')
                {
                    tokenBuilder.Add(currentChar);
                    continue;
                }

                if (!tokenBuilder.IsEmpty)
                {
                    tokenBuilder.MoveToResult(resultBuilder);
                }

                if (i == template.Length - 1)
                {
                    tokenBuilder.Add(currentChar);
                    continue;
                }

                var nextChar = template[i + 1];
                if (currentChar == nextChar)
                {
                    tokenBuilder.Add(currentChar);
                    i++;
                    continue;
                }

                if (currentChar == '}')
                {
                    tokenBuilder.Add(currentChar);
                    continue;
                }

                var findTokenResult = tokenBuilder.TryFindToken(template, i);

                i += tokenBuilder.Length - 1;

                if (findTokenResult)
                {
                    var key = tokenBuilder.GetKeyFromBuffer();
                    if (properties.TryGetValue(key, out var value))
                    {
                        resultBuilder.Append(FormatPropertyValue(value));
                        tokenBuilder.Clear();
                    }
                }
            }

            if (!tokenBuilder.IsEmpty)
            {
                tokenBuilder.MoveToResult(resultBuilder);
            }

            CharArrayCache.Return(tokenBuilderChars);

            return(StringBuilderCache.GetStringAndRelease(resultBuilder));
        }
        /// <summary>
        /// Parse expression of variables and make SymbolicVariable
        /// </summary>
        /// <param name="expr"></param>
        /// <returns></returns>
        public static SymbolicVariable Parse(string expression)
        {
            var r = from zr in expression.Split(new string[] { ":=" }, StringSplitOptions.RemoveEmptyEntries)
                    where string.IsNullOrWhiteSpace(zr) == false
                    select zr.Trim();

            string[] rr = r.ToArray();

            string expr = string.Empty;

            if (rr.Length == 0)
            {
                return(null);
            }
            if (rr.Length > 1)
            {
                //function
                expr = rr[1];
            }
            else
            {
                expr = rr[0];
            }

            char[] separators = { '^', '*', '/', '+', '-', '(', '|' };
            char[] seps       = { '^', '*', '/', '+', '-', '|' };


            expr = expr.Replace(" ", "");

            //if (expression.StartsWith("-") ||expression.StartsWith("+")) expression = expression.Insert(1,"1*");

            // simple parsing
            // obeys the rules of priorities

            // Priorities
            //    ^  Power
            //    *  multiplication
            //    /  division
            //    +  Addition
            //    -  Subtraction


            bool NextGroupIsNegativeSign = false;

            // Tokenization is done by separating with operators
            SymbolicExpressionOperator Root = new SymbolicExpressionOperator();
            SymbolicExpressionOperator ep   = Root;

            StringBuilder TokenBuilder    = new StringBuilder();
            Stack <int>   PLevels         = new Stack <int>();
            bool          Inner           = false;
            bool          FunctionContext = false;

            for (int ix = 0; ix < expr.Length; ix++)
            {
                if (PLevels.Count == 0)
                {
                    // include the normal parsing when we are not in parenthesis group
                    if (separators.Contains(expr[ix]))
                    {
                        if ((expr[ix] == '-' || expr[ix] == '+') && ix == 0)
                        {
                            if (expr[ix] == '-')
                            {
                                // in case of -x  for example ..this will converted into operations
                                //  of -1 * x
                                ep.SymbolicExpression = SymbolicVariable.NegativeOne;
                                ep.Operation          = "*";

                                ep.Next = new SymbolicExpressionOperator();
                                ep      = ep.Next;      // advance the reference to the next node to make the linked list.

                                TokenBuilder = new StringBuilder();
                            }
                            else
                            {
                                // append the normal token
                                TokenBuilder.Append(expr[ix]);
                            }
                        }
                        else if (ix > 1 &&
                                 char.ToUpper(expr[ix - 1]) == 'E' && char.IsDigit(expr[ix - 2]) &&
                                 (expr[ix] == '-' || expr[ix] == '+'))
                        {
                            // case of 3e+2 4e-2  all cases with e in it.
                            TokenBuilder.Append(expr[ix]);
                        }
                        else if (expr[ix] == '(')
                        {
                            PLevels.Push(1);
                            var bb = ix > 0 ? separators.Contains(expr[ix - 1]) : true;
                            if (!bb)
                            {
                                //the previous charachter is normal word which indicates we reached a function
                                FunctionContext = true;
                                TokenBuilder.Append(expr[ix]);
                            }
                        }
                        else if (
                            seps.Contains(expr[ix - 1]) &&
                            (expr[ix] == '-' || expr[ix] == '+')
                            )
                        {
                            if (expr[ix + 1] == '(')
                            {
                                // so this sign is glued to the next parentheisis group

                                TokenBuilder.Append(expr[ix]);

                                // now TokenBuilder contains all signs before this

                                // and we need to preserve the information about next group
                                //   that it has a sign.

                                string signs = TokenBuilder.ToString();

                                int nve = signs.ToCharArray().Count(sign => sign == '-');

                                if ((nve % 2.0) != 0)
                                {
                                    // negative sign
                                    NextGroupIsNegativeSign = true;
                                }
                                TokenBuilder.Clear();
                            }
                            else
                            {
                                TokenBuilder.Append(expr[ix]);
                            }
                        }
                        else
                        {
                            // tokenize   when we reach any operator  or open '(' parenthesis
                            if (Inner)
                            {
                                ep.SymbolicExpression = Parse(TokenBuilder.ToString());

                                if (NextGroupIsNegativeSign)
                                {
                                    ep.SymbolicExpression = SymbolicVariable.Multiply(SymbolicVariable.NegativeOne, ep.SymbolicExpression);

                                    NextGroupIsNegativeSign = false;
                                }
                                Inner = false;
                            }
                            else
                            {
                                ep.SymbolicExpression = new SymbolicVariable(TokenBuilder.ToString());
                            }

                            TokenBuilder = new StringBuilder();

                            ep.Operation = expr[ix].ToString();
                            ep.Next      = new SymbolicExpressionOperator();
                            ep           = ep.Next; // advance the reference to the next node to make the linked list.
                        }
                    }
                    else
                    {
                        TokenBuilder.Append(expr[ix]);
                    }
                }
                else
                {
                    // we are in group
                    if (expr[ix] == '(')
                    {
                        PLevels.Push(1);
                    }
                    if (expr[ix] == ')')
                    {
                        PLevels.Pop();

                        if (PLevels.Count == 0)
                        {
                            Inner = true;
                            if (FunctionContext)
                            {
                                TokenBuilder.Append(expr[ix]);
                                FunctionContext = false;
                                Inner           = false; // because i am taking the function body as a whole in this parse pass.
                                // then inner parameters of the function will be parsed again
                            }
                        }
                        else
                        {
                            TokenBuilder.Append(expr[ix]);
                        }
                    }
                    else
                    {
                        TokenBuilder.Append(expr[ix]);
                    }
                }
            }

            // Last pass that escaped from the loop.
            if (Inner)
            {
                ep.SymbolicExpression = Parse(TokenBuilder.ToString());
                if (NextGroupIsNegativeSign)
                {
                    ep.SymbolicExpression = SymbolicVariable.Multiply(SymbolicVariable.NegativeOne, ep.SymbolicExpression);

                    NextGroupIsNegativeSign = false;
                }

                Inner = false;
            }
            else
            {
                ep.SymbolicExpression = new SymbolicVariable(TokenBuilder.ToString());
            }
            TokenBuilder = null;


            string[] Group = { "^"    /* Power for normal product '*' */
            };

            string[] SymGroup = { "|" /* Derivation operator */ };

            string[] Group1 = { "*" /* normal multiplication */,
                                "/" /* normal division */,
                                "%" /* modulus */ };


            string[] Group2 = { "+", "-" };

            /// Operator Groups Ordered by Priorities.
            string[][] OperatorGroups = { Group, SymGroup, Group1, Group2 };

            foreach (var opg in OperatorGroups)
            {
                SymbolicExpressionOperator eop = Root;

                //Pass for '[op]' and merge it  but from top to child :)  {forward)
                while (eop.Next != null)
                {
                    //if the operator in node found in the opg (current operator group) then execute the logic

                    if (opg.Count(c => c.Equals(eop.Operation, StringComparison.OrdinalIgnoreCase)) > 0)
                    {
                        short skip;
                        eop.SymbolicExpression = ArithExpression(eop, out skip);

                        //drop eop.Next
                        if (eop.Next.Next != null)
                        {
                            while (skip > 0)
                            {
                                eop.Operation = eop.Next.Operation;

                                eop.Next = eop.Next.Next;

                                skip--;
                            }
                        }
                        else
                        {
                            //no more nodes exit the loop

                            eop.Next      = null; //last item were processed.
                            eop.Operation = string.Empty;
                        }
                    }
                    else
                    {
                        eop = eop.Next;
                    }
                }
            }

            if (rr.Length > 1)
            {
                // there was a function defintion
                var fname = rr[0];

                Functions[fname] = Root.SymbolicExpression;
            }

            return(Root.SymbolicExpression);
        }