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); }