using System.Collections.Generic;
using System.Text.RegularExpressions;
/// 파싱된 스크립트 명령
public class Command
{
public string Type { get; set; }
public Dictionary Params { get; set; } = new();
public List> Choices { get; set; }
public string GetParam(string key, string defaultValue = "")
{
return Params.TryGetValue(key, out var val) ? val.ToString() : defaultValue;
}
}
/// 스크립트 텍스트를 Command 리스트로 파싱
public static class Parser
{
private static readonly Regex TagRegex = new(@"^\[(\w+)(?:\s+(.*))?\]$");
private static readonly Regex AttrRegex = new(@"(\w+)=(""[^""]*""|'[^']*'|[^ \t\]]+)");
private static readonly Regex ChoiceRegex = new(@"^\*\s*(.+?)\s*>\s*(.+)$");
/// 스크립트 텍스트를 파싱하여 (Commands, LabelMap) 튜플 반환
public static (List Commands, Dictionary LabelMap) Parse(string text)
{
List commands = new();
Dictionary labelMap = new();
Command lastChoice = null;
text = Regex.Replace(text, "", "");
text = Regex.Replace(text, "", "");
text = Regex.Replace(text, "\r\n", "\n");
string[] lines = text.Split("\n");
foreach (var rawLine in lines)
{
string line = rawLine.Trim();
if (string.IsNullOrEmpty(line) || line.StartsWith("#"))
continue;
Match tagMatch = TagRegex.Match(line);
if (tagMatch.Success)
{
string tagName = tagMatch.Groups[1].Value;
string attrString = tagMatch.Groups[2].Value;
var scriptAction = new Command { Type = tagName };
if (!attrString.Contains("=")) scriptAction.Params["content"] = attrString;
else ParseAttributes(attrString, scriptAction.Params);
if (tagName == "label")
{
string label = scriptAction.GetParam("content");
if (!string.IsNullOrEmpty(label) && !labelMap.ContainsKey(label))
{
labelMap[label] = commands.Count;
}
}
else if (tagName == "choices")
{
scriptAction.Choices = new List>();
lastChoice = scriptAction;
}
commands.Add(scriptAction);
continue;
}
Match choiceMatch = ChoiceRegex.Match(line);
if (choiceMatch.Success && lastChoice != null)
{
lastChoice.Choices.Add(
new Dictionary
{
{ "type", "msg" },
{ "content", choiceMatch.Groups[1].Value.Trim() },
{ "goto", choiceMatch.Groups[2].Value.Trim() },
}
);
continue;
}
commands.Add(new Command { Type = "msg", Params = { { "content", line } } });
}
return (commands, labelMap);
}
private static void ParseAttributes(string attrString, Dictionary paramDict)
{
if (string.IsNullOrWhiteSpace(attrString))
return;
foreach (Match m in AttrRegex.Matches(attrString))
{
string key = m.Groups[1].Value;
string rawValue = m.Groups[2].Value;
if (rawValue.Length >= 2 && (rawValue.StartsWith("\"") || rawValue.StartsWith("'")))
rawValue = rawValue[1..^1];
paramDict[key] = rawValue;
}
}
}