Exemple #1
0
        public static IndexedVar AssignVarExt(VarCollection collection, ScopeGroup scope, string name, bool isGlobal, Node node)
        {
            int        index = collection.NextFreeExtended(isGlobal);
            IndexedVar var   = CreateVar(
                collection.WorkshopArrayBuilder,
                scope,
                name,
                isGlobal,
                collection.UseVariable(isGlobal),
                new Element[] { new V_Number(index) },
                node
                );

            collection.AllVars.Add(var);
            collection.UseExtendedCollection(isGlobal)[index] = var;
            return(var);
        }
        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());
        }
Exemple #3
0
        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);
        }
Exemple #4
0
        // Get This was an Australian radio comedy show which aired on Triple M and was hosted
        // by Tony Martin and Ed Kavalee, with contributions from panel operator, Richard Marsland.
        // A different guest co-host was featured nearly every day on the show and included music played throughout.
        // On the 15 October 2007 episode, the Get This team announced that Triple M/Austereo would not be renewing the show for 2008.
        // The final broadcast was on 23 November 2007. During its lifetime and since its cancellation, Get This developed a strong cult following.
        public Element GetThis(Location errorLocation)
        {
            ScopeGroup check = this;
            Element    @this = null;

            while (check != null && @this == null)
            {
                @this = check.This;
                check = check.Parent;
            }

            if (errorLocation != null && @this == null)
            {
                throw SyntaxErrorException.ThisCantBeUsed(errorLocation);
            }

            return(@this);
        }
        public DefinedVar GetVar(string name, Range range, List <Diagnostic> diagnostics)
        {
            DefinedVar var        = null;
            ScopeGroup checkGroup = this;

            while (var == null && checkGroup != null)
            {
                var        = checkGroup.InScope.FirstOrDefault(v => v.Name == name);
                checkGroup = checkGroup.Parent;
            }

            if (var == null && range != null && diagnostics != null)
            {
                throw SyntaxErrorException.VariableDoesNotExist(name, range);
            }

            return(var);
        }
        public IWorkshopTree[] ParsePickyParameters(ScopeGroup getter, ScopeGroup scope, ParameterBase[] parameters, PickyParameter[] values, string methodName, LanguageServer.Location methodRange)
        {
            for (int f = 0; f < values.Length; f++)
            {
                // Syntax error if the parameter does not exist.
                if (!parameters.Any(param => param.Name.Replace(" ", "") == values[f].Name))
                {
                    throw new SyntaxErrorException(values[f].Name + " is not a parameter in the method " + methodName + ".", values[f].Location);
                }

                // Check if there are any duplicates.
                for (int n = 0; n < values.Length; n++)
                {
                    if (f != n && values[f].Name == values[n].Name)
                    {
                        int use = Math.Max(f, n);
                        throw new SyntaxErrorException(values[use].Name + " was already set.", values[use].Location);
                    }
                }
            }

            // Parse the parameters
            List <IWorkshopTree> parsedParameters = new List <IWorkshopTree>();

            for (int i = 0; i < parameters.Length; i++)
            {
                PickyParameter setter = values.FirstOrDefault(value => value.Name == parameters[i].Name.Replace(" ", ""));

                IWorkshopTree result;

                if (setter == null)
                {
                    result = GetDefaultValue(parameters[i], methodName, methodRange);
                }
                else
                {
                    result = parameters[i].Parse(this, getter, scope, setter.Expression);
                }

                parsedParameters.Add(result);
            }

            return(parsedParameters.ToArray());
        }
