示例#1
0
        /// <summary>
        /// Applies the bracket operands. Executes the expressionBuilder with all the operands in the brackets.
        /// </summary>
        /// <param name="bracketOpen">The operator that opened the bracket.</param>
        /// <param name="bracketOperands">The list of operands within the brackets.</param>
        /// <param name="bracketClose">The operator that closed the bracket.</param>
        /// <param name="state">The current parse state.</param>
        /// <exception cref="FunctionArgumentCountException">When the number of opreands does not match the number of arguments</exception>
        /// <exception cref="FunctionArgumentTypeException">When argument Type does not match the type of the expression</exception>
        /// <exception cref="OperationInvalidException">When an error occured while executing the expressionBuilder</exception>
        public override void ApplyBracketOperands(Operator bracketOpen, Stack <Operand> bracketOperands, Operator bracketClose, ParseState state)
        {
            var operandSource     = StringSegment.Encompass(bracketOperands.Select(x => x.SourceMap));
            var functionArguments = bracketOperands.Select(x => x.Expression);

            //if we have been given specific argument types validate them
            if (ArgumentTypes != null)
            {
                var expectedArgumentCount = ArgumentTypes.Count;
                if (expectedArgumentCount != bracketOperands.Count)
                {
                    throw new FunctionArgumentCountException(
                              operandSource,
                              expectedArgumentCount,
                              bracketOperands.Count);
                }

                functionArguments = bracketOperands.Zip(ArgumentTypes, (o, t) => {
                    try
                    {
                        return(ExpressionConversions.Convert(o.Expression, t));
                    }
                    catch (InvalidOperationException)
                    {
                        //if we cant convert to the argument type then something is wrong with the argument
                        //so we will throw it up
                        throw new FunctionArgumentTypeException(o.SourceMap, t, o.Expression.Type);
                    }
                });
            }

            var        functionSourceMap      = StringSegment.Encompass(bracketOpen.SourceMap, operandSource);
            var        functionArgumentsArray = functionArguments.ToArray();
            Expression output;

            try
            {
                output = ExpressionBuilder(functionArgumentsArray);
            }
            catch (Exception ex)
            {
                throw new OperationInvalidException(functionSourceMap, ex);
            }
            if (output != null)
            {
                state.Operands.Push(new Operand(output, functionSourceMap));
            }
        }
        /// <summary>
        /// Applies the bracket operands. Adds the evaluated operand within the bracket to the state.
        /// </summary>
        /// <param name="bracketOpen">The operator that opened the bracket.</param>
        /// <param name="bracketOperands">The list of operands within the brackets.</param>
        /// <param name="bracketClose">The operator that closed the bracket.</param>
        /// <param name="state">The current parse state.</param>
        /// <exception cref="OperandExpectedException">When brackets are empty.</exception>
        /// <exception cref="OperandUnexpectedException">When there is more than one element in the brackets</exception>
        public virtual void ApplyBracketOperands(Operator bracketOpen, Stack <Operand> bracketOperands, Operator bracketClose, ParseState state)
        {
            if (bracketOperands.Count == 0)
            {
                var insideBrackets = StringSegment.Between(bracketOpen.SourceMap, bracketClose.SourceMap);
                throw new OperandExpectedException(insideBrackets);
            }
            else if (bracketOperands.Count > 1)
            {
                var operandSpan = StringSegment.Encompass(bracketOperands.Skip(1).Select(x => x.SourceMap));
                throw new OperandUnexpectedException(operandSpan);
            }


            var bracketOperand = bracketOperands.Pop();
            var sourceMap      = StringSegment.Encompass(new[] { bracketOpen.SourceMap, bracketOperand.SourceMap, bracketClose.SourceMap });

            state.Operands.Push(new Operand(bracketOperand.Expression, sourceMap));
        }
        /// <summary>
        /// Applies the token to the parsing state. Adds an operator to the state, when executed the operator will
        /// check it has enough operands and they are in the correct position. It will then execute the expressionBuilder
        /// placing the result in the state.
        /// </summary>
        /// <param name="token">The token to apply.</param>
        /// <param name="state">The state to apply the token to.</param>
        public override void Apply(Token token, ParseState state)
        {
            //Apply previous operators if they have a high precedence and they share an operand
            var anyLeftOperators = this.ParamaterPositions.Any(x => x == RelativePosition.Left);

            while (state.Operators.Count > 0 && this.OrderOfPrecedence != null && anyLeftOperators)
            {
                var prevOperator           = state.Operators.Peek().Definition as OperatorDefinition;
                var prevOperatorPrecedence = prevOperator?.OrderOfPrecedence;
                if (prevOperatorPrecedence <= this.OrderOfPrecedence && prevOperator.ParamaterPositions.Any(x => x == RelativePosition.Right))
                {
                    state.Operators.Pop().Execute();
                }
                else
                {
                    break;
                }
            }


            state.Operators.Push(new Operator(this, token.SourceMap, () =>
            {
                //Pop all our right arguments, and check there is the correct number and they are all to the right
                var rightArgs         = new Stack <Operand>(state.Operands.PopWhile(x => x.SourceMap.IsRightOf(token.SourceMap)));
                var expectedRightArgs = this.ParamaterPositions.Count(x => x == RelativePosition.Right);
                if (expectedRightArgs > 0 && rightArgs.Count > expectedRightArgs)
                {
                    var spanWhereOperatorExpected = StringSegment.Encompass(rightArgs
                                                                            .Reverse()
                                                                            .Take(rightArgs.Count - expectedRightArgs)
                                                                            .Select(x => x.SourceMap));
                    throw new OperandUnexpectedException(token.SourceMap, spanWhereOperatorExpected);
                }
                else if (rightArgs.Count < expectedRightArgs)
                {
                    throw new OperandExpectedException(token.SourceMap, new StringSegment(token.SourceMap.SourceString, token.SourceMap.End, 0));
                }


                //Pop all our left arguments, and check they are not to the left of the next operator
                var nextOperatorEndIndex = state.Operators.Count == 0 ? 0 : state.Operators.Peek().SourceMap.End;
                var expectedLeftArgs     = this.ParamaterPositions.Count(x => x == RelativePosition.Left);
                var leftArgs             = new Stack <Operand>(state.Operands
                                                               .PopWhile((x, i) => i < expectedLeftArgs && x.SourceMap.IsRightOf(nextOperatorEndIndex)
                                                                         ));
                if (leftArgs.Count < expectedLeftArgs)
                {
                    throw new OperandExpectedException(token.SourceMap, new StringSegment(token.SourceMap.SourceString, token.SourceMap.Start, 0));
                }

                //Map the operators into the correct argument positions
                var args = new List <Operand>();
                foreach (var paramPos in this.ParamaterPositions)
                {
                    Operand operand = paramPos == RelativePosition.Right
                        ? rightArgs.Pop()
                        : leftArgs.Pop();
                    args.Add(operand);
                }


                //our new source map will encompass this operator and all its operands
                var sourceMapSpan = StringSegment.Encompass(new[] { token.SourceMap }.Concat(args.Select(x => x.SourceMap)));

                Expression expression;
                try
                {
                    expression = ExpressionBuilder(args.Select(x => x.Expression).ToArray());
                }catch (Exception ex)
                {
                    throw new OperationInvalidException(sourceMapSpan, ex);
                }

                state.Operands.Push(new Operand(expression, sourceMapSpan));
            }));
        }