public ForEachStatement(
            IExecutable declarationStatement,
            IValue loopVariable,
            IValueGetter containerExpression,
            IExecutable loopBody,
            KeywordToken keywordToken)
        {
            if (!typeof(IEnumerable).IsAssignableFrom(containerExpression.GetValueType()))
            {
                throw new ScriptParsingException(
                          source: keywordToken,
                          message: $"Collection of ForEach statement is not an Enumerable collection: {containerExpression.GetValueType().Name}");
            }

            if (!loopVariable.GetValueType().AssignableFromType(containerExpression.GetValueType().GetGenericArguments()[0]))
            {
                throw new ScriptParsingException(
                          source: keywordToken,
                          message: $"Collection items of type " +
                          $"({containerExpression.GetValueType().GetGenericArguments()[0].Name}) " +
                          $"not assignable to declared item type: {loopVariable.GetValueType().Name}");
            }

            this.loopVariable = loopVariable;

            this.declarationStatement = declarationStatement;
            this.containerExpression  = containerExpression;
            this.loopBody             = loopBody;
        }
        public T GetAs <T>(RuntimeContext context)
        {
            Type returnType = typeof(T);

            if (!returnType.AssignableFromType(getType))
            {
                throw new ScriptRuntimeException($"Tried to retrieve result of Indexing with type {getType.Name} as type {returnType.Name}");
            }

            object index = indexArg.GetAs <object>(context);

            if (!indexerType.IsAssignableFrom(indexArg.GetValueType()))
            {
                index = Convert.ChangeType(index, indexerType);
            }

            object value = indexGetter.Invoke(valueArg.GetAs <object>(context), new object[] { index });

            if (returnType.IsAssignableFrom(getType))
            {
                return((T)value);
            }

            return((T)Convert.ChangeType(value, returnType));
        }
示例#3
0
        public IsNaNMathFunction(
            IValueGetter arg,
            Token source)
        {
            if (!(arg.GetValueType() == typeof(double) || arg.GetValueType() == typeof(int)))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Argument of IsNaN is not numerical: type {arg.GetValueType().Name}");
            }

            this.arg = arg;
        }
