public override Node VisitRuleset(DeltinScriptParser.RulesetContext context) { RuleNode[] rules = new RuleNode[context.ow_rule().Length]; for (int i = 0; i < rules.Length; i++) { rules[i] = (RuleNode)VisitOw_rule(context.ow_rule()[i]); } Variable useGlobalVar; Variable usePlayerVar; Enum.TryParse <Variable>(context.useGlobalVar()?.PART().GetText(), out useGlobalVar); Enum.TryParse <Variable>(context.usePlayerVar()?.PART().GetText(), out usePlayerVar); DefinedNode[] definedVars = new DefinedNode[context.vardefine().Length]; for (int i = 0; i < definedVars.Length; i++) { definedVars[i] = (DefinedNode)VisitVardefine(context.vardefine()[i]); } UserMethodNode[] userMethods = new UserMethodNode[context.user_method().Length]; for (int i = 0; i < userMethods.Length; i++) { userMethods[i] = (UserMethodNode)VisitUser_method(context.user_method()[i]); } Node node = new RulesetNode(rules, useGlobalVar, usePlayerVar, definedVars, userMethods, Range.GetRange(context)); CheckRange(node); return(node); }
private TranslateRule(RuleNode ruleNode, ScopeGroup root, ParsingData parserData) { VarCollection = parserData.VarCollection; ParserData = parserData; Rule = new Rule(ruleNode.Name, ruleNode.Event, ruleNode.Team, ruleNode.Player); Rule.Disabled = ruleNode.Disabled; IsGlobal = Rule.IsGlobal; ContinueSkip = new ContinueSkip(IsGlobal, Actions, VarCollection); ParseConditions(root, ruleNode.Conditions); // Parse the block of the rule. ScopeGroup ruleScope = root.Child(); ParseBlock(ruleScope, ruleScope, ruleNode.Block, false, null); // Fulfill remaining returns. FulfillReturns(0); Finish(); }
public override Node VisitOw_rule(DeltinScriptParser.Ow_ruleContext context) { string name = context.STRINGLITERAL().GetText().Trim('"'); BlockNode block = (BlockNode)VisitBlock(context.block()); IExpressionNode[] conditions = new IExpressionNode[context.rule_if()?.expr().Length ?? 0]; Range[] conditionRanges = new Range[context.rule_if()?.expr().Length ?? 0]; for (int i = 0; i < conditions.Length; i++) { conditions[i] = (IExpressionNode)VisitExpr(context.rule_if().expr()[i]); conditionRanges[i] = Range.GetRange(context.rule_if().expr()[i]); } RuleEvent eventType = RuleEvent.OngoingGlobal; TeamSelector team = TeamSelector.All; PlayerSelector player = PlayerSelector.All; Range eventRange = null; Range teamRange = null; Range playerRange = null; foreach (var ruleOption in context.rule_option()) { string option = ruleOption.PART(0).GetText(); Range optionRange = Range.GetRange(ruleOption.PART(0).Symbol); string value = null; Range valueRange = null; if (ruleOption.PART().Length == 2) { value = ruleOption.PART(1).GetText(); valueRange = Range.GetRange(ruleOption.PART(1).Symbol); } switch (option) { case "Event": if (!Enum.TryParse <RuleEvent>(value, out eventType)) { _diagnostics.Add(new Diagnostic($"{value} is not a valid Event type.", valueRange)); } eventRange = Range.GetRange(ruleOption); break; case "Team": if (!Enum.TryParse <TeamSelector>(value, out team)) { _diagnostics.Add(new Diagnostic($"{value} is not a valid Team type.", valueRange)); } teamRange = Range.GetRange(ruleOption); break; case "Player": if (!Enum.TryParse <PlayerSelector>(value, out player)) { _diagnostics.Add(new Diagnostic($"{value} is not a valid Player type.", valueRange)); } playerRange = Range.GetRange(ruleOption); break; default: _diagnostics.Add(new Diagnostic($"{value} is not a valid rule option.", optionRange)); break; } } var node = new RuleNode(name, eventType, team, player, conditions, block, eventRange, teamRange, playerRange, Range.GetRange(context)); CheckRange(node); return(node); }
private Translate(RuleNode ruleNode, ScopeGroup root, VarCollection varCollection, UserMethod[] userMethods) { Root = root; VarCollection = varCollection; UserMethods = userMethods; Rule = new Rule(ruleNode.Name, ruleNode.Event, ruleNode.Team, ruleNode.Player); IsGlobal = Rule.IsGlobal; ContinueSkip = new ContinueSkip(IsGlobal, Actions, varCollection); ParseConditions(ruleNode.Conditions); ParseBlock(root.Child(), ruleNode.Block, false, null); Rule.Actions = Actions.ToArray(); Rule.Conditions = Conditions.ToArray(); // Fufill remaining skips foreach (var skip in ReturnSkips) { skip.ParameterValues = new IWorkshopTree[] { new V_Number(Actions.Count - ReturnSkips.IndexOf(skip)) } } ; ReturnSkips.Clear(); } void ParseConditions(IExpressionNode[] expressions) { foreach (var expr in expressions) { Element parsedIf = ParseExpression(Root, expr); // If the parsed if is a V_Compare, translate it to a condition. // Makes "(value1 == value2) == true" to just "value1 == value2" if (parsedIf is V_Compare) { Element left = (Element)parsedIf.ParameterValues[0]; if (!left.ElementData.IsValue) { throw SyntaxErrorException.InvalidMethodType(true, left.Name, ((Node)expr).Range); } Element right = (Element)parsedIf.ParameterValues[2]; if (!right.ElementData.IsValue) { throw SyntaxErrorException.InvalidMethodType(true, right.Name, ((Node)expr).Range); } Conditions.Add( new Condition( left, (EnumMember)parsedIf.ParameterValues[1], right ) ); } // If not, just do "parsedIf == true" else { if (!parsedIf.ElementData.IsValue) { throw SyntaxErrorException.InvalidMethodType(true, parsedIf.Name, ((Node)expr).Range); } Conditions.Add(new Condition( parsedIf, EnumData.GetEnumValue(Operators.Equal), new V_True() )); } } } Element ParseExpression(ScopeGroup scope, IExpressionNode expression) { switch (expression) { // Math and boolean operations. case OperationNode operationNode: { Element left = ParseExpression(scope, operationNode.Left); Element right = ParseExpression(scope, operationNode.Right); /* * if (Constants.BoolOperations.Contains(operationNode.Operation)) * { * if (left.ElementData.ValueType != Elements.ValueType.Any && left.ElementData.ValueType != Elements.ValueType.Boolean) * throw new SyntaxErrorException($"Expected boolean, got {left .ElementData.ValueType.ToString()} instead.", ((Node)operationNode.Left).Range); * * if (right.ElementData.ValueType != Elements.ValueType.Any && right.ElementData.ValueType != Elements.ValueType.Boolean) * throw new SyntaxErrorException($"Expected boolean, got {right.ElementData.ValueType.ToString()} instead.", ((Node)operationNode.Right).Range); * } */ switch (operationNode.Operation) { // Math: ^, *, %, /, +, - case "^": return(Element.Part <V_RaiseToPower>(left, right)); case "*": return(Element.Part <V_Multiply>(left, right)); case "%": return(Element.Part <V_Modulo>(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)); // BoolCompare: &, | case "&": return(Element.Part <V_And>(left, right)); case "|": return(Element.Part <V_Or>(left, right)); // Compare: <, <=, ==, >=, >, != case "<": return(Element.Part <V_Compare>(left, EnumData.GetEnumValue(Operators.LessThan), right)); case "<=": return(Element.Part <V_Compare>(left, EnumData.GetEnumValue(Operators.LessThanOrEqual), right)); case "==": return(Element.Part <V_Compare>(left, EnumData.GetEnumValue(Operators.Equal), right)); case ">=": return(Element.Part <V_Compare>(left, EnumData.GetEnumValue(Operators.GreaterThanOrEqual), right)); case ">": return(Element.Part <V_Compare>(left, EnumData.GetEnumValue(Operators.GreaterThan), right)); case "!=": return(Element.Part <V_Compare>(left, EnumData.GetEnumValue(Operators.NotEqual), right)); } throw new Exception($"Operation {operationNode.Operation} not implemented."); } // Number case NumberNode numberNode: return(new V_Number(numberNode.Value)); // Bool case BooleanNode boolNode: if (boolNode.Value) { return(new V_True()); } else { return(new V_False()); } // Not operation case NotNode notNode: return(Element.Part <V_Not>(ParseExpression(scope, notNode.Value))); // Strings case StringNode stringNode: Element[] stringFormat = new Element[stringNode.Format?.Length ?? 0]; for (int i = 0; i < stringFormat.Length; i++) { stringFormat[i] = ParseExpression(scope, stringNode.Format[i]); } return(V_String.ParseString(stringNode.Range, stringNode.Value, stringFormat)); // Null case NullNode nullNode: return(new V_Null()); // TODO check if groups need to be implemented here // Methods case MethodNode methodNode: return(ParseMethod(scope, methodNode, true)); // Variable case VariableNode variableNode: return(scope.GetVar(variableNode.Name, variableNode.Range, Diagnostics) .GetVariable(variableNode.Target != null ? ParseExpression(scope, variableNode.Target) : null)); // Get value in array case ValueInArrayNode viaNode: return(Element.Part <V_ValueInArray>(ParseExpression(scope, viaNode.Value), ParseExpression(scope, viaNode.Index))); // Create array case CreateArrayNode createArrayNode: { Element prev = null; Element current = null; for (int i = 0; i < createArrayNode.Values.Length; i++) { current = new V_Append() { ParameterValues = new IWorkshopTree[2] }; if (prev != null) { current.ParameterValues[0] = prev; } else { current.ParameterValues[0] = new V_EmptyArray(); } current.ParameterValues[1] = ParseExpression(scope, createArrayNode.Values[i]); prev = current; } return(current ?? new V_EmptyArray()); } case EnumNode enumNode: return(EnumData.Special(enumNode.EnumMember) ?? throw SyntaxErrorException.EnumCantBeValue(enumNode.Type, enumNode.Range)); // Seperator } throw new Exception(); } Element ParseMethod(ScopeGroup scope, MethodNode methodNode, bool needsToBeValue) { methodNode.RelatedScopeGroup = scope; // Get the kind of method the method is (Method (Overwatch), Custom Method, or User Method.) var methodType = GetMethodType(UserMethods, methodNode.Name); // Throw exception if the method does not exist. if (methodType == null) { throw SyntaxErrorException.NonexistentMethod(methodNode.Name, methodNode.Range); } Element method; switch (methodType) { case MethodType.Method: { Type owMethod = Element.GetMethod(methodNode.Name); method = (Element)Activator.CreateInstance(owMethod); Parameter[] parameterData = owMethod.GetCustomAttributes <Parameter>().ToArray(); List <IWorkshopTree> parsedParameters = new List <IWorkshopTree>(); for (int i = 0; i < parameterData.Length; i++) { if (methodNode.Parameters.Length > i) { // Parse the parameter. parsedParameters.Add(ParseParameter(scope, methodNode.Parameters[i], methodNode.Name, parameterData[i])); } else { if (parameterData[i].ParameterType == ParameterType.Value && parameterData[i].DefaultType == null) { // Throw exception if there is no default method to fallback on. throw SyntaxErrorException.MissingParameter(parameterData[i].Name, methodNode.Name, methodNode.Range); } else { parsedParameters.Add(parameterData[i].GetDefault()); } } } method.ParameterValues = parsedParameters.ToArray(); break; } case MethodType.CustomMethod: { MethodInfo customMethod = CustomMethods.GetCustomMethod(methodNode.Name); Parameter[] parameterData = customMethod.GetCustomAttributes <Parameter>().ToArray(); object[] parsedParameters = new Element[parameterData.Length]; for (int i = 0; i < parameterData.Length; i++) { if (methodNode.Parameters.Length > i) { parsedParameters[i] = ParseParameter(scope, methodNode.Parameters[i], methodNode.Name, parameterData[i]); } else { // Throw exception if there is no default method to fallback on. throw SyntaxErrorException.MissingParameter(parameterData[i].Name, methodNode.Name, methodNode.Range); } } MethodResult result = (MethodResult)customMethod.Invoke(null, new object[] { IsGlobal, VarCollection, parsedParameters }); switch (result.MethodType) { case CustomMethodType.Action: if (needsToBeValue) { throw SyntaxErrorException.InvalidMethodType(true, methodNode.Name, methodNode.Range); } break; case CustomMethodType.MultiAction_Value: case CustomMethodType.Value: if (!needsToBeValue) { throw SyntaxErrorException.InvalidMethodType(false, methodNode.Name, methodNode.Range); } break; } // Some custom methods have extra actions. if (result.Elements != null) { Actions.AddRange(result.Elements); } method = result.Result; break; } case MethodType.UserMethod: { if (!AllowRecursion) { UserMethod userMethod = UserMethod.GetUserMethod(UserMethods, methodNode.Name); if (MethodStackNoRecursive.Contains(userMethod)) { throw SyntaxErrorException.RecursionNotAllowed(methodNode.Range); } var methodScope = Root.Child(); // Add the parameter variables to the scope. DefinedVar[] parameterVars = new DefinedVar[userMethod.Parameters.Length]; for (int i = 0; i < parameterVars.Length; i++) { if (methodNode.Parameters.Length > i) { // Create a new variable using the parameter input. parameterVars[i] = VarCollection.AssignDefinedVar(methodScope, IsGlobal, userMethod.Parameters[i].Name, methodNode.Range); Actions.Add(parameterVars[i].SetVariable(ParseExpression(scope, methodNode.Parameters[i]))); } else { throw SyntaxErrorException.MissingParameter(userMethod.Parameters[i].Name, methodNode.Name, methodNode.Range); } } var returns = VarCollection.AssignVar($"{methodNode.Name}: return temp value", IsGlobal); MethodStackNoRecursive.Add(userMethod); var userMethodScope = methodScope.Child(); userMethod.Block.RelatedScopeGroup = userMethodScope; ParseBlock(userMethodScope, userMethod.Block, true, returns); MethodStackNoRecursive.Remove(userMethod); // No return value if the method is being used as an action. if (needsToBeValue) { method = returns.GetVariable(); } else { method = null; } break; } else { UserMethod userMethod = UserMethod.GetUserMethod(UserMethods, methodNode.Name); MethodStack lastMethod = MethodStack.FirstOrDefault(ms => ms.UserMethod == userMethod); if (lastMethod != null) { ContinueSkip.Setup(); for (int i = 0; i < lastMethod.ParameterVars.Length; i++) { if (methodNode.Parameters.Length > i) { Actions.Add(lastMethod.ParameterVars[i].Push(ParseExpression(scope, methodNode.Parameters[i]))); } } // ?--- Multidimensional Array Actions.Add( Element.Part <A_SetGlobalVariable>(EnumData.GetEnumValue(Variable.B), lastMethod.ContinueSkipArray.GetVariable()) ); Actions.Add( Element.Part <A_ModifyGlobalVariable>(EnumData.GetEnumValue(Variable.B), EnumData.GetEnumValue(Operation.AppendToArray), new V_Number(ContinueSkip.GetSkipCount() + 4)) ); Actions.Add( lastMethod.ContinueSkipArray.SetVariable(Element.Part <V_GlobalVariable>(EnumData.GetEnumValue(Variable.B))) ); // ?--- ContinueSkip.SetSkipCount(lastMethod.ActionIndex); Actions.Add(Element.Part <A_Loop>()); if (needsToBeValue) { method = lastMethod.Return.GetVariable(); } else { method = null; } } else { var methodScope = Root.Child(); // Add the parameter variables to the scope. ParameterVar[] parameterVars = new ParameterVar[userMethod.Parameters.Length]; for (int i = 0; i < parameterVars.Length; i++) { if (methodNode.Parameters.Length > i) { // Create a new variable using the parameter input. parameterVars[i] = VarCollection.AssignParameterVar(Actions, methodScope, IsGlobal, userMethod.Parameters[i].Name, methodNode.Range); Actions.Add(parameterVars[i].Push(ParseExpression(scope, methodNode.Parameters[i]))); } else { throw SyntaxErrorException.MissingParameter(userMethod.Parameters[i].Name, methodNode.Name, methodNode.Range); } } var returns = VarCollection.AssignVar($"{methodNode.Name}: return temp value", IsGlobal); Var continueSkipArray = VarCollection.AssignVar($"{methodNode.Name}: continue skip temp value", IsGlobal); var stack = new MethodStack(userMethod, parameterVars, ContinueSkip.GetSkipCount(), returns, continueSkipArray); MethodStack.Add(stack); var userMethodScope = methodScope.Child(); userMethod.Block.RelatedScopeGroup = userMethodScope; ParseBlock(userMethodScope, userMethod.Block, true, returns); // No return value if the method is being used as an action. if (needsToBeValue) { method = returns.GetVariable(); } else { method = null; } Actions.Add(Element.Part <A_Wait>(new V_Number(Constants.MINIMUM_WAIT))); for (int i = 0; i < parameterVars.Length; i++) { parameterVars[i].Pop(); } ContinueSkip.Setup(); ContinueSkip.SetSkipCount(Element.Part <V_LastOf>(continueSkipArray.GetVariable())); // ?--- Multidimensional Array Actions.Add( Element.Part <A_SetGlobalVariable>(EnumData.GetEnumValue(Variable.B), continueSkipArray.GetVariable()) ); Actions.Add( continueSkipArray.SetVariable( Element.Part <V_ArraySlice>( Element.Part <V_GlobalVariable>(EnumData.GetEnumValue(Variable.B)), new V_Number(0), Element.Part <V_Subtract>( Element.Part <V_CountOf>(Element.Part <V_GlobalVariable>(EnumData.GetEnumValue(Variable.B))), new V_Number(1) ) ) ) ); // ?--- Actions.Add( Element.Part <A_LoopIf>( Element.Part <V_Compare>( Element.Part <V_CountOf>(continueSkipArray.GetVariable()), EnumData.GetEnumValue(Operators.NotEqual), new V_Number(0) ) ) ); ContinueSkip.ResetSkip(); MethodStack.Remove(stack); } break; } } default: throw new NotImplementedException(); } methodNode.RelatedElement = method; return(method); } IWorkshopTree ParseParameter(ScopeGroup scope, IExpressionNode node, string methodName, Parameter parameterData) { IWorkshopTree value = null; switch (node) { case EnumNode enumNode: /* * if (parameterData.ParameterType != ParameterType.Enum) * throw SyntaxErrorException.ExpectedType(true, parameterData.ValueType.ToString(), methodName, parameterData.Name, enumNode.Range); * * if (enumNode.Type != parameterData.EnumType.Name) * throw SyntaxErrorException.ExpectedType(false, parameterData.EnumType.ToString(), methodName, parameterData.Name, enumNode.Range); */ value = (IWorkshopTree)EnumData.Special(enumNode.EnumMember) ?? (IWorkshopTree)enumNode.EnumMember; //if (value == null) // throw SyntaxErrorException.InvalidEnumValue(enumNode.Type, enumNode.Value, enumNode.Range); break; default: if (parameterData.ParameterType != ParameterType.Value) { throw SyntaxErrorException.ExpectedType(false, parameterData.EnumType.Name, methodName, parameterData.Name, ((Node)node).Range); } value = ParseExpression(scope, node); Element element = value as Element; ElementData elementData = element.GetType().GetCustomAttribute <ElementData>(); if (elementData.ValueType != Elements.ValueType.Any && !parameterData.ValueType.HasFlag(elementData.ValueType)) { throw SyntaxErrorException.InvalidType(parameterData.ValueType, elementData.ValueType, ((Node)node).Range); } break; } if (value == null) { throw new Exception("Failed to parse parameter."); } return(value); }
public static TranslateResult GetRule(RuleNode ruleNode, ScopeGroup root, VarCollection varCollection, UserMethod[] userMethods) { var result = new Translate(ruleNode, root, varCollection, userMethods); return(new TranslateResult(result.Rule, result.Diagnostics.ToArray())); }
public RulesetNode(DeltinScriptParser.RulesetContext context, BuildAstVisitor visitor) : base(new Location(visitor.file, Range.GetRange(context))) { Imports = new ImportNode[context.import_file().Length]; for (int i = 0; i < Imports.Length; i++) { Imports[i] = new ImportNode(context.import_file(i), visitor); } ObjectImports = new ImportObjectNode[context.import_object().Length]; for (int i = 0; i < ObjectImports.Length; i++) { ObjectImports[i] = new ImportObjectNode(context.import_object(i), visitor); } Rules = new RuleNode[context.ow_rule().Length]; for (int i = 0; i < Rules.Length; i++) { Rules[i] = (RuleNode)visitor.VisitOw_rule(context.ow_rule()[i]); } if (context.useGlobalVar() != null) { if (Enum.TryParse(context.useGlobalVar().PART().GetText(), out Variable temp)) { UseGlobalVar = temp; } } if (context.usePlayerVar() != null) { if (Enum.TryParse(context.usePlayerVar().PART().GetText(), out Variable temp)) { UsePlayerVar = temp; } } if (context.useDimVar() != null) { if (Enum.TryParse(context.useDimVar().PART().GetText(), out Variable temp)) { UseBuilderVar = temp; } } DefinedVars = new RuleDefineNode[context.rule_define().Length]; for (int i = 0; i < DefinedVars.Length; i++) { DefinedVars[i] = (RuleDefineNode)visitor.VisitRule_define(context.rule_define(i)); } UserMethods = new UserMethodNode[context.user_method().Length]; for (int i = 0; i < UserMethods.Length; i++) { UserMethods[i] = (UserMethodNode)visitor.VisitUser_method(context.user_method(i)); } DefinedTypes = new TypeDefineNode[context.type_define().Length]; for (int i = 0; i < DefinedTypes.Length; i++) { DefinedTypes[i] = (TypeDefineNode)visitor.VisitType_define(context.type_define(i)); } }
public RulesetNode(DeltinScriptParser.RulesetContext context, BuildAstVisitor visitor) : base(new Location(visitor.file, DocRange.GetRange(context))) { // Get imports Imports = new ImportNode[context.import_file().Length]; for (int i = 0; i < Imports.Length; i++) { Imports[i] = new ImportNode(context.import_file(i), visitor); } ObjectImports = new ImportObjectNode[context.import_object().Length]; for (int i = 0; i < ObjectImports.Length; i++) { ObjectImports[i] = new ImportObjectNode(context.import_object(i), visitor); } // Get rules Rules = new RuleNode[context.ow_rule().Length]; for (int i = 0; i < Rules.Length; i++) { Rules[i] = (RuleNode)visitor.VisitOw_rule(context.ow_rule()[i]); } // Get defined variables DefinedVars = new RuleDefineNode[context.rule_define().Length]; var reservedGlobalIDs = new List <int>(); var reservedPlayerIDs = new List <int>(); for (int i = 0; i < DefinedVars.Length; i++) { DefinedVars[i] = new RuleDefineNode(context.rule_define(i), visitor); if (DefinedVars[i].OverrideID != -1) { (DefinedVars[i].IsGlobal ? reservedGlobalIDs : reservedPlayerIDs).Add(DefinedVars[i].OverrideID); } } ReservedGlobalIDs = reservedGlobalIDs.ToArray(); ReservedPlayerIDs = reservedPlayerIDs.ToArray(); // Get user methods UserMethods = new UserMethodBase[context.user_method().Length + context.macro().Length]; for (int i = 0; i < context.user_method().Length; i++) { UserMethods[i] = (UserMethodNode)visitor.VisitUser_method(context.user_method(i)); } // Get macros for (int i = 0; i < context.macro().Length; i++) { UserMethods[i + context.user_method().Length] = new MacroNode(context.macro(i), visitor); } // Get types DefinedTypes = new TypeDefineNode[context.type_define().Length]; for (int i = 0; i < DefinedTypes.Length; i++) { DefinedTypes[i] = (TypeDefineNode)visitor.VisitType_define(context.type_define(i)); } // Get reserved global variables if (context.reserved_global()?.reserved_list() != null) { ReservedGlobal = new ReservedNode(context.reserved_global().reserved_list(), visitor); } // Get reserved player variables if (context.reserved_player()?.reserved_list() != null) { ReservedPlayer = new ReservedNode(context.reserved_player().reserved_list(), visitor); } }
public static Rule GetRule(RuleNode ruleNode, ScopeGroup root, ParsingData parserData) { var result = new TranslateRule(ruleNode, root, parserData); return(result.Rule); }