override public Element Get(TranslateRule context, ScopeGroup scope, MethodNode methodNode, IWorkshopTree[] parameters) { Element result; if (!IsRecursive) { // Check the method stack if this method was already called. // Throw a syntax error if it was. if (context.MethodStackNotRecursive.Contains(this)) { throw SyntaxErrorException.RecursionNotAllowed(methodNode.Location); } var methodScope = scope.Root().Child(); // Add the parameter variables to the scope. context.AssignParameterVariables(methodScope, Parameters, parameters, methodNode); // The variable that stores the return value. IndexedVar returns = null; if (DoesReturn) { returns = IndexedVar.AssignVar(context.VarCollection, scope, $"{methodNode.Name} return", context.IsGlobal, null); returns.Type = Type; } // Add the method to the method stack context.MethodStackNotRecursive.Add(this); Block.RelatedScopeGroup = methodScope; // Parse the block of the method context.ParseBlock(methodScope, methodScope, Block, true, returns); // Take the method scope out of scope. methodScope.Out(context); // Remove the method from the stack. context.MethodStackNotRecursive.Remove(this); if (DoesReturn) { result = returns.GetVariable(); } else { result = new V_Null(); } } else { // Check the method stack if this method was already called. It will be null if it wasn't called. MethodStack lastMethod = context.MethodStackRecursive.FirstOrDefault(ms => ms.UserMethod == this); if (lastMethod != null) { context.ContinueSkip.Setup(); // Re-push the paramaters. for (int i = 0; i < lastMethod.ParameterVars.Length; i++) { if (lastMethod.ParameterVars[i] is RecursiveVar) { context.Actions.AddRange ( ((RecursiveVar)lastMethod.ParameterVars[i]).InScope((Element)parameters[i]) ); } } // Add to the continue skip array. context.Actions.AddRange( lastMethod.ContinueSkipArray.SetVariable( Element.Part <V_Append>(lastMethod.ContinueSkipArray.GetVariable(), new V_Number(context.ContinueSkip.GetSkipCount() + 3)) ) ); // Loop back to the start of the method. context.ContinueSkip.SetSkipCount(lastMethod.ActionIndex); context.Actions.Add(Element.Part <A_Loop>()); result = lastMethod.Return.GetVariable(); } else { var methodScope = scope.Root().Child(true); // Add the parameter variables to the scope. Var[] parameterVars = new Var[Parameters.Length]; for (int i = 0; i < parameterVars.Length; i++) { if (parameters[i] is Element) { // Create a new variable using the parameter input. parameterVars[i] = (RecursiveVar)IndexedVar.AssignVar(context.VarCollection, methodScope, Parameters[i].Name, context.IsGlobal, methodNode); ((RecursiveVar)parameterVars[i]).Type = ((Element)parameters[i]).SupportedType?.Type; context.Actions.AddRange ( ((RecursiveVar)parameterVars[i]).InScope((Element)parameters[i]) ); } else if (parameters[i] is EnumMember) { parameterVars[i] = new ElementReferenceVar(Parameters[i].Name, methodScope, methodNode, parameters[i]); } else { throw new NotImplementedException(); } } var returns = IndexedVar.AssignInternalVarExt(context.VarCollection, null, $"{methodNode.Name}: return", context.IsGlobal); returns.Type = Type; // Setup the continue skip array. IndexedVar continueSkipArray = IndexedVar.AssignInternalVar(context.VarCollection, null, $"{methodNode.Name} sca", context.IsGlobal); var stack = new MethodStack(this, parameterVars, context.ContinueSkip.GetSkipCount(), returns, continueSkipArray); // Add the method to the stack. context.MethodStackRecursive.Add(stack); Block.RelatedScopeGroup = methodScope; // Parse the method block context.ParseBlock(methodScope, methodScope, Block, true, returns); // No return value if the method is being used as an action. result = returns.GetVariable(); // Take the method out of scope. //Actions.AddRange(methodScope.RecursiveMethodStackPop()); methodScope.Out(context); // Setup the next continue skip. context.ContinueSkip.Setup(); context.ContinueSkip.SetSkipCount(Element.Part <V_LastOf>(continueSkipArray.GetVariable())); // Remove the last continue skip. context.Actions.AddRange( continueSkipArray.SetVariable( Element.Part <V_ArraySlice>( continueSkipArray.GetVariable(), new V_Number(0), Element.Part <V_CountOf>(continueSkipArray.GetVariable()) - 1 ) ) ); // Loop if the method goes any deeper by checking the length of the continue skip array. context.Actions.Add( Element.Part <A_LoopIf>( Element.Part <V_Compare>( Element.Part <V_CountOf>(continueSkipArray.GetVariable()), EnumData.GetEnumValue(Operators.NotEqual), new V_Number(0) ) ) ); // Reset the continue skip. context.ContinueSkip.ResetSkip(); context.Actions.AddRange(continueSkipArray.SetVariable(0)); // Remove the method from the stack. context.MethodStackRecursive.Remove(stack); } } return(result); }
public ParseExpressionTree(TranslateRule translator, ScopeGroup getter, ScopeGroup scope, Node root) { if (root is VariableNode) { VariableNode variableNode = (VariableNode)root; Var var = scope.GetVar(getter, ((VariableNode)root).Name, root.Location); ResultingVariable = var; //if (!ResultingVariable.Gettable()) throw SyntaxErrorException.CantReadVariable(ResultingVariable.Name, root.Location); if (ResultingVariable.Gettable()) { ResultingElement = var.GetVariable(); } VariableIndex = new Element[variableNode.Index.Length]; for (int i = 0; i < VariableIndex.Length; i++) { VariableIndex[i] = translator.ParseExpression(getter, scope, variableNode.Index[i]); } for (int i = 0; i < VariableIndex.Length; i++) { if (!ResultingVariable.Gettable()) { throw SyntaxErrorException.CantReadVariable(ResultingVariable.Name, root.Location); } ResultingElement = Element.Part <V_ValueInArray>(ResultingElement, VariableIndex[i]); } return; } if (root is ExpressionTreeNode == false) { throw new SyntaxErrorException("Error", root.Location); } List <Node> nodes = flatten((ExpressionTreeNode)root); ScopeGroup currentScope = scope; Element nodeResult = null; for (int index = 0; index < nodes.Count; index++) { if (nodes[index] is RootNode) { currentScope = translator.ParserData.Root; nodeResult = new V_Null(); } // If the node is a variable node, get the value. else if (nodes[index] is VariableNode) { VariableNode variableNode = (VariableNode)nodes[index]; Var var = currentScope.GetVar(getter, variableNode.Name, variableNode.Location); // If this is the last node, set the resulting var. if (index == nodes.Count - 1) { ResultingVariable = var; } // Get the variable index VariableIndex = new Element[variableNode.Index.Length]; for (int i = 0; i < VariableIndex.Length; i++) { VariableIndex[i] = translator.ParseExpression(getter, scope, variableNode.Index[i]); } // Set the nodeResult. nodeResult = var.GetVariable(Target); // Apply the index for (int i = 0; i < VariableIndex.Length; i++) { nodeResult = Element.Part <V_ValueInArray>(nodeResult, VariableIndex[i]); } } // If not, parse the node as an expression. else { nodeResult = translator.ParseExpression(getter, currentScope, nodes[index]); } // SupportedType will equal null if the element is not a defined type. if (nodeResult.SupportedType == null) { // If there is no supported type, assume the element or variable is containing a player. // Reset the scope. //currentScope = scope; currentScope = translator.ParserData.Root; // If this isn't the last node, set the target and reset the nodeResult. if (index < nodes.Count - 1) { Target = nodeResult; nodeResult = null; } } else { // Set the target scope to the type. currentScope = nodeResult.SupportedType.Type.GetRootScope(nodeResult, nodeResult.SupportedType, translator.ParserData, Target); } } ResultingElement = nodeResult; }