示例#4
0
        public static DeclarationAssignmentOperation CreateDelcaration(
            IdentifierToken identifierToken,
            Type valueType,
            IValueGetter initializer,
            bool isConstant,
            CompilationContext context)
        {
            //Check initializer type
            if (!valueType.AssignableFromType(initializer.GetValueType()))
            {
                throw new ScriptParsingException(
                          source: identifierToken,
                          message: $"Incompatible type in declaration.  Expected type {valueType.Name}, Received {initializer.GetValueType().Name}");
            }

            if (isConstant)
            {
                if (initializer is LiteralToken litToken)
                {
                    object value = litToken.GetAs <object>();

                    if (!valueType.IsAssignableFrom(initializer.GetValueType()))
                    {
                        value = Convert.ChangeType(value, valueType);
                    }

                    context.DeclareConstant(
                        identifierToken: identifierToken,
                        type: valueType,
                        value: value);

                    //Const declaration can't have sideeffects, thus no statement is generated
                    return(null);
                }

                throw new ScriptParsingException(
                          source: identifierToken,
                          message: $"Constants cannot be initialized with non-constant values.");
            }

            //Try to declare and throw exceptions if invalid
            context.DeclareVariable(identifierToken, valueType);

            return(new DeclarationAssignmentOperation(
                       identifier: identifierToken.identifier,
                       valueType: valueType,
                       initializer: initializer));
        }
        public static IExpression CreateCastOperation(
            IValueGetter arg,
            OperatorToken operatorToken)
        {
            Type argType = arg.GetValueType();

            if (!(argType == typeof(double) || argType == typeof(int)))
            {
                throw new ScriptParsingException(
                          source: operatorToken,
                          message: $"Argument of operator {operatorToken.operatorType} is not numerical: type {argType.Name}.");
            }

            if (arg is LiteralToken litArg)
            {
                switch (operatorToken.operatorType)
                {
                case Operator.CastDouble: return(new LiteralToken <double>(operatorToken, litArg.GetAs <double>()));

                case Operator.CastInteger: return(new LiteralToken <int>(operatorToken, (int)litArg.GetAs <double>()));

                default: throw new ArgumentException($"Unexpected Operator: {operatorToken.operatorType}");
                }
            }

            return(new CastOperation(arg, operatorToken.operatorType));
        }
        public static IValueGetter[] ParseItems(
            IEnumerator <Token> tokens,
            Type itemType,
            CompilationContext context)
        {
            List <IValueGetter> items = new List <IValueGetter>();

            tokens.AssertAndSkip(Separator.OpenCurlyBoi);

            if (!tokens.TestWithoutSkipping(Separator.CloseCurlyBoi))
            {
                do
                {
                    Token        temp      = tokens.Current;
                    IValueGetter nextValue = ParseNextGetterExpression(tokens, context);

                    if (!itemType.AssignableFromType(nextValue.GetValueType()))
                    {
                        throw new ScriptParsingException(
                                  source: temp,
                                  message: $"Initializer List Argument must be of appropriate value type: Expected: {itemType.Name}, Found: {nextValue.GetValueType().Name}");
                    }

                    items.Add(nextValue);
                }while (tokens.TestAndConditionallySkip(Separator.Comma));
            }

            tokens.AssertAndSkip(Separator.CloseCurlyBoi);

            return(items.ToArray());
        }
        public static IExpression CreateNegationOperation(
            IValueGetter arg,
            Token source)
        {
            Type argType = arg.GetValueType();

            if (!(argType == typeof(double) || argType == typeof(int)))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Cannot negate a non-numerical value {arg} of type {argType.Name}");
            }

            if (arg is LiteralToken litArg)
            {
                if (argType == typeof(int))
                {
                    return(new LiteralToken <int>(source, -litArg.GetAs <int>()));
                }
                else
                {
                    return(new LiteralToken <double>(source, -litArg.GetAs <double>()));
                }
            }

            return(new NegationOperation(arg, argType));
        }
        public static IExpression CreateBinaryBoolOperator(
            IValueGetter arg1,
            IValueGetter arg2,
            OperatorToken operatorToken)
        {
            if (arg1.GetValueType() != typeof(bool))
            {
                throw new ScriptParsingException(
                          source: operatorToken,
                          message: $"Left side of operator {operatorToken.operatorType} not of expected type bool: {arg1.GetValueType().Name}");
            }

            if (arg2.GetValueType() != typeof(bool))
            {
                throw new ScriptParsingException(
                          source: operatorToken,
                          message: $"Right side of operator {operatorToken.operatorType} not of expected type bool: {arg2.GetValueType().Name}");
            }

            //Constant case
            if (arg1 is LiteralToken litArg1 && arg2 is LiteralToken litArg2)
            {
                switch (operatorToken.operatorType)
                {
                case Operator.And: return(new LiteralToken <bool>(operatorToken, litArg1.GetAs <bool>() && litArg2.GetAs <bool>()));

                case Operator.Or: return(new LiteralToken <bool>(operatorToken, litArg1.GetAs <bool>() || litArg2.GetAs <bool>()));

                default: throw new ArgumentException($"Unexpected Operator {operatorToken.operatorType}");
                }
            }

            return(new BinaryBoolOperation(arg1, arg2, operatorToken.operatorType));
        }
        public BooleanInPlaceOperation(
            IValue assignee,
            IValueGetter value,
            Operator operatorType,
            Token source)
        {
            if (assignee.GetValueType() != typeof(bool))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Left Argument {assignee} of Operator {source} is not a bool: type {assignee.GetValueType().Name}");
            }

            if (value.GetValueType() != typeof(bool))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Right Argument {value} of Operator {source} is not a bool.");
            }

            this.assignee     = assignee;
            this.value        = value;
            this.operatorType = operatorType;

            switch (operatorType)
            {
            case Operator.AndEquals:
            case Operator.OrEquals:
                //Acceptable
                break;

            default:
                throw new ArgumentException($"Unexpected Operator: {operatorType}");
            }
        }
