Element ParseExpression(DeltinScriptParser.ExprContext context) { // If the expression is a(n)... #region Operation // 0 1 2 // (expr operation expr) // count == 3 if (context.ChildCount == 3 && (Constants.MathOperations.Contains(context.GetChild(1).GetText()) || Constants.CompareOperations.Contains(context.GetChild(1).GetText()) || Constants.BoolOperations.Contains(context.GetChild(1).GetText()))) { Element left = ParseExpression(context.GetChild(0) as DeltinScriptParser.ExprContext); string operation = context.GetChild(1).GetText(); Element right = ParseExpression(context.GetChild(2) as DeltinScriptParser.ExprContext); if (Constants.BoolOperations.Contains(context.GetChild(1).GetText())) { if (left.ElementData.ValueType != Elements.ValueType.Any && left.ElementData.ValueType != Elements.ValueType.Boolean) { throw new SyntaxErrorException($"Expected boolean datatype, got {left .ElementData.ValueType.ToString()} instead.", context.start); } if (right.ElementData.ValueType != Elements.ValueType.Any && right.ElementData.ValueType != Elements.ValueType.Boolean) { throw new SyntaxErrorException($"Expected boolean datatype, got {right.ElementData.ValueType.ToString()} instead.", context.start); } } switch (operation) { case "^": return(Element.Part <V_RaiseToPower>(left, right)); case "*": return(Element.Part <V_Multiply>(left, right)); case "/": return(Element.Part <V_Divide>(left, right)); case "+": return(Element.Part <V_Add>(left, right)); case "-": return(Element.Part <V_Subtract>(left, right)); case "%": return(Element.Part <V_Modulo>(left, right)); // COMPARE : '<' | '<=' | '==' | '>=' | '>' | '!='; case "&": return(Element.Part <V_And>(left, right)); case "|": return(Element.Part <V_Or>(left, right)); case "<": return(Element.Part <V_Compare>(left, Operators.LessThan, right)); case "<=": return(Element.Part <V_Compare>(left, Operators.LessThanOrEqual, right)); case "==": return(Element.Part <V_Compare>(left, Operators.Equal, right)); case ">=": return(Element.Part <V_Compare>(left, Operators.GreaterThanOrEqual, right)); case ">": return(Element.Part <V_Compare>(left, Operators.GreaterThan, right)); case "!=": return(Element.Part <V_Compare>(left, Operators.NotEqual, right)); } } #endregion #region Not if (context.GetChild(0) is DeltinScriptParser.NotContext) { return(Element.Part <V_Not>(ParseExpression(context.GetChild(1) as DeltinScriptParser.ExprContext))); } #endregion #region Number if (context.GetChild(0) is DeltinScriptParser.NumberContext) { var number = context.GetChild(0); double num = double.Parse(number.GetChild(0).GetText()); /* * // num will have the format expr(number(X)) if positive, expr(number(neg(X))) if negative. * if (number.GetChild(0) is DeltinScriptParser.NegContext) * // Is negative, use '-' before int.parse to make it negative. * num = -double.Parse(number.GetChild(0).GetText()); * else * // Is positive * num = double.Parse(number.GetChild(0).GetText()); */ return(new V_Number(num)); } #endregion #region Boolean // True if (context.GetChild(0) is DeltinScriptParser.TrueContext) { return(new V_True()); } // False if (context.GetChild(0) is DeltinScriptParser.FalseContext) { return(new V_False()); } #endregion #region String if (context.GetChild(0) is DeltinScriptParser.StringContext) { return(V_String.ParseString( context.start, // String will look like "hey this is the contents", trim the quotes. (context.GetChild(0) as DeltinScriptParser.StringContext).STRINGLITERAL().GetText().Trim('\"'), null )); } #endregion #region Formatted String if (context.GetChild(1) is DeltinScriptParser.StringContext) { Element[] values = context.expr().Select(expr => ParseExpression(expr)).ToArray(); return(V_String.ParseString( context.start, (context.GetChild(1) as DeltinScriptParser.StringContext).STRINGLITERAL().GetText().Trim('\"'), values )); } #endregion #region null if (context.GetChild(0) is DeltinScriptParser.NullContext) { return(new V_Null()); } #endregion #region Group ( expr ) if (context.ChildCount == 3 && context.GetChild(0).GetText() == "(" && context.GetChild(1) is DeltinScriptParser.ExprContext && context.GetChild(2).GetText() == ")") { Console.WriteLine("Group type:" + context.GetChild(0).GetType()); return(ParseExpression(context.GetChild(1) as DeltinScriptParser.ExprContext)); } #endregion #region Method if (context.GetChild(0) is DeltinScriptParser.MethodContext) { return(ParseMethod(context.GetChild(0) as DeltinScriptParser.MethodContext, true)); } #endregion #region Variable if (context.GetChild(0) is DeltinScriptParser.VariableContext) { return(DefinedVar.GetVar((context.GetChild(0) as DeltinScriptParser.VariableContext).PART().GetText(), context.start).GetVariable(new V_EventPlayer())); } #endregion #region Array if (context.ChildCount == 4 && context.GetChild(1).GetText() == "[" && context.GetChild(3).GetText() == "]") { return(Element.Part <V_ValueInArray>( ParseExpression(context.expr(0) as DeltinScriptParser.ExprContext), ParseExpression(context.expr(1) as DeltinScriptParser.ExprContext))); } #endregion #region Create Array if (context.ChildCount >= 4 && context.GetChild(0).GetText() == "[") { var expressions = context.expr(); V_Append prev = null; V_Append current = null; for (int i = 0; i < expressions.Length; i++) { current = new V_Append() { ParameterValues = new object[2] }; if (prev != null) { current.ParameterValues[0] = prev; } else { current.ParameterValues[0] = new V_EmptyArray(); } current.ParameterValues[1] = ParseExpression(expressions[i]); prev = current; } return(current); } #endregion #region Empty Array if (context.ChildCount == 2 && context.GetText() == "[]") { return(Element.Part <V_EmptyArray>()); } #endregion #region Seperator/enum if (context.ChildCount == 3 && context.GetChild(1).GetText() == ".") { Element left = ParseExpression(context.GetChild(0) as DeltinScriptParser.ExprContext); string variableName = context.GetChild(2).GetChild(0).GetText(); DefinedVar var = DefinedVar.GetVar(variableName, context.start); return(var.GetVariable(left)); } #endregion throw new Exception($"What's a {context.GetType().Name}?"); }
void ParseStatement(DeltinScriptParser.StatementContext statementContext) { #region Method if (statementContext.GetChild(0) is DeltinScriptParser.MethodContext) { Actions.Add(ParseMethod(statementContext.GetChild(0) as DeltinScriptParser.MethodContext, false)); return; } #endregion #region Variable set if (statementContext.STATEMENT_OPERATION() != null) { DefinedVar variable; Element target; Element index = null; string operation = statementContext.STATEMENT_OPERATION().GetText(); Element value; value = ParseExpression(statementContext.expr(1) as DeltinScriptParser.ExprContext); /* Format if the variable has an expression beforehand (sets the target player) * expr(0) .ChildCount * v v * Statement ( v v ) | Operation | Set to variable * Variable to set ( v ) * ^ expr | . | expr * ^ ^ * expr(0) .GetChild(1) == '.' */ if (statementContext.expr(0).ChildCount == 3 && statementContext.expr(0).GetChild(1).GetText() == ".") { /* Get Variable: .expr(0) .expr(1) * v v .expr(1) (if the value to be set is an array) * Statement ( v v v ) | Operation | Set to variable * Variable to set ( v v ) * ^ expr | . | expr | [] * ^ ^ * Get Target: .expr(0) .expr(0) */ variable = DefinedVar.GetVar(statementContext.expr(0).expr(1).GetChild(0).GetText(), statementContext.expr(0).expr(1).start); target = ParseExpression(statementContext.expr(0).expr(0)); // Get the index if the variable has [] var indexExpression = statementContext.expr(0).expr(1).expr(1); if (indexExpression != null) { index = ParseExpression(indexExpression); } } else { /* .expr(0) .expr(1) * v v * Statement ( v v ) | Operation | Set to variable * Variable to set (expr) | [] */ variable = DefinedVar.GetVar(statementContext.expr(0).GetChild(0).GetText(), statementContext.expr(0).start); target = new V_EventPlayer(); // Get the index if the variable has [] var indexExpression = statementContext.expr(0).expr(1); if (indexExpression != null) { index = ParseExpression(indexExpression); } } switch (operation) { case "+=": value = Element.Part <V_Add>(variable.GetVariable(target, index), value); break; case "-=": value = Element.Part <V_Subtract>(variable.GetVariable(target, index), value); break; case "*=": value = Element.Part <V_Multiply>(variable.GetVariable(target, index), value); break; case "/=": value = Element.Part <V_Divide>(variable.GetVariable(target, index), value); break; case "^=": value = Element.Part <V_RaiseToPower>(variable.GetVariable(target, index), value); break; case "%=": value = Element.Part <V_Modulo>(variable.GetVariable(target, index), value); break; } Actions.Add(variable.SetVariable(value, target, index)); return; } #endregion #region for if (statementContext.GetChild(0) is DeltinScriptParser.ForContext) { /* * CreateInitialSkip = true; * * if (SkipCountIndex == -1) * SkipCountIndex = Assign(); */ // The action the for loop starts on. // +1 for the counter reset. int forActionStartIndex = Actions.Count() + 1; // The target array in the for statement. Element forArrayElement = ParseExpression(statementContext.@for().expr()); // Use skipIndex with Get/SetIVarAtIndex to get the bool to determine if the loop is running. Var isBoolRunningSkipIf = Var.AssignVar(IsGlobal); // Insert the SkipIf at the start of the rule. Actions.Insert(0, Element.Part <A_SkipIf> ( // Condition isBoolRunningSkipIf.GetVariable(), // Number of actions new V_Number(forActionStartIndex) ) ); // Create the for's temporary variable. DefinedVar forTempVar = Var.AssignDefinedVar( name: statementContext.@for().PART().GetText(), isGlobal: IsGlobal, token: statementContext.@for().start ); // Reset the counter. Actions.Add(forTempVar.SetVariable(new V_Number(0))); // Parse the for's block. ParseBlock(statementContext.@for().block()); // Take the variable out of scope. forTempVar.OutOfScope(); // Add the for's finishing elements //Actions.Add(SetIVarAtIndex(skipIndex, new V_Number(forActionStartIndex))); // Sets how many variables to skip in the next iteraction. Actions.Add(isBoolRunningSkipIf.SetVariable(new V_True())); // Enables the skip. Actions.Add(forTempVar.SetVariable( // Indent the index by 1. Element.Part <V_Add> ( forTempVar.GetVariable(), new V_Number(1) ) )); Actions.Add(Element.Part <A_Wait>(new V_Number(0.06), WaitBehavior.IgnoreCondition)); // Add the Wait() required by the workshop. Actions.Add(Element.Part <A_LoopIf>( // Loop if the for condition is still true. Element.Part <V_Compare> ( forTempVar.GetVariable(), Operators.LessThan, Element.Part <V_CountOf>(forArrayElement) ) )); Actions.Add(isBoolRunningSkipIf.SetVariable(new V_False())); return; } #endregion #region if if (statementContext.GetChild(0) is DeltinScriptParser.IfContext) { /* * Syntax after parse: * * If: * Skip If (Not (expr)) * (body) * Skip - Only if there is if-else or else statements. * Else if: * Skip If (Not (expr)) * (body) * Skip - Only if there is more if-else or else statements. * Else: * (body) * */ // Add dummy action, create after body is created. int skipIfIndex = Actions.Count(); Actions.Add(null); // Parse the if body. ParseBlock(statementContext.@if().block()); // Determines if the "Skip" action after the if block will be created. // Only if there is if-else or else statements. bool addIfSkip = statementContext.@if().else_if().Count() > 0 || statementContext.@if().@else() != null; // Create the inital "SkipIf" action now that we know how long the if's body is. // Add one to the body length if a Skip action is going to be added. Actions.RemoveAt(skipIfIndex); Actions.Insert(skipIfIndex, Element.Part <A_SkipIf>(Element.Part <V_Not>(ParseExpression(statementContext.@if().expr())), new V_Number(Actions.Count - skipIfIndex + (addIfSkip ? 1 : 0)))); // Create the "Skip" dummy action. int skipIndex = -1; if (addIfSkip) { skipIndex = Actions.Count(); Actions.Add(null); } // Parse else-ifs var skipIfContext = statementContext.@if().else_if(); int[] skipIfData = new int[skipIfContext.Length]; // The index where the else if's "Skip" action is. for (int i = 0; i < skipIfContext.Length; i++) { // Create the dummy action. int skipIfElseIndex = Actions.Count(); Actions.Add(null); // Parse the else-if body. ParseBlock(skipIfContext[i].block()); // Determines if the "Skip" action after the else-if block will be created. // Only if there is additional if-else or else statements. bool addIfElseSkip = i < skipIfContext.Length - 1 || statementContext.@if().@else() != null; // Create the "Skip If" action. Actions.RemoveAt(skipIfElseIndex); Actions.Insert(skipIfElseIndex, Element.Part <A_SkipIf>(Element.Part <V_Not>(ParseExpression(skipIfContext[i].expr())), new V_Number(Actions.Count - skipIfElseIndex + (addIfElseSkip ? 1 : 0)))); // Create the "Skip" dummy action. if (addIfElseSkip) { skipIfData[i] = Actions.Count(); Actions.Add(null); } } // Parse else body. if (statementContext.@if().@else() != null) { ParseBlock(statementContext.@if().@else().block()); } // Replace dummy skip with real skip now that we know the length of the if, if-else, and else's bodies. // Replace if's dummy. if (skipIndex != -1) { Actions.RemoveAt(skipIndex); Actions.Insert(skipIndex, Element.Part <A_Skip>(new V_Number(Actions.Count - skipIndex))); } // Replace else-if's dummy. for (int i = 0; i < skipIfData.Length; i++) { if (skipIfData[i] != 0) { Actions.RemoveAt(skipIfData[i]); Actions.Insert(skipIfData[i], Element.Part <A_Skip>(new V_Number(Actions.Count - skipIfData[i]))); } } return; } #endregion throw new Exception($"What's a {statementContext.GetChild(0)} ({statementContext.GetChild(0).GetType()})?"); }