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));
            }
        }
        public Element ParseExpression(ScopeGroup getter, ScopeGroup scope, Node expression)
        {
            switch (expression)
            {
            // Math and boolean operations.
            case OperationNode operationNode:
            {
                Element left  = ParseExpression(getter, scope, operationNode.Left);
                Element right = ParseExpression(getter, 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(left * right);

                case "%":
                    return(left % right);

                case "/":
                    return(left / right);

                case "+":
                    return(left + right);

                case "-":
                    return(left - right);


                // BoolCompare: &&, ||
                case "&&":
                    return(Element.Part <V_And>(left, right));

                case "||":
                    return(Element.Part <V_Or>(left, right));

                // Compare: <, <=, ==, >=, >, !=
                case "<":
                    return(left < right);

                case "<=":
                    return(left <= right);

                case "==":
                    return(Element.Part <V_Compare>(left, EnumData.GetEnumValue(Operators.Equal), right));

                case ">=":
                    return(left >= right);

                case ">":
                    return(left > 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(numberNode.Value);

            // Bool
            case BooleanNode boolNode:
                if (boolNode.Value)
                {
                    return(new V_True());
                }
                else
                {
                    return(new V_False());
                }

            // Not operation
            case NotNode notNode:
                return(!(ParseExpression(getter, scope, notNode.Value)));

            case InvertNode invertNode:
                return(-ParseExpression(getter, scope, invertNode.Value));

            // Strings
            case StringNode stringNode:

                Element[] stringFormat = new Element[stringNode.Format?.Length ?? 0];
                for (int i = 0; i < stringFormat.Length; i++)
                {
                    stringFormat[i] = ParseExpression(getter, scope, stringNode.Format[i]);
                }
                if (stringNode.Localized)
                {
                    return(V_String.ParseString(stringNode.Location, stringNode.Value, stringFormat));
                }
                else
                {
                    return(V_CustomString.ParseString(stringNode.Location, 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(getter, scope, methodNode, true));

            // Variable
            case VariableNode variableNode:

                Element[] index = new Element[variableNode.Index.Length];
                for (int i = 0; i < index.Length; i++)
                {
                    index[i] = ParseExpression(getter, scope, variableNode.Index[i]);
                }

                Var var = scope.GetVar(getter, variableNode.Name, variableNode.Location);
                if (!var.Gettable())
                {
                    throw SyntaxErrorException.VariableIsReadonly(var.Name, variableNode.Location);
                }

                Element result = var.GetVariable();
                for (int i = 0; i < index.Length; i++)
                {
                    result = Element.Part <V_ValueInArray>(result, index[i]);
                }

                return(result);

            // Get value in array
            case ValueInArrayNode viaNode:
                return(Element.Part <V_ValueInArray>(ParseExpression(getter, scope, viaNode.Value), ParseExpression(getter, 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(getter, scope, createArrayNode.Values[i]);
                    prev = current;
                }

                return(current ?? new V_EmptyArray());
            }

            // Ternary Conditional (a ? b : c)
            case TernaryConditionalNode ternaryNode:
                return(Element.TernaryConditional
                       (
                           ParseExpression(getter, scope, ternaryNode.Condition),
                           ParseExpression(getter, scope, ternaryNode.Consequent),
                           ParseExpression(getter, scope, ternaryNode.Alternative)
                       ));

            // Enums
            case EnumNode enumNode:
                return(EnumData.ToElement(enumNode.EnumMember)
                       ?? throw SyntaxErrorException.EnumCantBeValue(enumNode.Type, enumNode.Location));

            // New object
            case CreateObjectNode createObjectNode:
                DefinedType typeData = ParserData.GetDefinedType(createObjectNode.TypeName, createObjectNode.Location);
                return(typeData.New(createObjectNode, getter, scope, this));

            // Expression tree
            case ExpressionTreeNode expressionTree:
                return(new ParseExpressionTree(this, getter, scope, expressionTree).ResultingElement);

            // This
            case ThisNode thisNode:
                return(getter.GetThis(thisNode.Location));

            // Type convert
            case TypeConvertNode typeConvertNode:
                DefinedType type    = ParserData.GetDefinedType(typeConvertNode.Type, typeConvertNode.Location);
                Element     element = ParseExpression(getter, scope, typeConvertNode.Expression);
                type.GetSource(this, element, typeConvertNode.Location);
                return(element);

            case RootNode rootNode: throw new SyntaxErrorException("'root' cannot be used like an expression.", rootNode.Location);
            }

            throw new Exception();
        }