示例#10
0
        public static IExpression CreateEqualityComparisonOperator(
            IValueGetter arg1,
            IValueGetter arg2,
            OperatorToken operatorToken)
        {
            Type argType;
            Type arg1Type = arg1.GetValueType();
            Type arg2Type = arg2.GetValueType();

            if (arg1Type == arg2Type)
            {
                argType = arg1Type;
            }
            else if (arg1Type.AssignableFromType(arg2Type))
            {
                argType = arg1Type;
            }
            else if (arg2Type.AssignableFromType(arg1Type))
            {
                argType = arg2Type;
            }
            else
            {
                throw new ScriptParsingException(
                          source: operatorToken,
                          message: $"Incompatible Types for {operatorToken.operatorType} operator: {arg1Type.Name} and {arg2Type.Name}");
            }

            //Constant case
            if (arg1 is LiteralToken litArg1 && arg2 is LiteralToken litArg2)
            {
                object value1 = litArg1.GetAs <object>();
                object value2 = litArg2.GetAs <object>();

                if (argType != arg1Type)
                {
                    value1 = Convert.ChangeType(value1, argType);
                }

                if (argType != arg2Type)
                {
                    value2 = Convert.ChangeType(value2, argType);
                }

                switch (operatorToken.operatorType)
                {
                case Operator.IsEqualTo: return(new LiteralToken <bool>(operatorToken, value1.Equals(value2)));

                case Operator.IsNotEqualTo: return(new LiteralToken <bool>(operatorToken, !value1.Equals(value2)));

                default: throw new ArgumentException($"Unexpected Operator: {operatorToken.operatorType}");
                }
            }

            return(new EqualityCompairsonOperation(arg1, arg2, argType, operatorToken.operatorType));
        }
        public ReturnStatement(
            KeywordToken keywordToken,
            IValueGetter returnValue,
            CompilationContext context)
        {
            this.returnValue = returnValue;

            context.ValidateReturn(
                returnKeyword: keywordToken,
                returnType: returnValue?.GetValueType() ?? typeof(void));

            returnType = context.GetReturnType();
        }
        public HasDataOperation(
            IValueGetter keyArg,
            Token source)
        {
            if (keyArg.GetValueType() != typeof(string))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Key argument of User.HasData must be a string: type {keyArg.GetValueType().Name}");
            }

            this.keyArg = keyArg;
        }
        public static IExpression CreateComparisonOperation(
            IValueGetter arg1,
            IValueGetter arg2,
            OperatorToken operatorToken)
        {
            if (!(arg1.GetValueType() == typeof(double) || arg1.GetValueType() == typeof(int)))
            {
                throw new ScriptParsingException(
                          source: operatorToken,
                          message: $"Left side of operator {operatorToken.operatorType} has incompatible type: {arg1.GetValueType().Name}");
            }

            if (!(arg2.GetValueType() == typeof(double) || arg2.GetValueType() == typeof(int)))
            {
                throw new ScriptParsingException(
                          source: operatorToken,
                          message: $"Right side of operator {operatorToken.operatorType} has incompatible type: {arg2.GetValueType().Name}");
            }


            //Constant case
            if (arg1 is LiteralToken litArg1 && arg2 is LiteralToken litArg2)
            {
                switch (operatorToken.operatorType)
                {
                case Operator.IsGreaterThan: return(new LiteralToken <bool>(operatorToken, litArg1.GetAs <double>() > litArg2.GetAs <double>()));

                case Operator.IsGreaterThanOrEqualTo: return(new LiteralToken <bool>(operatorToken, litArg1.GetAs <double>() >= litArg2.GetAs <double>()));

                case Operator.IsLessThan: return(new LiteralToken <bool>(operatorToken, litArg1.GetAs <double>() < litArg2.GetAs <double>()));

                case Operator.IsLessThanOrEqualTo: return(new LiteralToken <bool>(operatorToken, litArg1.GetAs <double>() <= litArg2.GetAs <double>()));

                default: throw new ArgumentException($"Unexpected Operator {operatorToken.operatorType}");
                }
            }

            return(new ComparisonOperation(arg1, arg2, operatorToken.operatorType));
        }
        public static IExpression CreateBinaryNumericalOperation(
            IValueGetter arg1,
            IValueGetter arg2,
            OperatorToken operatorToken)
        {
            Type arg1Type = arg1.GetValueType();
            Type arg2Type = arg2.GetValueType();
            Type valueType;

            if (!(arg1Type == typeof(double) || arg1Type == typeof(int)))
            {
                throw new ScriptParsingException(
                          source: operatorToken,
                          message: $"Left side of operator {operatorToken.operatorType} not of expected type int or bool: {arg1.GetValueType().Name}");
            }

            if (!(arg2Type == typeof(double) || arg2Type == typeof(int)))
            {
                throw new ScriptParsingException(
                          source: operatorToken,
                          message: $"Right side of operator {operatorToken.operatorType} not of expected type int or bool: {arg2.GetValueType().Name}");
            }

            if (arg1Type == arg2Type)
            {
                valueType = arg1Type;
            }
            else
            {
                valueType = typeof(double);
            }

            //Constant case
            if (arg1 is LiteralToken litArg1 && arg2 is LiteralToken litArg2)
            {
                if (valueType == typeof(int))
                {
                    return(new LiteralToken <int>(
                               operatorToken,
                               IntOperator <int>(litArg1.GetAs <int>(), litArg2.GetAs <int>(), operatorToken.operatorType, valueType)));
                }
                else
                {
                    return(new LiteralToken <double>(
                               operatorToken,
                               DoubleOperator <double>(litArg1.GetAs <double>(), litArg2.GetAs <double>(), operatorToken.operatorType, valueType)));
                }
            }

            return(new BinaryNumericalOperation(arg1, arg2, valueType, operatorToken.operatorType));
        }
        public SingleArgumentMathFunction(
            IValueGetter arg,
            MathMethod mathMethod,
            Token source)
        {
            this.arg        = arg;
            this.mathMethod = mathMethod;

            Type argType = arg.GetValueType();

            if (!(argType == typeof(double) || argType == typeof(int)))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Cannot perform Math.{mathMethod} on non-numerical value {arg} of type {argType.Name}");
            }

            switch (mathMethod)
            {
            case MathMethod.Floor:
            case MathMethod.Ceiling:
            case MathMethod.Round:
            case MathMethod.Abs:
                valueType = argType;
                break;

            case MathMethod.Sign:
                valueType = typeof(int);
                break;

            case MathMethod.Ln:
            case MathMethod.Log10:
            case MathMethod.Exp:
            case MathMethod.Sqrt:
            case MathMethod.Sin:
            case MathMethod.Cos:
            case MathMethod.Tan:
            case MathMethod.Asin:
            case MathMethod.Acos:
            case MathMethod.Atan:
            case MathMethod.Sinh:
            case MathMethod.Cosh:
            case MathMethod.Tanh:
                //Only return doubles.
                valueType = typeof(double);
                break;

            default:
                throw new ArgumentException($"Unexpected Operator: {mathMethod}");
            }
        }
