Files
ZelWiki/ZelWiki.Engine.Function/FunctionPrototypeCollection.cs
2025-02-23 18:47:21 +08:00

215 lines
7.5 KiB
C#

using ZelWiki.Engine.Function.Exceptions;
namespace ZelWiki.Engine.Function
{
public class FunctionPrototypeCollection
{
public enum WikiFunctionType
{
Standard,
Scoped,
Instruction
}
public WikiFunctionType FunctionTypes { get; private set; }
public List<PrototypeSet> Items { get; set; } = new();
/// <summary>
///
/// </summary>
/// <param name="functionTypes"></param>
public FunctionPrototypeCollection(WikiFunctionType functionTypes)
{
FunctionTypes = functionTypes;
}
public void Add(string prototypeString)
{
var prototype = ParsePrototype(prototypeString);
Items.Add(new PrototypeSet()
{
FunctionPrefix = prototype.FunctionPrefix,
ProperName = prototype.ProperName,
FunctionName = prototype.FunctionName.ToLower(),
Value = prototype
});
}
public bool Exists(string functionPrefix, string functionName)
{
functionName = functionName.ToLower();
return Items.Any(o =>
(o.FunctionPrefix == functionPrefix || o.FunctionPrefix == "$$") && o.FunctionName == functionName);
}
public FunctionPrototype Get(string functionPrefix, string functionName)
{
functionName = functionName.ToLower();
var functionPrototype = Items.FirstOrDefault(o =>
(o.FunctionPrefix == functionPrefix || o.FunctionPrefix == "$$") && o.FunctionName == functionName)
?.Value;
return functionPrototype
?? throw new WikiFunctionPrototypeNotDefinedException(
$"函数 ({functionName}) 没有定义的原型.");
}
#region Private
private FunctionPrototype ParsePrototype(string prototypeString)
{
var nameStartIndex = prototypeString.TakeWhile(c => char.IsLetterOrDigit(c) == false).Count();
var nameEndIndex = prototypeString.IndexOf(':');
var properName = prototypeString.Substring(nameStartIndex, nameEndIndex - nameStartIndex).Trim();
var functionName = properName.ToLower();
var functionPrefix = prototypeString.Substring(0, nameStartIndex).Trim();
prototypeString = prototypeString.Substring(nameEndIndex + 1).Trim();
var prototype = new FunctionPrototype()
{ FunctionPrefix = functionPrefix, ProperName = properName, FunctionName = functionName };
if (prototypeString.Length == 0)
return prototype;
var segments = prototypeString.Trim().Split('|').Select(o => o.Trim());
foreach (var segment in segments)
{
var prototypeSegment = new PrototypeParameter();
var index = 0;
if (segment[index] == '<')
{
index++;
prototypeSegment.Type = Tok(segment, ref index);
index++;
if (prototypeSegment.Type.Contains(':'))
{
var splitSeg = prototypeSegment.Type.Split(':');
prototypeSegment.Type = splitSeg[0];
if (splitSeg[1].Equals("infinite", StringComparison.InvariantCultureIgnoreCase))
{
prototypeSegment.IsInfinite = true;
if (prototype.Parameters.Any(o => o.IsInfinite))
{
throw new Exception(
$"函数 [{functionName}], 原型错误: cannot contain more than one [infinite] parameter.");
}
}
else
{
throw new Exception(
$"函数 [{functionName}], 原型错误: expected [infinite] got [{splitSeg[1]}].");
}
}
SkipWhiteSpace(segment, ref index);
if (index < segment.Length && segment[index] == '{' || segment[index] == '[')
{
if (index < segment.Length && segment[index] == '[')
{
prototypeSegment.IsRequired = true;
}
index++;
prototypeSegment.Name = Tok(segment, ref index);
if (index < segment.Length && segment[index] == '(')
{
int allowedValueEndIndex = segment.IndexOf(')', index);
string roteRequiredValues = segment.Substring(index + 1, allowedValueEndIndex - index - 1);
prototypeSegment.AllowedValues = roteRequiredValues.Trim().Split(',')
.Select(o => o.Trim().ToLower()).ToList();
index = allowedValueEndIndex;
index++;
SkipWhiteSpace(segment, ref index);
}
index++;
}
else
{
throw new Exception($"函数 [{functionName}], 原型错误: expected [{{] or [[].");
}
SkipWhiteSpace(segment, ref index);
if (index < segment.Length && segment[index] == '=')
{
index++;
SkipWhiteSpace(segment, ref index);
if (segment[index] != '\'')
{
throw new Exception($"函数 [{functionName}], 原型错误: expected [\'].");
}
index++;
prototypeSegment.DefaultValue = segment.Substring(index, (segment.Length - index) - 1);
index = segment.Length - 1;
if (index < segment.Length && segment[index] != '\'')
{
throw new Exception($"函数 [{functionName}], 原型错误: expected [\'].");
}
}
}
else
{
throw new Exception($"函数 [{functionName}], 原型错误: expected [<].");
}
prototype.Parameters.Add(prototypeSegment);
}
return prototype;
}
/// <summary>
///
/// </summary>
/// <param name="str"></param>
/// <param name="index"></param>
/// <returns></returns>
private string Tok(string str, ref int index)
{
var token = string.Empty;
SkipWhiteSpace(str, ref index);
for (; index < str.Length; index++)
{
if ("<>{}[]()".Contains(str[index]))
{
break;
}
token += str[index];
}
SkipWhiteSpace(str, ref index);
return token;
}
private static void SkipWhiteSpace(string str, ref int index)
{
while (index < str.Length && char.IsWhiteSpace(str[index]))
{
index++;
}
}
#endregion
}
}