/// <summary>Evaluates a terminfo formatting string, using the supplied arguments.</summary> /// <param name="format">The format string.</param> /// <param name="args">The arguments to the format string.</param> /// <returns>The formatted string.</returns> public static string Evaluate(string format, params FormatParam[] args) { if (format == null) { throw new ArgumentNullException(nameof(format)); } if (args == null) { throw new ArgumentNullException(nameof(args)); } // Initialize the stack to use for processing. LowLevelStack <FormatParam> stack = t_cachedStack; if (stack == null) { t_cachedStack = stack = new LowLevelStack <FormatParam>(); } else { stack.Clear(); } // "dynamic" and "static" variables are much less often used (the "dynamic" and "static" // terminology appears to just refer to two different collections rather than to any semantic // meaning). As such, we'll only initialize them if we really need them. FormatParam[] dynamicVars = null, staticVars = null; int pos = 0; return(EvaluateInternal(format, ref pos, args, stack, ref dynamicVars, ref staticVars)); // EvaluateInternal may throw IndexOutOfRangeException and InvalidOperationException // if the format string is malformed or if it's inconsistent with the parameters provided. }
public ILInterpreter(TypeSystemContext context, MethodDesc method, MethodIL methodIL) { _context = context; _method = method; _methodIL = methodIL; _stack = new LowLevelStack <StackItem>(); }
public ILInterpreter(TypeSystemContext context, MethodDesc method, MethodIL methodIL) { _context = context; _method = method; _methodIL = methodIL; _locals = new StackItem[methodIL.GetLocals().Length]; _stack = new LowLevelStack <StackItem>(); }
/// <summary>Evaluates a terminfo formatting string, using the supplied arguments and processing data structures.</summary> /// <param name="format">The format string.</param> /// <param name="pos">The position in <paramref name="format"/> to start processing.</param> /// <param name="args">The arguments to the format string.</param> /// <param name="stack">The stack to use as the format string is evaluated.</param> /// <param name="dynamicVars">A lazily-initialized collection of variables.</param> /// <param name="staticVars">A lazily-initialized collection of variables.</param> /// <returns> /// The formatted string; this may be empty if the evaluation didn't yield any output. /// The evaluation stack will have a 1 at the top if all processing was completed at invoked level /// of recursion, and a 0 at the top if we're still inside of a conditional that requires more processing. /// </returns> 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; int res; switch (format[pos]) { case '+': res = first + second; break; case '-': res = first - second; break; case '*': res = first * second; break; case '/': res = first / second; break; case 'm': res = first % second; break; case '^': res = first ^ second; break; case '&': res = first & second; break; case '|': res = first | second; break; case '=': res = AsInt(first == second); break; case '>': res = AsInt(first > second); break; case '<': res = AsInt(first < second); break; case 'A': res = AsInt(AsBool(first) && AsBool(second)); break; case 'O': res = AsInt(AsBool(first) || AsBool(second)); break; default: res = 0; break; } stack.Push(res); 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(); }
/// <summary>Evaluates a terminfo formatting string, using the supplied arguments.</summary> /// <param name="format">The format string.</param> /// <param name="args">The arguments to the format string.</param> /// <returns>The formatted string.</returns> public static string Evaluate(string format, params FormatParam[] args) { if (format == null) throw new ArgumentNullException("format"); if (args == null) throw new ArgumentNullException("args"); // Initialize the stack to use for processing. LowLevelStack stack = _cachedStack; if (stack == null) _cachedStack = stack = new LowLevelStack(); else stack.Clear(); // "dynamic" and "static" variables are much less often used (the "dynamic" and "static" // terminology appears to just refer to two different collections rather than to any semantic // meaning). As such, we'll only initialize them if we really need them. FormatParam[] dynamicVars = null, staticVars = null; int pos = 0; return EvaluateInternal(format, ref pos, args, stack, ref dynamicVars, ref staticVars); // EvaluateInternal may throw IndexOutOfRangeException and InvalidOperationException // if the format string is malformed or if it's inconsistent with the parameters provided. }
/// <summary>Evaluates a terminfo formatting string, using the supplied arguments and processing data structures.</summary> /// <param name="format">The format string.</param> /// <param name="pos">The position in <paramref name="format"/> to start processing.</param> /// <param name="args">The arguments to the format string.</param> /// <param name="stack">The stack to use as the format string is evaluated.</param> /// <param name="dynamicVars">A lazily-initialized collection of variables.</param> /// <param name="staticVars">A lazily-initialized collection of variables.</param> /// <returns> /// The formatted string; this may be empty if the evaluation didn't yield any output. /// The evaluation stack will have a 1 at the top if all processing was completed at invoked level /// of recursion, and a 0 at the top if we're still inside of a conditional that requires more processing. /// </returns> private static string EvaluateInternal( string format, ref int pos, FormatParam[] args, LowLevelStack <FormatParam> 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 = StringBuilderCache.Acquire(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(SR.IO_TermInfoInvalid); } 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++; Debug.Assert(format[pos] >= '0' && format[pos] <= '9'); 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] != '}') { Debug.Assert(format[pos] >= '0' && format[pos] <= '9'); 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]); Debug.Assert(format[pos + 2] == '\''); 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; // Some terminfo files appear to have a fairly liberal interpretation of %i. The spec states that %i increments the first two arguments, // but some uses occur when there's only a single argument. To make sure we accommodate these files, we increment the values // of up to (but not requiring) two arguments. case 'i': if (args.Length > 0) { args[0] = 1 + args[0].Int32; if (args.Length > 1) { 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); } Debug.Assert(format[pos] == 'e' || format[pos] == ';'); // 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 been handled in the recursive call). if (!AsBool(stack.Pop().Int32)) { throw new InvalidOperationException(SR.IO_TermInfoInvalid); } } // If we're in a nested processing, return to our parent. if (!sawIfConditional) { stack.Push(1); return(StringBuilderCache.GetStringAndRelease(output)); } // 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(StringBuilderCache.GetStringAndRelease(output)); // Anything else is an error default: throw new InvalidOperationException(SR.IO_TermInfoInvalid); } } stack.Push(1); return(StringBuilderCache.GetStringAndRelease(output)); }
public static string Evaluate(string format, params /* 0x00000001800D4E50-0x00000001800D4E60 */ FormatParam[] args) => default; // 0x000000018068F3F0-0x000000018068F570 private static string EvaluateInternal(string format, ref int pos, FormatParam[] args, LowLevelStack stack, ref FormatParam[] dynamicVars, ref FormatParam[] staticVars) => default; // 0x000000018068E6E0-0x000000018068F3F0