示例#16
0
        public SetUserValueMethod(
            IValueGetter keyArg,
            IValueGetter valueArg,
            UserMethod userMethod,
            Token source)
        {
            switch (userMethod)
            {
            case UserMethod.SetString:
                valueType = typeof(string);
                break;

            case UserMethod.SetBool:
                valueType = typeof(bool);
                break;

            case UserMethod.SetDouble:
                valueType = typeof(double);
                break;

            case UserMethod.SetInt:
                valueType = typeof(int);
                break;

            case UserMethod.SetList:
                valueType = typeof(IList);
                break;

            default:
                throw new Exception($"Unexpected UserMethod: {userMethod}");
            }


            if (keyArg.GetValueType() != typeof(string))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Key Argument {keyArg} of User.{userMethod} is not a string: type {keyArg.GetValueType().Name}");
            }

            if (!valueType.AssignableFromType(valueArg.GetValueType()))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Value Argument {valueArg} of User.{userMethod} is type {valueType.Name} and not assignable to type {valueArg.GetValueType().Name}");
            }

            this.keyArg   = keyArg;
            this.valueArg = valueArg;
        }
示例#17
0
        public MemberArgumentValueExecutableOperation(
            IValueGetter value,
            Func <TInput, RuntimeContext, TResult> operation,
            Token source)
        {
            this.value     = value;
            this.operation = operation;

            if (!typeof(TInput).AssignableFromType(value.GetValueType()))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Incorrect value type.  Expected: {typeof(TInput).Name}.  Received: {value.GetValueType().Name}. ");
            }
        }
示例#18
0
        public MemberStatementOperation(
            IValueGetter value,
            Action <TInput> operation,
            Token source)
        {
            this.value     = value;
            this.operation = operation;

            if (!typeof(TInput).AssignableFromType(value.GetValueType()))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Incorrect value type.  Expected: {typeof(TInput).Name}.  Received: {value.GetValueType().Name}. ");
            }
        }
示例#19
0
        public WhileStatement(
            IValueGetter continueExpression,
            IExecutable loopBody,
            KeywordToken keywordToken)
        {
            if (continueExpression.GetValueType() != typeof(bool))
            {
                throw new ScriptParsingException(
                          source: keywordToken,
                          message: $"ContinueExpression of {keywordToken} statement is not a boolean value: type {continueExpression.GetValueType().Name}");
            }

            this.continueExpression = continueExpression;
            this.loopBody           = loopBody;
        }