Exemple #7
0
        public ScopeGroup GetRootScope(Element reference, IndexedVar var, ParsingData parseData, Element target = null)
        {
            if (target == null)
            {
                target = new V_EventPlayer();
            }

            IndexedVar root = GetRoot(var, parseData, target);

            root.DefaultTarget = target;

            ScopeGroup typeScope = new ScopeGroup(parseData.VarCollection);

            if (reference == null)
            {
                typeScope.This = root.GetVariable();
            }
            else
            {
                typeScope.This = reference;
                typeScope.This.SupportedType = root;
            }

            for (int i = 0; i < DefinedVars.Length; i++)
            {
                IndexedVar newVar = root.CreateChild(typeScope, DefinedVars[i].VariableName, Element.IntToElement(i), DefinedVars[i]);
                newVar.DefaultTarget = target;
                if (DefinedVars[i].Type != null)
                {
                    newVar.Type = parseData.GetDefinedType(DefinedVars[i].Type, DefinedVars[i].Location);
                }
                newVar.AccessLevel = DefinedVars[i].AccessLevel;
            }

            for (int i = 0; i < MethodNodes.Length; i++)
            {
                UserMethod method = UserMethod.CreateUserMethod(typeScope, MethodNodes[i]);
                method.RegisterParameters(parseData);
                method.AccessLevel = MethodNodes[i].AccessLevel;
            }

            return(typeScope);
        }
        void ParseConditions(ScopeGroup scope, Node[] expressions)
        {
            foreach (var expr in expressions)
            {
                Element parsedIf = ParseExpression(scope, scope, 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, expr.Location);
                    }

                    Element right = (Element)parsedIf.ParameterValues[2];
                    if (!right.ElementData.IsValue)
                    {
                        throw SyntaxErrorException.InvalidMethodType(true, right.Name, expr.Location);
                    }

                    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, expr.Location);
                    }

                    Conditions.Add(new Condition(
                                       parsedIf, EnumData.GetEnumValue(Operators.Equal), new V_True()
                                       ));
                }
            }
        }
        public void ParseBlock(ScopeGroup getter, ScopeGroup scopeGroup, BlockNode blockNode, bool fulfillReturns, IndexedVar returnVar)
        {
            if (scopeGroup == null)
            {
                throw new ArgumentNullException(nameof(scopeGroup));
            }

            blockNode.RelatedScopeGroup = scopeGroup;

            int returnSkipStart = ReturnSkips.Count;

            for (int i = 0; i < blockNode.Statements.Length; i++)
            {
                ParseStatement(getter, scopeGroup, blockNode.Statements[i], returnVar);
            }

            if (fulfillReturns)
            {
                FulfillReturns(returnSkipStart);
            }
        }
Exemple #10
0
        public static IndexedVar AssignVar(VarCollection collection, ScopeGroup scope, string name, bool isGlobal, WorkshopVariable variable, Node node)
        {
            string workshopName = variable.Name;

            if (workshopName == null)
            {
                workshopName = collection.WorkshopNameFromCodeName(isGlobal, name);
            }

            int id = variable.ID;

            if (id == -1)
            {
                id = collection.NextFree(isGlobal);
            }
            else
            {
                WorkshopVariable assigned = collection.FromID(isGlobal, variable.ID);
                if (assigned != null)
                {
                    throw new SyntaxErrorException("Variable ID '" + variable.ID + "' has already been assigned by '" + assigned.Name + "'.", node.Location);
                }
            }

            WorkshopVariable use = new WorkshopVariable(isGlobal, id, workshopName);

            IndexedVar var = CreateVar(
                collection.WorkshopArrayBuilder,
                scope,
                name,
                isGlobal,
                use,
                null,
                node
                );

            collection.AllVars.Add(var);
            collection.UseCollection(isGlobal)[id] = use;
            return(var);
        }
        public UserMethodBlock(ScopeGroup scope, UserMethodNode node) : base(scope, node)
        {
            List <ReturnNode> returnNodes = new List <ReturnNode>();

            ReturnNodes(node.Block, returnNodes);
            DoesReturn = node.Type != null || returnNodes.Any(returnNode => returnNode.Value != null);
            if (DoesReturn)
            {
                foreach (var returnNode in returnNodes)
                {
                    if (returnNode.Value == null)
                    {
                        throw new SyntaxErrorException("A return value is required.", returnNode.Location);
                    }
                }
                CheckContainer((IBlockContainer)node);
            }

            Block       = node.Block;
            IsRecursive = node.IsRecursive;
            TypeString  = node.Type;
        }
        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();
        }
