System.ParameterizedStrings.EvaluateInternal C# (CSharp) Method

EvaluateInternal() private static method

Evaluates a terminfo formatting string, using the supplied arguments and processing data structures.
private static EvaluateInternal ( string format, int &pos, FormatParam args, LowLevelStack stack, FormatParam &dynamicVars, FormatParam &staticVars ) : string
format string The format string.
pos int The position in to start processing.
args FormatParam The arguments to the format string.
stack LowLevelStack The stack to use as the format string is evaluated.
dynamicVars FormatParam A lazily-initialized collection of variables.
staticVars FormatParam A lazily-initialized collection of variables.
return string
                private static string EvaluateInternal(
			string format, ref int pos, FormatParam[] args, LowLevelStack stack,
			ref FormatParam[] dynamicVars, ref FormatParam[] staticVars)
		{
			// Create a StringBuilder to store the output of this processing.  We use the format's length as an 
			// approximation of an upper-bound for how large the output will be, though with parameter processing,
			// this is just an estimate, sometimes way over, sometimes under.
			StringBuilder output = new StringBuilder(format.Length);

			// Format strings support conditionals, including the equivalent of "if ... then ..." and
			// "if ... then ... else ...", as well as "if ... then ... else ... then ..."
			// and so on, where an else clause can not only be evaluated for string output but also
			// as a conditional used to determine whether to evaluate a subsequent then clause.
			// We use recursion to process these subsequent parts, and we track whether we're processing
			// at the same level of the initial if clause (or whether we're nested).
			bool sawIfConditional = false;

			// Process each character in the format string, starting from the position passed in.
			for (; pos < format.Length; pos++){
				// '%' is the escape character for a special sequence to be evaluated.
				// Anything else just gets pushed to output.
				if (format[pos] != '%') {
					output.Append(format[pos]);
					continue;
				}
				// We have a special parameter sequence to process.  Now we need
				// to look at what comes after the '%'.
				++pos;
				switch (format[pos]) {
				// Output appending operations
				case '%': // Output the escaped '%'
					output.Append('%');
					break;
				case 'c': // Pop the stack and output it as a char
					output.Append((char)stack.Pop().Int32);
					break;
				case 's': // Pop the stack and output it as a string
					output.Append(stack.Pop().String);
					break;
				case 'd': // Pop the stack and output it as an integer
					output.Append(stack.Pop().Int32);
					break;
				case 'o':
				case 'X':
				case 'x':
				case ':':
				case '0':
				case '1':
				case '2':
				case '3':
				case '4':
				case '5':
				case '6':
				case '7':
				case '8':
				case '9':
					// printf strings of the format "%[[:]flags][width[.precision]][doxXs]" are allowed
					// (with a ':' used in front of flags to help differentiate from binary operations, as flags can
					// include '-' and '+').  While above we've special-cased common usage (e.g. %d, %s),
					// for more complicated expressions we delegate to printf.
					int printfEnd = pos;
					for (; printfEnd < format.Length; printfEnd++) // find the end of the printf format string
					{
						char ec = format[printfEnd];
						if (ec == 'd' || ec == 'o' || ec == 'x' || ec == 'X' || ec == 's')
						{
							break;
						}
					}
					if (printfEnd >= format.Length)
						throw new InvalidOperationException("Terminfo database contains invalid values");
					string printfFormat = format.Substring(pos - 1, printfEnd - pos + 2); // extract the format string
					if (printfFormat.Length > 1 && printfFormat[1] == ':')
						printfFormat = printfFormat.Remove(1, 1);
					output.Append(FormatPrintF(printfFormat, stack.Pop().Object)); // do the printf formatting and append its output
					break;

					// Stack pushing operations
				case 'p': // Push the specified parameter (1-based) onto the stack
					pos++;
					stack.Push(args[format[pos] - '1']);
					break;
				case 'l': // Pop a string and push its length
					stack.Push(stack.Pop().String.Length);
					break;
				case '{': // Push integer literal, enclosed between braces
					pos++;
					int intLit = 0;
					while (format[pos] != '}')
					{
						intLit = (intLit * 10) + (format[pos] - '0');
						pos++;
					}
					stack.Push(intLit);
					break;
				case '\'': // Push literal character, enclosed between single quotes
					stack.Push((int)format[pos + 1]);
					pos += 2;
					break;

					// Storing and retrieving "static" and "dynamic" variables
				case 'P': // Pop a value and store it into either static or dynamic variables based on whether the a-z variable is capitalized
					pos++;
					int setIndex;
					FormatParam[] targetVars = GetDynamicOrStaticVariables(format[pos], ref dynamicVars, ref staticVars, out setIndex);
					targetVars[setIndex] = stack.Pop();
					break;
				case 'g': // Push a static or dynamic variable; which is based on whether the a-z variable is capitalized
					pos++;
					int getIndex;
					FormatParam[] sourceVars = GetDynamicOrStaticVariables(format[pos], ref dynamicVars, ref staticVars, out getIndex);
					stack.Push(sourceVars[getIndex]);
					break;

					// Binary operations
				case '+':
				case '-':
				case '*':
				case '/':
				case 'm':
				case '^': // arithmetic
				case '&':
				case '|':                                         // bitwise
				case '=':
				case '>':
				case '<':                               // comparison
				case 'A':
				case 'O':                                         // logical
					int second = stack.Pop().Int32; // it's a stack... the second value was pushed last
					int first = stack.Pop().Int32;
					char c = format[pos];
					stack.Push(
						c == '+' ? (first + second) :
						c == '-' ? (first - second) :
						c == '*' ? (first * second) :
						c == '/' ? (first / second) :
						c == 'm' ? (first % second) :
						c == '^' ? (first ^ second) :
						c == '&' ? (first & second) :
						c == '|' ? (first | second) :
						c == '=' ? AsInt(first == second) :
						c == '>' ? AsInt(first > second) :
						c == '<' ? AsInt(first < second) :
						c == 'A' ? AsInt(AsBool(first) && AsBool(second)) :
						c == 'O' ? AsInt(AsBool(first) || AsBool(second)) :
						0); // not possible; we just validated above
					break;

					// Unary operations
				case '!':
				case '~':
					int value = stack.Pop().Int32;
					stack.Push(
						format[pos] == '!' ? AsInt(!AsBool(value)) :
						~value);
					break;

					// Augment first two parameters by 1
				case 'i':
					args[0] = 1 + args[0].Int32;
					args[1] = 1 + args[1].Int32;
					break;

					// Conditional of the form %? if-part %t then-part %e else-part %;
					// The "%e else-part" is optional.
				case '?':
					sawIfConditional = true;
					break;
				case 't':
					// We hit the end of the if-part and are about to start the then-part.
					// The if-part left its result on the stack; pop and evaluate.
					bool conditionalResult = AsBool(stack.Pop().Int32);

					// Regardless of whether it's true, run the then-part to get past it.
					// If the conditional was true, output the then results.
					pos++;
					string thenResult = EvaluateInternal(format, ref pos, args, stack, ref dynamicVars, ref staticVars);
					if (conditionalResult)
					{
						output.Append(thenResult);
					}

					// We're past the then; the top of the stack should now be a Boolean
					// indicating whether this conditional has more to be processed (an else clause).
					if (!AsBool(stack.Pop().Int32))
					{
						// Process the else clause, and if the conditional was false, output the else results.
						pos++;
						string elseResult = EvaluateInternal(format, ref pos, args, stack, ref dynamicVars, ref staticVars);
						if (!conditionalResult)
						{
							output.Append(elseResult);
						}
						// Now we should be done (any subsequent elseif logic will have bene handled in the recursive call).
						if (!AsBool(stack.Pop().Int32))
						{
							throw new InvalidOperationException("Terminfo database contains invalid values");
						}
					}

					// If we're in a nested processing, return to our parent.
					if (!sawIfConditional)
					{
						stack.Push(1);
						return output.ToString();
					}
					// Otherwise, we're done processing the conditional in its entirety.
					sawIfConditional = false;
					break;
				case 'e':
				case ';':
					// Let our caller know why we're exiting, whether due to the end of the conditional or an else branch.
					stack.Push(AsInt(format[pos] == ';'));
					return output.ToString();

					// Anything else is an error
				default:
					throw new InvalidOperationException("Terminfo database contains invalid values");
				}
			}
			stack.Push(1);
			return output.ToString();
		}