示例#20
0
        public NumericalInPlaceOperation(
            IValue assignee,
            IValueGetter value,
            Operator operatorType,
            Token source)
        {
            assigneeType = assignee.GetValueType();
            Type valueType = value.GetValueType();

            if (!(assigneeType == typeof(int) || assigneeType == typeof(double)))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Assignee {assignee} for Operator {source} is not a numerical value: type {assigneeType.Name}");
            }

            if (!(valueType == typeof(int) || valueType == typeof(double)))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Value {value} for Operator {source} is not a numerical value: type {valueType.Name}");
            }

            if (assigneeType == typeof(int) && valueType == typeof(double))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Unable to implicity cast Value {value} to type int for assignment to assignee {assignee}.");
            }

            this.assignee     = assignee;
            this.value        = value;
            this.operatorType = operatorType;

            switch (operatorType)
            {
            case Operator.PlusEquals:
            case Operator.MinusEquals:
            case Operator.TimesEquals:
            case Operator.DivideEquals:
            case Operator.PowerEquals:
            case Operator.ModuloEquals:
                //Acceptable
                break;

            default: throw new ArgumentException($"Unexpected Operator: {operatorType}");
            }
        }
示例#21
0
        public IfStatement(
            IValueGetter condition,
            IExecutable trueBlock,
            IExecutable falseBlock,
            KeywordToken keywordToken)
        {
            if (condition.GetValueType() != typeof(bool))
            {
                throw new ScriptParsingException(
                          source: keywordToken,
                          message: $"Condition of {keywordToken} statement is not a boolean value: type {condition.GetValueType().Name}");
            }

            this.condition  = condition;
            this.trueBlock  = trueBlock;
            this.falseBlock = falseBlock;
        }
        public SettablePropertyValueOperation(
            IValueGetter value,
            Func <TInput, TResult> getOperation,
            Action <TInput, TResult> setOperation,
            Token source)
        {
            this.value        = value;
            this.getOperation = getOperation;
            this.setOperation = setOperation;

            if (!typeof(TInput).AssignableFromType(value.GetValueType()))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Incorrect value type.  Expected: {typeof(TInput).Name}.  Received: {value.GetValueType().Name}. ");
            }
        }
        public ClampMathFunction(
            IValueGetter value,
            IValueGetter lowerbound,
            IValueGetter upperbound,
            Token source)
        {
            Type inputValueType = value.GetValueType();
            Type lowerboundType = lowerbound.GetValueType();
            Type upperboundType = upperbound.GetValueType();

            if (!(inputValueType == typeof(int) || inputValueType == typeof(double)))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Tried to apply function Clamp to value {value} of type {inputValueType.Name}");
            }

            if (!(lowerboundType == typeof(int) || lowerboundType == typeof(double)))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Tried to apply function Clamp with lowerbound value {lowerbound} of type {lowerboundType.Name}");
            }

            if (!(upperboundType == typeof(int) || upperboundType == typeof(double)))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Tried to apply function Clamp with upperbound value {upperbound} of type {upperboundType.Name}");
            }

            if (inputValueType == typeof(int) &&
                lowerboundType == typeof(int) &&
                upperboundType == typeof(int))
            {
                valueType = inputValueType;
            }
            else
            {
                valueType = typeof(double);
            }

            this.value      = value;
            this.lowerbound = lowerbound;
            this.upperbound = upperbound;
        }
示例#24
0
        public GetUserValueFunction(
            IValueGetter keyArg,
            IValueGetter defaultArg,
            UserMethod userMethod,
            Token source)
        {
            this.keyArg     = keyArg;
            this.defaultArg = defaultArg;
            this.userMethod = userMethod;

            if (keyArg.GetValueType() != typeof(string))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Key argument of User.{userMethod} must be a string: type {keyArg.GetValueType().Name}");
            }

            switch (userMethod)
            {
            case UserMethod.GetInt:
                getType = typeof(int);
                break;

            case UserMethod.GetDouble:
                getType = typeof(double);
                break;

            case UserMethod.GetBool:
                getType = typeof(bool);
                break;

            case UserMethod.GetString:
                getType = typeof(string);
                break;

            default:
                throw new Exception($"Unsupported UserMethod: {userMethod}");
            }

            if (defaultArg != null && !getType.AssignableFromType(defaultArg.GetValueType()))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Default Value argument of User.{userMethod} must be of type {getType.Name}: type {defaultArg.GetValueType().Name}");
            }
        }