Exemple #13
0
        private bool IsAlreadyDefined(string name)
        {
            int        index = 0;
            ScopeGroup check = this;

            while (check != null)
            {
                if (check.This != null && index > 0)
                {
                    return(false);
                }

                if (check.InScope.Any(v => v.Name == name))
                {
                    return(true);
                }

                index++;
                check = check.Parent;
            }

            return(false);
        }
Exemple #14
0
 private ScopeGroup(VarCollection varCollection, ScopeGroup parent, bool recursive) : this(varCollection)
 {
     Parent    = parent;
     Recursive = recursive;
 }
 public Macro(ScopeGroup scope, MacroNode node) : base(scope, node)
 {
     Expression = node.Expression;
     TypeString = null;
 }
        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);
            }
        }
Exemple #17
0
 private ScopeGroup(VarCollection varCollection, ScopeGroup parent) : this(varCollection)
 {
     Parent    = parent;
     Recursive = parent.Recursive;
 }
 private ScopeGroup(ScopeGroup parent)
 {
     Parent = parent;
 }
        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));
            }
        }
Exemple #20
0
        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);
        }
Exemple #21
0
        void ParseStatement(ScopeGroup scope, IStatementNode statement, Var returnVar, bool isLast)
        {
            switch (statement)
            {
            // Method
            case MethodNode methodNode:
                Element method = ParseMethod(scope, methodNode, false);
                if (method != null)
                {
                    Actions.Add(method);
                }
                return;

            // Variable set
            case VarSetNode varSetNode:
                ParseVarset(scope, varSetNode);
                return;

            // For
            case ForEachNode forEachNode:
            {
                ContinueSkip.Setup();

                // The action the for loop starts on.
                int forActionStartIndex = Actions.Count() - 1;

                ScopeGroup forGroup = scope.Child();

                // Create the for's temporary variable.
                DefinedVar forTempVar = VarCollection.AssignDefinedVar(
                    scopeGroup: forGroup,
                    name: forEachNode.Variable,
                    isGlobal: IsGlobal,
                    range: forEachNode.Range
                    );

                // Reset the counter.
                Actions.Add(forTempVar.SetVariable(new V_Number(0)));

                // Parse the for's block.
                ParseBlock(forGroup, forEachNode.Block, false, returnVar);

                // Add the for's finishing elements
                Actions.Add(forTempVar.SetVariable(     // Indent the index by 1.
                                Element.Part <V_Add>
                                (
                                    forTempVar.GetVariable(),
                                    new V_Number(1)
                                )
                                ));

                ContinueSkip.SetSkipCount(forActionStartIndex);

                // The target array in the for statement.
                Element forArrayElement = ParseExpression(scope, forEachNode.Array);

                Actions.Add(Element.Part <A_LoopIf>(    // Loop if the for condition is still true.
                                Element.Part <V_Compare>
                                (
                                    forTempVar.GetVariable(),
                                    EnumData.GetEnumValue(Operators.LessThan),
                                    Element.Part <V_CountOf>(forArrayElement)
                                )
                                ));

                ContinueSkip.ResetSkip();
                return;
            }

            // For
            case ForNode forNode:
            {
                ContinueSkip.Setup();

                // The action the for loop starts on.
                int forActionStartIndex = Actions.Count() - 1;

                ScopeGroup forGroup = scope.Child();

                // Set the variable
                if (forNode.VarSetNode != null)
                {
                    ParseVarset(scope, forNode.VarSetNode);
                }
                if (forNode.DefineNode != null)
                {
                    ParseDefine(scope, forNode.DefineNode);
                }

                // Parse the for's block.
                ParseBlock(forGroup, forNode.Block, false, returnVar);

                Element expression = null;
                if (forNode.Expression != null)
                {
                    expression = ParseExpression(forGroup, forNode.Expression);
                }

                // Check the expression
                if (forNode.Expression != null)     // If it has an expression
                {
                    // Parse the statement
                    if (forNode.Statement != null)
                    {
                        ParseStatement(forGroup, forNode.Statement, returnVar, false);
                    }

                    ContinueSkip.SetSkipCount(forActionStartIndex);
                    Actions.Add(Element.Part <A_LoopIf>(expression));
                }
                // If there is no expression but there is a statement, parse the statement.
                else if (forNode.Statement != null)
                {
                    ParseStatement(forGroup, forNode.Statement, returnVar, false);
                    ContinueSkip.SetSkipCount(forActionStartIndex);
                    // Add the loop
                    Actions.Add(Element.Part <A_Loop>());
                }

                ContinueSkip.ResetSkip();
                return;
            }

            // While
            case WhileNode whileNode:
            {
                ContinueSkip.Setup();

                // The action the while loop starts on.
                int whileStartIndex = Actions.Count() - 2;

                ScopeGroup whileGroup = scope.Child();

                ParseBlock(whileGroup, whileNode.Block, false, returnVar);

                ContinueSkip.SetSkipCount(whileStartIndex);

                // Add the loop-if
                Element expression = ParseExpression(scope, whileNode.Expression);
                Actions.Add(Element.Part <A_LoopIf>(expression));

                ContinueSkip.ResetSkip();
                return;
            }

            // If
            case IfNode ifNode:
            {
                A_SkipIf if_SkipIf = new A_SkipIf();
                Actions.Add(if_SkipIf);

                var ifScope = scope.Child();

                // Parse the if body.
                ParseBlock(ifScope, ifNode.IfData.Block, false, returnVar);

                // 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;

                // Update the initial SkipIf's skip count now that we know the number of actions the if block has.
                // Add one to the body length if a Skip action is going to be added.
                if_SkipIf.ParameterValues = new IWorkshopTree[]
                {
                    Element.Part <V_Not>(ParseExpression(scope, ifNode.IfData.Expression)),
                    new V_Number(Actions.Count - 1 - Actions.IndexOf(if_SkipIf) + (addIfSkip ? 1 : 0))
                };

                // Create the "Skip" action.
                A_Skip if_Skip = new A_Skip();
                if (addIfSkip)
                {
                    Actions.Add(if_Skip);
                }

                // 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();
                    Actions.Add(elseif_SkipIf);

                    // Parse the else-if body.
                    var elseifScope = scope.Child();
                    ParseBlock(elseifScope, ifNode.ElseIfData[i].Block, false, returnVar);

                    // 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;

                    // Set the SkipIf's parameters.
                    elseif_SkipIf.ParameterValues = new IWorkshopTree[]
                    {
                        Element.Part <V_Not>(ParseExpression(scope, ifNode.ElseIfData[i].Expression)),
                        new V_Number(Actions.Count - 1 - Actions.IndexOf(elseif_SkipIf) + (addIfElseSkip ? 1 : 0))
                    };

                    // Create the "Skip" action for the else-if.
                    if (addIfElseSkip)
                    {
                        elseif_Skips[i] = new A_Skip();
                        Actions.Add(elseif_Skips[i]);
                    }
                }

                // Parse else body.
                if (ifNode.ElseBlock != null)
                {
                    var elseScope = scope.Child();
                    ParseBlock(elseScope, ifNode.ElseBlock, false, returnVar);
                }

                // 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_Skip.ParameterValues = new IWorkshopTree[]
                {
                    new V_Number(Actions.Count - 1 - Actions.IndexOf(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(Actions.Count - 1 - Actions.IndexOf(elseif_Skips[i]))
                        };
                    }
                }

                return;
            }

            // Return
            case ReturnNode returnNode:

                if (returnNode.Value != null)
                {
                    Element result = ParseExpression(scope, returnNode.Value);
                    if (returnVar != null)
                    {
                        Actions.Add(returnVar.SetVariable(result));
                    }
                }

                if (!isLast)
                {
                    A_Skip returnSkip = new A_Skip();
                    Actions.Add(returnSkip);
                    ReturnSkips.Add(returnSkip);
                }

                return;

            // Define
            case ScopedDefineNode defineNode:
                ParseDefine(scope, defineNode);
                return;
            }
        }
