using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using YesNt.Interpreter.Runtime; namespace YesNt.Interpreter.Utilities; /// /// Provides high-performance template substitution for variables and stack parameters. /// internal static class TemplateProcessor { /// /// Replaces all occurrences of ${variableName} with their current values. /// public static string ProcessVariables(string input, RuntimeInformation runtimeInfo) { if (string.IsNullOrEmpty(input)) { return input; } int startIdx = input.IndexOf("${", StringComparison.Ordinal); if (startIdx == -1) { return input; } StringBuilder sb = new StringBuilder(input.Length); int lastIdx = 0; while (startIdx != -1) { _ = sb.Append(input, lastIdx, startIdx - lastIdx); int endIdx = input.IndexOf('}', startIdx + 2); if (endIdx == -1) { _ = sb.Append("${"); lastIdx = startIdx + 2; } else { string varName = input[(startIdx + 2)..endIdx]; if (runtimeInfo.Variables.TryGetValue(varName, out string value)) { _ = sb.Append(value); } else if (runtimeInfo.GlobalVariables.TryGetValue(varName, out value)) { _ = sb.Append(value); } else if (!runtimeInfo.IsSearching) { runtimeInfo.Exit(ExitMessages.VariableNotFound(varName), true); return input; } else { _ = sb.Append("${"); _ = sb.Append(varName); _ = sb.Append('}'); } lastIdx = endIdx + 1; } startIdx = input.IndexOf("${", lastIdx, StringComparison.Ordinal); } _ = sb.Append(input, lastIdx, input.Length - lastIdx); return sb.ToString(); } /// /// Replaces all occurrences of a placeholder (e.g., %in, %out) with values popped from a stack. /// public static string ProcessStackParameters(string input, string placeholder, Stack stack, RuntimeInformation runtimeInfo, string emptyStackMessage) { if (string.IsNullOrEmpty(input)) { return input; } int startIdx = input.IndexOf(placeholder, StringComparison.Ordinal); if (startIdx == -1) { return input; } StringBuilder sb = new StringBuilder(input.Length); int lastIdx = 0; int placeholderLen = placeholder.Length; while (startIdx != -1) { _ = sb.Append(input, lastIdx, startIdx - lastIdx); if (stack.Count == 0) { runtimeInfo.Exit(emptyStackMessage, true); return input; } _ = sb.Append(stack.Pop()); lastIdx = startIdx + placeholderLen; startIdx = input.IndexOf(placeholder, lastIdx, StringComparison.Ordinal); } _ = sb.Append(input, lastIdx, input.Length - lastIdx); return sb.ToString(); } /// /// Replaces all occurrences of a placeholder with a fixed value. /// public static string ProcessSimplePlaceholders(string input, string placeholder, string value) { return string.IsNullOrEmpty(input) ? input : input.Replace(placeholder, value, StringComparison.Ordinal); } /// /// Replaces all occurrences of a placeholder with values generated by a provider function. /// public static string ProcessDynamicPlaceholders(string input, string placeholder, Func valueProvider) { if (string.IsNullOrEmpty(input)) { return input; } int startIdx = input.IndexOf(placeholder, StringComparison.Ordinal); if (startIdx == -1) { return input; } StringBuilder sb = new StringBuilder(input.Length); int lastIdx = 0; int placeholderLen = placeholder.Length; while (startIdx != -1) { _ = sb.Append(input, lastIdx, startIdx - lastIdx); _ = sb.Append(valueProvider()); lastIdx = startIdx + placeholderLen; startIdx = input.IndexOf(placeholder, lastIdx, StringComparison.Ordinal); } _ = sb.Append(input, lastIdx, input.Length - lastIdx); return sb.ToString(); } /// /// Replaces all occurrences of arithmetic expressions with their results. /// public static string ProcessCalculations(string input, RuntimeInformation runtimeInfo, Regex calculationRegex) { if (string.IsNullOrEmpty(input)) { return input; } MatchCollection matches = calculationRegex.Matches(input); if (matches.Count == 0) { return input; } StringBuilder sb = new StringBuilder(input.Length); int lastIdx = 0; for (int i = 0; i < matches.Count; i++) { Match match = matches[i]; _ = sb.Append(input, lastIdx, match.Index - lastIdx); string res = Evaluator.Calculate(match.Value); if (res is null) { runtimeInfo.Exit(ExitMessages.InvalidOperation, true); return input; } _ = sb.Append(res); lastIdx = match.Index + match.Length; } _ = sb.Append(input, lastIdx, input.Length - lastIdx); return sb.ToString(); } }