示例#25
0
        public DoubleArgumentMathFunction(
            IValueGetter arg1,
            IValueGetter arg2,
            MathMethod mathMethod,
            Token source)
        {
            Type arg1Type = arg1.GetValueType();
            Type arg2Type = arg2.GetValueType();

            this.arg1       = arg1;
            this.arg2       = arg2;
            this.mathMethod = mathMethod;

            if (!(arg1Type == typeof(double) || arg1Type == typeof(int)))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"First Argument of Math.{mathMethod} not of expected type int or bool: {arg1.GetValueType().Name}");
            }

            if (!(arg2Type == typeof(double) || arg2Type == typeof(int)))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Second Argument of Math.{mathMethod} not of expected type int or bool: {arg2.GetValueType().Name}");
            }

            if (arg1Type == arg2Type)
            {
                valueType = arg1Type;
            }
            else
            {
                valueType = typeof(double);
            }

            switch (mathMethod)
            {
            case MathMethod.Min:
            case MathMethod.Max:
                //Acceptable
                break;

            default: throw new ArgumentException($"Unexpected MathMethod: {mathMethod}");
            }
        }
        public IndexerOperation(
            IValueGetter valueArg,
            IValueGetter indexArg,
            Token source)
        {
            Type valueType = valueArg.GetValueType();

            indexerType = valueType.GetIndexingType();

            if (indexerType == null)
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Indexer used on non-Indexable type: type {valueType.Name}");
            }

            getType = valueType.GetIndexingReturnType();

            if (!indexerType.AssignableFromType(indexArg.GetValueType()))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Indexer value must be of type {indexerType.Name}: type {indexArg.GetValueType().Name}");
            }

            this.valueArg = valueArg;
            this.indexArg = indexArg;

            indexGetter = valueType.GetMethod("get_Item", new Type[] { indexerType });
            indexSetter = valueType.GetMethod("set_Item", new Type[] { indexerType, getType });

            if (indexGetter == null)
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Failed to get indexGetter for type: type {valueType.Name}");
            }

            if (indexSetter == null)
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Failed to get indexSetter for type: type {valueType.Name}");
            }
        }
        public static IExpression CreateNotOperation(
            IValueGetter arg,
            OperatorToken operatorToken)
        {
            if (arg.GetValueType() != typeof(bool))
            {
                throw new ScriptParsingException(
                          source: operatorToken,
                          message: $"Argument of Operator {operatorToken} is not boolean: type {arg.GetValueType().Name}.");
            }

            if (arg is LiteralToken litArg)
            {
                return(new LiteralToken <bool>(operatorToken, !litArg.GetAs <bool>()));
            }

            return(new NotOperation(arg));
        }
        public AssignmentOperation(
            IValue assignee,
            IValueGetter value,
            Token source)
        {
            this.assignee = assignee;
            this.value    = value;

            assigneeType = assignee.GetValueType();
            valueType    = value.GetValueType();

            if (!assigneeType.AssignableFromType(valueType))
            {
                throw new ScriptParsingException(
                          source: source,
                          message: $"Assignment operator has an incompatible type for {assigneeType.Name} variable: type {valueType.Name}");
            }
        }
        public ScriptDeclaration(
            IdentifierToken identifierToken,
            Type valueType,
            IValueGetter initializer,
            CompilationContext context)
        {
            identifier       = identifierToken.identifier;
            this.valueType   = valueType;
            this.initializer = initializer;

            //Try to declare and throw exceptions if invalid
            context.DeclareVariable(identifierToken, valueType);

            //Check initializer type
            if (initializer != null && !valueType.AssignableFromType(initializer.GetValueType()))
            {
                throw new ScriptParsingException(
                          source: identifierToken,
                          message: $"Incompatible type in declaration.  Expected type {valueType.Name}, Received {initializer.GetValueType().Name}");
            }
        }
        public override FlowState Execute(ScopeRuntimeContext context)
        {
            if (returnType == typeof(void))
            {
                context.PushReturnValue(null);
            }
            else
            {
                if (returnType == returnValue.GetValueType())
                {
                    context.PushReturnValue(returnValue.GetAs <object>(context));
                }
                else
                {
                    context.PushReturnValue(
                        Convert.ChangeType(returnValue.GetAs <object>(context), returnType));
                }
            }

            return(FlowState.Return);
        }