using sly.lexer; using sly.parser.generator; namespace RhythmBase.Components.RDLang { internal class RDLangParser { internal const string PlainString = ""; private static List> TokenList { get; set; } = []; public required RDVariables Variables { get; set; } [NodeName("integer")] [Production("primary: Number")] public static float Primary(Token intToken) => float.Parse(intToken.Value); [NodeName("boolean")] [Production("primary: True")] [Production("primary: False")] public static float Boolean(Token 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 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 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 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 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 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 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 nameToken, Token _, 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 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 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 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> 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}"), }; } } }