override public Element New(CreateObjectNode node, ScopeGroup getter, ScopeGroup scope, TranslateRule context) { // Get the index to store the class. IndexedVar index = context.VarCollection.AssignVar(scope, "New " + Name + " class index", context.IsGlobal, null); // Assigns the index variable. // Get the index of the next free spot in the class array. context.Actions.AddRange( index.SetVariable( Element.Part <V_IndexOfArrayValue>( WorkshopArrayBuilder.GetVariable(true, null, Variable.C), new V_Null() ) ) ); // Set the index to the count of the class array if the index equals -1. context.Actions.AddRange( index.SetVariable( Element.TernaryConditional( new V_Compare(index.GetVariable(), Operators.Equal, new V_Number(-1)), Element.Part <V_CountOf>( WorkshopArrayBuilder.GetVariable(true, null, Variable.C) ), index.GetVariable() ) ) ); // The direct reference to the class variable. IndexedVar store = new IndexedVar( scope, Name + " root", true, Variable.C, new Element[] { index.GetVariable() }, context.VarCollection.WorkshopArrayBuilder, null ); store.Index[0].SupportedType = store; store.Type = this; ScopeGroup typeScope = GetRootScope(store, context.ParserData); SetupNew(getter, scope, store, typeScope, context, node); return(index.GetVariable()); }
protected void SetupNew(ScopeGroup getter, ScopeGroup scope, IndexedVar store, ScopeGroup typeScope, TranslateRule context, CreateObjectNode node) { // Set the default variables in the struct for (int i = 0; i < DefinedVars.Length; i++) { if (DefinedVars[i].Value != null) { context.Actions.AddRange( store.SetVariable(context.ParseExpression(typeScope, typeScope, DefinedVars[i].Value), null, i) ); } } Constructor constructor = Constructors.FirstOrDefault(c => c.Parameters.Length == node.Parameters.Length); if (constructor == null) { throw SyntaxErrorException.NotAConstructor(TypeKind, Name, node.Parameters.Length, node.Location); } if (context.MethodStackNotRecursive.Contains(constructor)) { throw new SyntaxErrorException("Constructors cannot be recursive.", node.Location); } context.MethodStackNotRecursive.Add(constructor); ScopeGroup constructorScope = typeScope.Child(); IWorkshopTree[] parameters = context.ParseParameters( getter, scope, constructor.Parameters, node.Parameters, node.TypeName, node.Location ); context.AssignParameterVariables(constructorScope, constructor.Parameters, parameters, node); if (constructor.BlockNode != null) { context.ParseBlock(constructorScope, constructorScope, constructor.BlockNode, true, null); } constructorScope.Out(context); context.MethodStackNotRecursive.Remove(constructor); }
public void Setup() { if (IsSetup) { return; } IsSetup = true; SkipCount = VarCollection.AssignVar(null, "ContinueSkip", IsGlobal, null); TempHolder = VarCollection.AssignVar(null, "ContinueSkip temp holder", IsGlobal, null); A_Wait waitAction = A_Wait.MinimumWait; waitAction.Comment = "ContinueSkip Wait"; A_SkipIf skipAction = Element.Part <A_SkipIf> ( // Condition Element.Part <V_Compare>(SkipCount.GetVariable(), EnumData.GetEnumValue(Operators.Equal), new V_Number(0)), // Number of actions new V_Number(3) ); skipAction.Comment = "ContinueSkip Skipper"; Element[] actions = ArrayBuilder <Element> .Build( waitAction, skipAction, TempHolder.SetVariable(SkipCount.GetVariable()), SkipCount.SetVariable(new V_Number(0)), Element.Part <A_Skip>(TempHolder.GetVariable()) ); if (actions.Length != ExpectedActionCount) { throw new Exception($"Expected {ExpectedActionCount} actions for the Continue Skip, got {actions.Length} instead."); } Actions.InsertRange(0, actions); }
public Element[] SetSkipCountActions(int number) { return(SkipCount.SetVariable(new V_Number(number))); }
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); }
override public Element New(CreateObjectNode node, ScopeGroup getter, ScopeGroup scope, TranslateRule context) { context.ParserData.SetupClasses(); // Get the index to store the class. IndexedVar index = IndexedVar.AssignInternalVarExt(context.VarCollection, scope, "New " + Name + " class index", context.IsGlobal); // Assigns the index variable. Element takenIndexes = context.ParserData.ClassIndexes.GetVariable(); // Get an empty index in the class array to store the new class. Element firstFree = ( Element.Part <V_FirstOf>( Element.Part <V_FilteredArray>( // Sort the taken index array. Element.Part <V_SortedArray>(takenIndexes, new V_ArrayElement()), // Filter Element.Part <V_And>( // If the previous index was not taken, use that index. !(Element.Part <V_ArrayContains>( takenIndexes, new V_ArrayElement() - 1 )), // Make sure the index does not equal 0 so the resulting index is not -1. new V_Compare(new V_ArrayElement(), Operators.NotEqual, new V_Number(0)) ) ) ) - 1 // Subtract 1 to get the previous index ); // If the taken index array has 0 elements, just use the length of the class array subtracted by 1. firstFree = Element.TernaryConditional( new V_Compare(Element.Part <V_CountOf>(takenIndexes), Operators.NotEqual, new V_Number(0)), firstFree, Element.Part <V_CountOf>(context.ParserData.ClassArray.GetVariable()) - 1 ); context.Actions.AddRange(index.SetVariable(firstFree)); context.Actions.AddRange( index.SetVariable( Element.TernaryConditional( // If the index equals -1, use the length of the class array instead. new V_Compare(index.GetVariable(), Operators.Equal, new V_Number(-1)), Element.Part <V_CountOf>(context.ParserData.ClassArray.GetVariable()), index.GetVariable() ) ) ); // Add the selected index to the taken indexes array. context.Actions.AddRange( context.ParserData.ClassIndexes.SetVariable( Element.Part <V_Append>( context.ParserData.ClassIndexes.GetVariable(), index.GetVariable() ) ) ); // The direct reference to the class variable. IndexedVar store = context.ParserData.ClassArray.CreateChild(scope, Name + " root", new Element[] { index.GetVariable() }, null); store.Index[0].SupportedType = store; store.Type = this; ScopeGroup typeScope = GetRootScope(index.GetVariable(), store, context.ParserData); SetupNew(getter, scope, store, typeScope, context, node); return(index.GetVariable()); }
void ParseVarset(ScopeGroup getter, ScopeGroup scope, VarSetNode varSetNode) { var varSetData = new ParseExpressionTree(this, getter, scope, varSetNode.Variable); if (!(varSetData.ResultingVariable is IndexedVar)) { throw SyntaxErrorException.VariableIsReadonly(varSetData.ResultingVariable.Name, varSetNode.Location); } IndexedVar variable = (IndexedVar)varSetData.ResultingVariable; Element[] index = varSetData.VariableIndex; Element value = null; if (varSetNode.Value != null) { value = ParseExpression(getter, scope, varSetNode.Value); } Element initialVar = variable.GetVariable(varSetData.Target); Operation?operation = null; switch (varSetNode.Operation) { case "+=": operation = Operation.Add; break; case "-=": operation = Operation.Subtract; break; case "*=": operation = Operation.Multiply; break; case "/=": operation = Operation.Divide; break; case "^=": operation = Operation.RaiseToPower; break; case "%=": operation = Operation.Modulo; break; case "++": operation = Operation.Add; value = 1; break; case "--": operation = Operation.Subtract; value = 1; break; } if (operation == null) { Actions.AddRange(variable.SetVariable(value, varSetData.Target, index)); } else { Actions.AddRange(variable.ModifyVariable((Operation)operation, value, varSetData.Target, index)); } }
void ParseStatement(ScopeGroup getter, ScopeGroup scope, Node statement, IndexedVar returnVar) { switch (statement) { // Method case MethodNode methodNode: Element method = ParseMethod(getter, scope, methodNode, false); return; // Variable set case VarSetNode varSetNode: ParseVarset(getter, scope, varSetNode); return; // Foreach case ForEachNode forEachNode: { ContinueSkip.Setup(); ScopeGroup forGroup = scope.Child(); Element array = ParseExpression(getter, scope, forEachNode.Array); IndexedVar index = IndexedVar.AssignInternalVarExt(VarCollection, scope, $"'{forEachNode.Variable.VariableName}' for index", IsGlobal); int offset = 0; Element getVariableReference() { return(Element.Part <V_ValueInArray>(array, indexer())); } Element indexer() { if (offset == 0) { return(index.GetVariable()); } else { return(index.GetVariable() + getOffset()); } } V_Number getOffset() { return(new V_Number(offset)); } IndexedVar arrayVar = null; ElementOrigin origin = ElementOrigin.GetElementOrigin(array); if (origin == null && forEachNode.Variable.Type != null) { throw new SyntaxErrorException("Could not get the type source.", forEachNode.Variable.Location); } if (origin != null) { arrayVar = origin.OriginVar(VarCollection, null, null); } // Reset the counter. Actions.AddRange(index.SetVariable(0)); // The action the for loop starts on. int forStartIndex = ContinueSkip.GetSkipCount(); A_SkipIf skipCondition = new A_SkipIf() { ParameterValues = new IWorkshopTree[2] }; skipCondition.ParameterValues[0] = !(index.GetVariable() < Element.Part <V_CountOf>(array) ); Actions.Add(skipCondition); List <A_SkipIf> rangeSkips = new List <A_SkipIf>(); for (; offset < forEachNode.Repeaters; offset++) { if (offset > 0) { //variable.Reference = getVariableReference(); A_SkipIf skipper = new A_SkipIf() { ParameterValues = new Element[2] }; skipper.ParameterValues[0] = !( index.GetVariable() + getOffset() < Element.Part <V_CountOf>(array) ); rangeSkips.Add(skipper); Actions.Add(skipper); } // Parse the for's block. Use a child to prevent conflicts with repeaters. ScopeGroup tempChild = forGroup.Child(); Var variable; if (arrayVar != null) { variable = arrayVar.CreateChild(tempChild, forEachNode.Variable.VariableName, new Element[] { indexer() }, forEachNode.Variable); if (forEachNode.Variable.Type != null) { variable.Type = ParserData.GetDefinedType(forEachNode.Variable.Type, forEachNode.Variable.Location); } } else { variable = new ElementReferenceVar(forEachNode.Variable.VariableName, tempChild, forEachNode, getVariableReference()); } ParseBlock(tempChild, tempChild, forEachNode.Block, false, returnVar); tempChild.Out(this); } // Take the foreach out of scope. forGroup.Out(this); // Increment the index Actions.AddRange(index.SetVariable(index.GetVariable() + forEachNode.Repeaters)); // Add the for's finishing elements ContinueSkip.SetSkipCount(forStartIndex); Actions.Add(Element.Part <A_Loop>()); rangeSkips.ForEach(var => var.ParameterValues[1] = new V_Number(GetSkipCount(var))); // Set the skip if (skipCondition != null) { skipCondition.ParameterValues[1] = new V_Number(GetSkipCount(skipCondition)); } ContinueSkip.ResetSkip(); return; } // For case ForNode forNode: { ContinueSkip.Setup(); ScopeGroup forContainer = scope.Child(); // Set the variable if (forNode.VarSetNode != null) { ParseVarset(getter, scope, forNode.VarSetNode); } if (forNode.DefineNode != null) { ParseDefine(getter, forContainer, forNode.DefineNode); } ScopeGroup forGroup = forContainer.Child(); // The action the for loop starts on. int forStartIndex = ContinueSkip.GetSkipCount(); A_SkipIf skipCondition = null; // Skip if the condition is false. if (forNode.Expression != null) // If it has an expression { skipCondition = new A_SkipIf() { ParameterValues = new IWorkshopTree[2] }; skipCondition.ParameterValues[0] = !(ParseExpression(forGroup, forGroup, forNode.Expression)); Actions.Add(skipCondition); } // Parse the for's block. ParseBlock(forGroup, forGroup, forNode.Block, false, returnVar); // Parse the statement if (forNode.Statement != null) { ParseVarset(forGroup, forGroup, forNode.Statement); } // Take the for out of scope. forGroup.Out(this); ContinueSkip.SetSkipCount(forStartIndex); Actions.Add(Element.Part <A_Loop>()); // Set the skip if (skipCondition != null) { skipCondition.ParameterValues[1] = new V_Number(GetSkipCount(skipCondition)); } // Take the defined variable in the for out of scope forContainer.Out(this); ContinueSkip.ResetSkip(); return; } // While case WhileNode whileNode: { ContinueSkip.Setup(); // The action the while loop starts on. int whileStartIndex = ContinueSkip.GetSkipCount(); A_SkipIf skipCondition = new A_SkipIf() { ParameterValues = new IWorkshopTree[2] }; skipCondition.ParameterValues[0] = !(ParseExpression(getter, scope, whileNode.Expression)); Actions.Add(skipCondition); ScopeGroup whileGroup = scope.Child(); ParseBlock(whileGroup, whileGroup, whileNode.Block, false, returnVar); // Take the while out of scope. whileGroup.Out(this); ContinueSkip.SetSkipCount(whileStartIndex); Actions.Add(Element.Part <A_Loop>()); skipCondition.ParameterValues[1] = new V_Number(GetSkipCount(skipCondition)); ContinueSkip.ResetSkip(); return; } // If case IfNode ifNode: { A_SkipIf if_SkipIf = new A_SkipIf() { ParameterValues = new IWorkshopTree[2] }; if_SkipIf.ParameterValues[0] = !(ParseExpression(getter, scope, ifNode.IfData.Expression)); Actions.Add(if_SkipIf); var ifScope = scope.Child(); // Parse the if body. ParseBlock(ifScope, ifScope, ifNode.IfData.Block, false, returnVar); // Take the if out of scope. ifScope.Out(this); // Determines if the "Skip" action after the if block will be created. // Only if there is if-else or else statements. bool addIfSkip = ifNode.ElseIfData.Length > 0 || ifNode.ElseBlock != null; // Create the "Skip" action. A_Skip if_Skip = new A_Skip(); if (addIfSkip) { Actions.Add(if_Skip); } // Update the initial SkipIf's skip count now that we know the number of actions the if block has. if_SkipIf.ParameterValues[1] = new V_Number(GetSkipCount(if_SkipIf)); // Parse else-ifs A_Skip[] elseif_Skips = new A_Skip[ifNode.ElseIfData.Length]; // The ElseIf's skips for (int i = 0; i < ifNode.ElseIfData.Length; i++) { // Create the SkipIf action for the else if. A_SkipIf elseif_SkipIf = new A_SkipIf() { ParameterValues = new IWorkshopTree[2] }; elseif_SkipIf.ParameterValues[0] = !(ParseExpression(getter, scope, ifNode.ElseIfData[i].Expression)); Actions.Add(elseif_SkipIf); // Parse the else-if body. var elseifScope = scope.Child(); ParseBlock(elseifScope, elseifScope, ifNode.ElseIfData[i].Block, false, returnVar); // Take the else-if out of scope. elseifScope.Out(this); // 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 < ifNode.ElseIfData.Length - 1 || ifNode.ElseBlock != null; // Create the "Skip" action for the else-if. if (addIfElseSkip) { elseif_Skips[i] = new A_Skip(); Actions.Add(elseif_Skips[i]); } // Set the SkipIf's parameters. elseif_SkipIf.ParameterValues[1] = new V_Number(GetSkipCount(elseif_SkipIf)); } // Parse else body. if (ifNode.ElseBlock != null) { var elseScope = scope.Child(); ParseBlock(elseScope, elseScope, ifNode.ElseBlock, false, returnVar); // Take the else out of scope. elseScope.Out(this); } // 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 (addIfSkip) { if_Skip.ParameterValues = new IWorkshopTree[] { new V_Number(GetSkipCount(if_Skip)) } } ; // Replace else-if's dummy. for (int i = 0; i < elseif_Skips.Length; i++) { if (elseif_Skips[i] != null) { elseif_Skips[i].ParameterValues = new IWorkshopTree[] { new V_Number(GetSkipCount(elseif_Skips[i])) }; } } return; } // Return case ReturnNode returnNode: if (returnNode.Value != null) { Element result = ParseExpression(getter, scope, returnNode.Value); if (returnVar != null) { Actions.AddRange(returnVar.SetVariable(result)); } } A_Skip returnSkip = new A_Skip(); Actions.Add(returnSkip); Actions.Add(Element.Part <A_Skip>(new V_Number(-1))); ReturnSkips.Add(returnSkip); return; case DeleteNode deleteNode: DefinedClass.Delete(ParseExpression(getter, scope, deleteNode.Delete), this); return; // Define case DefineNode defineNode: ParseDefine(getter, scope, defineNode); return; case ExpressionTreeNode expressionTree: new ParseExpressionTree(this, getter, scope, expressionTree); return; default: throw new SyntaxErrorException("Expected statement.", statement.Location); } }