添加对 Core 的直接引用

This commit is contained in:
OLDREDSTONE
2025-03-25 15:49:57 +08:00
parent 24907abedb
commit 06c19bf10a
296 changed files with 24961 additions and 2 deletions
@@ -0,0 +1,52 @@
using sly.lexer;
namespace RhythmBase.Components.RDLang
{
internal enum RDExpressionToken
{
[Lexeme(@"[0-9]+(\.[0-9]+)?")]
Number,
[Lexeme("[i][0-9]")]
VariableInt,
[Lexeme("[f][0-9]")]
VariableFloat,
[Lexeme("[b][0-9]")]
VariableBoolean,
[Lexeme(@"\+")]
Add,
[Lexeme("-")]
Subtract,
[Lexeme(@"\*")]
Multiply,
[Lexeme("/")]
Divide,
[Lexeme("true")]
True,
[Lexeme("false")]
False,
[Lexeme("=")]
Assignment,
[Lexeme(">=")]
GreaterThanOrEqual,
[Lexeme("<=")]
LessThanOrEqual,
[Lexeme(">")]
GreaterThan,
[Lexeme("<")]
LessThan,
[Lexeme(",")]
Comma,
[Lexeme(@"[A-Za-z0-9]+(?=\()")]
Identifier,
[Lexeme(@"\(")]
LeftParenthesis,
[Lexeme(@"\)")]
RightParenthesis,
[Lexeme(@"[A-Za-z0-9]+")]
PlainString,
[Lexeme(@"[A-Za-z0-9\+]+(?=\s*[\),])|""([A-Za-z0-9\+]+)""|str:([A-Za-z0-9\+]+)")]
String,
[Lexeme(@"[ \t\r\n]", IsSkippable = true)]
Whitespace,
}
}
@@ -0,0 +1,47 @@
using sly.parser;
using sly.parser.generator;
namespace RhythmBase.Components.RDLang
{
/// <summary>
/// RDLang class provides functionality to parse and evaluate expressions written in a custom language.
/// </summary>
public static class RDLang
{
private static readonly RDVariables variables = new();
private static readonly RDLangParser parserInstance;
/// <summary>
/// Gets the collection of variables used in the custom language.
/// </summary>
/// <value>
/// The collection of variables.
/// </value>
public static RDVariables Variables { get => variables; }
/// <summary>
/// Lazy-initialized parser for the custom language expressions.
/// </summary>
internal static Lazy<Parser<RDExpressionToken, float>> Parser = new(() =>
{
var builder = new ParserBuilder<RDExpressionToken, float>();
var build = builder.BuildParser(parserInstance, ParserType.LL_RECURSIVE_DESCENT, "expression");
var parser = build.Result;
return parser;
});
static RDLang()
{
parserInstance = new RDLangParser() { Variables = variables };
}
/// <summary>
/// Tries to parse the given code string into a float result.
/// </summary>
/// <param name="code">The code string to parse.</param>
/// <param name="result">The parsed float result if the parsing is successful.</param>
/// <returns>True if parsing is successful; otherwise, false.</returns>
public static bool TryRun(string code, out float result)
{
var parseResult = Parser.Value.Parse(code);
result = parseResult.Result;
return parseResult.IsOk;
}
}
}
@@ -0,0 +1,187 @@
using sly.lexer;
using sly.parser.generator;
namespace RhythmBase.Components.RDLang
{
internal class RDLangParser
{
internal const string PlainString = "";
private static List<Token<RDExpressionToken>> TokenList { get; set; } = [];
public required RDVariables Variables { get; set; }
[NodeName("integer")]
[Production("primary: Number")]
public static float Primary(Token<RDExpressionToken> intToken) => float.Parse(intToken.Value);
[NodeName("boolean")]
[Production("primary: True")]
[Production("primary: False")]
public static float Boolean(Token<RDExpressionToken> token) => token.TokenID switch
{
RDExpressionToken.True => 1.0f,
RDExpressionToken.False => 0.0f,
_ => throw new InvalidOperationException("Invalid boolean token")
};
[NodeName("group")]
[Production("primary: LeftParenthesis [d] expression RightParenthesis [d]")]
public static float Group(float groupValue) => groupValue;
[NodeName("addOrSubstract")]
[Production("expression : term Add expression")]
[Production("expression : term Subtract expression")]
public static float Expression(float left, Token<RDExpressionToken> operatorToken, float right) => operatorToken.TokenID switch
{
RDExpressionToken.Add => left + right,
RDExpressionToken.Subtract => left - right,
_ => throw new InvalidOperationException("Invalid operator")
};
[NodeName("expression")]
[Production("expression : term")]
public static float Expression_Term(float termValue) => termValue;
[NodeName("multOrDivide")]
[Production("term : factor Multiply term")]
[Production("term : factor Divide term")]
public static float Term(float left, Token<RDExpressionToken> operatorToken, float right) => operatorToken.TokenID switch
{
RDExpressionToken.Multiply => left * right,
RDExpressionToken.Divide => left / right,
_ => throw new InvalidOperationException("Invalid operator")
};
[NodeName("term")]
[Production("term : factor")]
public static float TermFactor(float factorValue) => factorValue;
[NodeName("primary")]
[Production("factor : primary")]
public static float PrimaryFactor(float primValue) => primValue;
[NodeName("negate")]
[Production("factor : Add factor")]
[Production("factor : Subtract factor")]
public static float Factor(Token<RDExpressionToken> symbolToken, float factorValue) => symbolToken.TokenID switch
{
RDExpressionToken.Add => factorValue,
RDExpressionToken.Subtract => -factorValue,
_ => throw new InvalidOperationException("Invalid operator")
};
[NodeName("primary")]
[Production("primary: VariableInt")]
[Production("primary: VariableFloat")]
[Production("primary: VariableBoolean")]
[Production("primary: PlainString")]
public float PrimaryVariable(Token<RDExpressionToken> variableToken)
{
return variableToken.TokenID switch
{
RDExpressionToken.VariableInt => Variables.i[int.Parse(variableToken.Value[1..])],
RDExpressionToken.VariableFloat => Variables.f[int.Parse(variableToken.Value[1..])],
RDExpressionToken.VariableBoolean => Variables.b[int.Parse(variableToken.Value[1..])] ? 1.0f : 0.0f,
RDExpressionToken.PlainString => (float)Variables[variableToken.Value],
_ => throw new InvalidOperationException("Invalid variable type"),
};
}
[NodeName("string")]
[Production("argument: String")]
public static float String(Token<RDExpressionToken> stringToken)
{
TokenList.Add(new(RDExpressionToken.String,
stringToken.Value switch
{
['s', 't', 'r', ':', ..] => stringToken.Value[4..],
['"', .., '"'] => stringToken.Value[1..^1],
_ => stringToken.Value,
},
new()));
return 1;
}
[NodeName("compare")]
[Production("expression: term GreaterThanOrEqual expression")]
[Production("expression: term GreaterThan expression")]
[Production("expression: term LessThanOrEqual expression")]
[Production("expression: term LessThan expression")]
public static float Compare(float left, Token<RDExpressionToken> operatorToken, float right)
{
var result = operatorToken.TokenID switch
{
RDExpressionToken.GreaterThan => left > right,
RDExpressionToken.GreaterThanOrEqual => left >= right,
RDExpressionToken.LessThan => left < right,
RDExpressionToken.LessThanOrEqual => left <= right,
_ => throw new InvalidOperationException("Invalid operator")
};
return result ? 1.0f : 0.0f;
}
[NodeName("assignment")]
[Production("primary: VariableInt Assignment expression")]
[Production("primary: VariableFloat Assignment expression")]
[Production("primary: VariableBoolean Assignment expression")]
[Production("primary: PlainString Assignment expression")]
public float Assignment(Token<RDExpressionToken> nameToken, Token<RDExpressionToken> _, float expression)
{
var variableName = nameToken.Value;
switch (variableName[0])
{
case 'i':
Variables.i[int.Parse(variableName[1..])] = (int)expression;
break;
case 'f':
Variables.f[int.Parse(variableName[1..])] = expression;
break;
case 'b':
Variables.b[int.Parse(variableName[1..])] = expression != 0.0f;
break;
default:
Variables[variableName] = expression;
break;
}
return expression;
}
[NodeName("function_call")]
[Production("primary: Identifier LeftParenthesis [d] functionRight")]
public static float FunctionCallWithArguments(Token<RDExpressionToken> identifierToken, float _) => EvaluateFunction(identifierToken.Value, TokenList);
[NodeName("function_right")]
[Production("functionRight: RightParenthesis [d]")]
public static float FunctionCall() => 0;
[NodeName("function_right")]
[Production("functionRight: Number RightParenthesis [d]")]
[Production("functionRight: PlainString RightParenthesis [d]")]
public static float FunctionEnd(Token<RDExpressionToken> valueToken)
{
TokenList.Add(valueToken);
return 1;
}
[NodeName("arguments")]
[Production("functionRight: Number Comma [d] functionRight")]
[Production("functionRight: String Comma [d] functionRight")]
[Production("functionRight: PlainString Comma [d] functionRight")]
public static float ArgumentListWithComma(Token<RDExpressionToken> valueToken, float argument)
{
TokenList.Add(valueToken);
return 1 + argument;
}
[NodeName("arguments")]
[Production("functionRight: expression Comma [d] functionRight")]
public static float ArgumentListWithComma2(float arg, float argument)
{
TokenList.Add(new(RDExpressionToken.Number,arg.ToString(),new()));
return 1 + argument;
}
private static float EvaluateFunction(string functionName, List<Token<RDExpressionToken>> tokenList)
{
return functionName switch
{
"Rand" => (float)(TokenList.Count == 1
? int.TryParse(tokenList[0].Value, out int result)
? RDVariables.Rand(result)
: throw new ArgumentException("Invalid argument type for Rand function")
: throw new ArgumentException("Invalid argument count for Rand function")),
"atLeastRank" => (TokenList.Count == 1
? RDVariables.atLeastRank(tokenList[0].Value)
? 1.0f
: 0.0f
: throw new ArgumentException("Invalid argument count for atLeastRank function")),
"atLeastNPerfects" => (TokenList.Count == 2
? RDVariables.atLeastNPerfects(int.Parse(tokenList[0].Value), int.Parse(tokenList[1].Value))
? 1.0f
: 0.0f
: throw new ArgumentException("Invalid argument count for atLeastNPerfects function")),
_ => throw new InvalidOperationException($"Unknown function: {functionName}"),
};
}
}
}