Exemple #22
0
        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()));
        }
Exemple #23
0
        public static ParserData GetParser(string document, Pos documentPos)
        {
            AntlrInputStream inputStream = new AntlrInputStream(document);

            // Lexer
            DeltinScriptLexer lexer             = new DeltinScriptLexer(inputStream);
            CommonTokenStream commonTokenStream = new CommonTokenStream(lexer);

            // Parse
            DeltinScriptParser parser = new DeltinScriptParser(commonTokenStream);
            var errorListener         = new ErrorListener();

            parser.RemoveErrorListeners();
            parser.AddErrorListener(errorListener);

            DeltinScriptParser.RulesetContext ruleSetContext = parser.ruleset();

            List <Diagnostic> diagnostics = new List <Diagnostic>();

            diagnostics.AddRange(errorListener.Errors);

            // Get the ruleset node.
            BuildAstVisitor bav         = null;
            RulesetNode     ruleSetNode = null;

            if (diagnostics.Count == 0)
            {
                bav         = new BuildAstVisitor(documentPos, diagnostics);
                ruleSetNode = (RulesetNode)bav.Visit(ruleSetContext);
            }

            VarCollection     varCollection = null;
            ScopeGroup        root          = null;
            List <UserMethod> userMethods   = null;

            Rule[] rules   = null;
            bool   success = false;

            AdditionalErrorChecking aec = new AdditionalErrorChecking(parser, diagnostics);

            aec.Visit(ruleSetContext);

            bool parse = diagnostics.Count == 0;

            if (parse)
            {
                varCollection = new VarCollection();
                root          = new ScopeGroup();
                userMethods   = new List <UserMethod>();

                foreach (var definedVar in ruleSetNode.DefinedVars)
                {
                    varCollection.AssignDefinedVar(root, definedVar.IsGlobal, definedVar.VariableName, definedVar.Range);
                }

                // Get the user methods.
                for (int i = 0; i < ruleSetNode.UserMethods.Length; i++)
                {
                    userMethods.Add(new UserMethod(ruleSetNode.UserMethods[i]));
                }

                // Parse the rules.
                rules = new Rule[ruleSetNode.Rules.Length];

                for (int i = 0; i < rules.Length; i++)
                {
                    try
                    {
                        var result = Translate.GetRule(ruleSetNode.Rules[i], root, varCollection, userMethods.ToArray());
                        rules[i] = result.Rule;
                        diagnostics.AddRange(result.Diagnostics);
                    }
                    catch (SyntaxErrorException ex)
                    {
                        diagnostics.Add(new Diagnostic(ex.Message, ex.Range)
                        {
                            severity = Diagnostic.Error
                        });
                    }
                }

                success = true;
            }

            return(new ParserData()
            {
                Parser = parser,
                RulesetContext = ruleSetContext,
                RuleSetNode = ruleSetNode,
                Bav = bav,
                Diagnostics = diagnostics,
                Rules = rules,
                UserMethods = userMethods?.ToArray(),
                Root = root,
                Success = success,
                VarCollection = varCollection
            });
        }
Exemple #24
0
        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());
        }
 abstract public Element New(CreateObjectNode node, ScopeGroup getter, ScopeGroup scope, TranslateRule context);
Exemple #26
0
        private void GetObjects(string document, string file, TranslateRule globalTranslate, TranslateRule playerTranslate, bool isRoot)
        {
            // If this file was already loaded, don't load it again.
            if (Imported.Contains(file))
            {
                return;
            }
            Imported.Add(file);
            Diagnostics.AddFile(file);

            // Get the ruleset.
            RulesetNode ruleset = GetRuleset(file, document);

            Rulesets.Add(file, ruleset);

            if (ruleset != null && !Diagnostics.ContainsErrors())
            {
                if (isRoot)
                {
                    VarCollection = new VarCollection(ruleset.UseGlobalVar, ruleset.UsePlayerVar, ruleset.UseBuilderVar);
                    Root          = new ScopeGroup(VarCollection);
                }

                // Get the defined types
                foreach (var definedType in ruleset.DefinedTypes)
                {
                    try
                    {
                        if (DefinedTypes.Any(type => type.Name == definedType.Name))
                        {
                            throw SyntaxErrorException.NameAlreadyDefined(definedType.Location);
                        }
                        DefinedTypes.Add(DefinedType.GetDefinedType(definedType));
                    }
                    catch (SyntaxErrorException ex)
                    {
                        Diagnostics.Error(ex);
                    }
                }

                // Get the user methods.
                for (int i = 0; i < ruleset.UserMethods.Length; i++)
                {
                    try
                    {
                        UserMethods.Add(new UserMethod(Root, ruleset.UserMethods[i]));
                    }
                    catch (SyntaxErrorException ex)
                    {
                        Diagnostics.Error(ex);
                    }
                }

                // Get the rules
                RuleNodes.AddRange(ruleset.Rules);

                List <string> importedFiles = new List <string>();

                foreach (ImportObjectNode importObject in ruleset.ObjectImports)
                {
                    try
                    {
                        Importer importer = new Importer(Diagnostics, importedFiles, importObject.File, file, importObject.Location);
                        if (!importer.AlreadyImported)
                        {
                            importedFiles.Add(importer.ResultingPath);
                            string content = importer.GetFile();
                            switch (importer.FileType)
                            {
                            case ".obj":
                                Model newModel = Model.ImportObj(content);
                                new ModelVar(importObject.Name, Root, importObject, newModel);
                                break;
                            }
                        }
                    }
                    catch (SyntaxErrorException ex)
                    {
                        Diagnostics.Error(ex);
                    }
                }

                // Check the imported files.
                foreach (ImportNode importNode in ruleset.Imports)
                {
                    try
                    {
                        Importer importer = new Importer(Diagnostics, importedFiles, importNode.File, file, importNode.Location);
                        if (!importer.AlreadyImported)
                        {
                            string content = File.ReadAllText(importer.ResultingPath);
                            GetObjects(content, importer.ResultingPath, globalTranslate, playerTranslate, false);
                            importedFiles.Add(importer.ResultingPath);
                        }
                    }
                    catch (SyntaxErrorException ex)
                    {
                        Diagnostics.Error(ex);
                    }
                }

                // Get the variables
                foreach (var definedVar in ruleset.DefinedVars)
                {
                    try
                    {
                        IndexedVar var;
                        if (definedVar.UseVar == null)
                        {
                            var = VarCollection.AssignVar(Root, definedVar.VariableName, definedVar.IsGlobal, definedVar);
                        }
                        else
                        {
                            var = VarCollection.AssignVar(
                                Root,
                                definedVar.VariableName,
                                definedVar.IsGlobal,
                                definedVar.UseVar.Variable,
                                definedVar.UseVar.Index,
                                definedVar
                                );
                        }
                        if (definedVar.Type != null)
                        {
                            var.Type = GetDefinedType(definedVar.Type, definedVar.Location);
                        }
                    }
                    catch (SyntaxErrorException ex)
                    {
                        Diagnostics.Error(ex);
                    }
                }
            }
        }
        private ParsingData(string file, string content)
        {
            Rule initialGlobalValues = new Rule(Constants.INTERNAL_ELEMENT + "Initial Global Values");
            Rule initialPlayerValues = new Rule(Constants.INTERNAL_ELEMENT + "Initial Player Values", RuleEvent.OngoingPlayer, Team.All, PlayerSelector.All);

            globalTranslate = new TranslateRule(initialGlobalValues, Root, this);
            playerTranslate = new TranslateRule(initialPlayerValues, Root, this);

            GetRulesets(content, file, true, null);

            VarCollection = new VarCollection(ReservedGlobalIDs.ToArray(), ReservedGlobalNames.ToArray(), ReservedPlayerIDs.ToArray(), ReservedPlayerNames.ToArray());
            Root          = new ScopeGroup(VarCollection);
            ClassIndexes  = IndexedVar.AssignInternalVar(VarCollection, null, "_classIndexes", true);
            ClassArray    = IndexedVar.AssignInternalVar(VarCollection, null, "_classArray", true);

            if (!Diagnostics.ContainsErrors())
            {
                foreach (var ruleset in Rulesets)
                {
                    GetObjects(ruleset.Value, ruleset.Key, globalTranslate, playerTranslate);
                }
            }

            foreach (var type in DefinedTypes)
            {
                try
                {
                    type.RegisterParameters(this);
                }
                catch (SyntaxErrorException ex)
                {
                    Diagnostics.Error(ex);
                }
            }
            foreach (var method in UserMethods)
            {
                try
                {
                    method.RegisterParameters(this);
                }
                catch (SyntaxErrorException ex)
                {
                    Diagnostics.Error(ex);
                }
            }

            if (!Diagnostics.ContainsErrors())
            {
                // Parse the rules.
                Rules = new List <Rule>();

                for (int i = 0; i < RuleNodes.Count; i++)
                {
                    try
                    {
                        var result = TranslateRule.GetRule(RuleNodes[i], Root, this);
                        Rules.Add(result);
                    }
                    catch (SyntaxErrorException ex)
                    {
                        Diagnostics.Error(ex);
                    }
                }

                foreach (var definedVar in VarCollection.AllVars)
                {
                    try
                    {
                        if (definedVar is IndexedVar && definedVar.IsDefinedVar && definedVar.Scope == Root)
                        {
                            Node value = ((IDefine)definedVar.Node).Value;
                            if (value != null)
                            {
                                if (((IndexedVar)definedVar).IsGlobal)
                                {
                                    globalTranslate.Actions.AddRange(((IndexedVar)definedVar).SetVariable(globalTranslate.ParseExpression(Root, Root, value)));
                                }
                                else
                                {
                                    playerTranslate.Actions.AddRange(((IndexedVar)definedVar).SetVariable(playerTranslate.ParseExpression(Root, Root, value)));
                                }
                            }
                        }
                    }
                    catch (SyntaxErrorException ex)
                    {
                        Diagnostics.Error(ex);
                    }
                }

                globalTranslate.Finish();
                playerTranslate.Finish();

                // Add the player initial values rule if it was used.
                if (initialPlayerValues.Actions.Length > 0)
                {
                    Rules.Insert(0, initialPlayerValues);
                }

                // Add the global initial values rule if it was used.
                if (initialGlobalValues.Actions.Length > 0)
                {
                    Rules.Insert(0, initialGlobalValues);
                }

                foreach (Rule rule in AdditionalRules)
                {
                    if (rule.Actions.Length > 0)
                    {
                        Rules.Add(rule);
                    }
                }
            }

            Success = !Diagnostics.ContainsErrors();
        }
        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);
        }
Exemple #29
0
 public ParameterVar(List <Element> actions, ScopeGroup scopeGroup, string name, bool isGlobal, Variable variable, int index, Range range)
     : base(scopeGroup, name, isGlobal, variable, index, range)
 {
     Actions = actions;
 }
 abstract public Element Get(TranslateRule context, ScopeGroup scope, MethodNode methodNode, IWorkshopTree[] parameters);