예제 #1
0
        public void IndexShouldIncreaseWhenMoveNext()
        {
            var tokens = new List <Token>
            {
                new Token("1", TokenType.Decimal),
                new Token("2", TokenType.Decimal)
            };
            var navigator = new TokenNavigator(tokens);

            navigator.MoveNext();

            Assert.AreEqual(1, navigator.Index, "Index was not 1 but " + navigator.Index);
        }
예제 #2
0
        public void MoveToNextAndReturnPrevToken()
        {
            var tokens = new List <Token>
            {
                new Token("1", TokenType.Decimal),
                new Token("2", TokenType.Decimal)
            };
            var navigator = new TokenNavigator(tokens);

            navigator.MoveNext();

            Assert.AreEqual("1", navigator.PreviousToken.Value.Value);
        }
예제 #3
0
        public void NumberOfRemainingTokensShouldBeCorrect()
        {
            var tokens = new List <Token>
            {
                new Token("1", TokenType.Decimal),
                new Token("2", TokenType.Decimal),
                new Token("3", TokenType.Decimal)
            };
            var navigator = new TokenNavigator(tokens);

            Assert.AreEqual(2, navigator.NbrOfRemainingTokens);
            navigator.MoveNext();
            Assert.AreEqual(1, navigator.NbrOfRemainingTokens);
        }
예제 #4
0
        /// <summary>
        /// This will never return null nor a set containing any nulls
        /// </summary>
        private static IEnumerable <Expression> Generate(TokenNavigator tokenNavigator, int depth, IToken directedWithReferenceIfAny, Action <string> warningLogger)
        {
            if (tokenNavigator == null)
            {
                throw new ArgumentNullException("tokenNavigator");
            }
            if (depth < 0)
            {
                throw new ArgumentOutOfRangeException("depth", "must be zero or greater");
            }
            if (warningLogger == null)
            {
                throw new ArgumentNullException("warningLogger");
            }

            var expressions        = new List <Expression>();
            var expressionSegments = new List <IExpressionSegment>();
            var accessorBuffer     = new List <IToken>();

            while (true)
            {
                var token = tokenNavigator.Value;
                if (token == null)
                {
                    if (depth > 0)
                    {
                        throw new ArgumentException("Expected CloseBrace and didn't encounter one - invalid content");
                    }
                    break;
                }

                if (token is CloseBrace)
                {
                    if (depth == 0)
                    {
                        throw new ArgumentException("Unexpected CloseBrace - invalid content");
                    }
                    tokenNavigator.MoveNext(); // Move on since this token has been processed
                    if (expressionSegments.Count == 1)
                    {
                        var callExpressionSegment = expressionSegments[0] as CallExpressionSegment;
                        if ((callExpressionSegment != null) && (callExpressionSegment.MemberAccessTokens.Count() == 1) && !callExpressionSegment.Arguments.Any())
                        {
                            // VBScript gives special meaning to a reference wrapped in brackets when passing it to a function (or property); if
                            // the argument would otherwise be passed ByRef, it will be passed ByVal. If this close bracket terminates a section
                            // containing only a single CallExpressionSegment without property accesses or arguments, then the brackets have
                            // significance and the content must be represented by a BracketedExpressionSegment. (If it's a variable access with
                            // function / property accesses - meaning there would be multiple MemberAccessTokens - or if there are arguments -
                            // meaning that it's a function or property call - then the value would not be elligible for being passed ByRef anyway,
                            // so the extra brackets need not be maintained). There is chance that ths single token represents a non-argument call
                            // to a function, but we don't have enough information at this point to know that, so we have to presume the worst and
                            // keep the brackets here.
                            expressionSegments[0] = new BracketedExpressionSegment(new[] { callExpressionSegment });
                        }
                    }
                    break;
                }

                if (token is ArgumentSeparatorToken)
                {
                    if (depth == 0)
                    {
                        throw new ArgumentException("Encountered ArgumentSeparatorToken in top-level content - invalid");
                    }

                    if (accessorBuffer.Any())
                    {
                        expressionSegments.Add(
                            GetCallOrNewOrValueExpressionSegment(
                                accessorBuffer,
                                new Expression[0],
                                directedWithReferenceIfAny,
                                argumentsAreBracketed: false,
                                willBeFirstSegmentInCallExpression: WillBeFirstSegmentInCallExpression(expressionSegments),
                                warningLogger: warningLogger
                                )
                            );
                        accessorBuffer.Clear();
                    }
                    if (!expressionSegments.Any())
                    {
                        throw new ArgumentException("Unexpected ArgumentSeparatorToken - invalid content");
                    }

                    expressions.Add(GetExpression(expressionSegments));
                    expressionSegments.Clear();
                    tokenNavigator.MoveNext(); // Move on since this token has been processed
                    continue;
                }

                if (token is OpenBrace)
                {
                    tokenNavigator.MoveNext(); // Move on since this token has been processed

                    // Get the content from inside the brackets (using a TokenNavigator here that is passed again into the Generate
                    // method means that when the below call returns, the tokenNavigator here will have been moved along to after
                    // the bracketed content that is about to be processed)
                    var bracketedExpressions = Generate(tokenNavigator, depth + 1, directedWithReferenceIfAny, warningLogger);

                    // If the accessorBuffer isn't empty then the bracketed content should be arguments, if not then it's just a bracketed expression
                    if (accessorBuffer.Any())
                    {
                        expressionSegments.Add(
                            GetCallOrNewOrValueExpressionSegment(
                                accessorBuffer,
                                bracketedExpressions,
                                directedWithReferenceIfAny,
                                argumentsAreBracketed: true,
                                willBeFirstSegmentInCallExpression: WillBeFirstSegmentInCallExpression(expressionSegments),
                                warningLogger: warningLogger
                                )
                            );
                        accessorBuffer.Clear();
                    }
                    else if (bracketedExpressions.Any())
                    {
                        if (expressionSegments.Any() && (expressionSegments.Last() is CallSetItemExpressionSegment))
                        {
                            // If the previous expression segment was a CallExpressionSegment or CallSetItemExpressionSegment (the first
                            // is derived from the second so only a single type check is required) then this bracketed content should
                            // be considered a continuation of the call (these segments will later be grouped into a single
                            // CallSetExpression)
                            expressionSegments.Add(
                                new CallSetItemExpressionSegment(
                                    new IToken[0],
                                    bracketedExpressions,
                                    null // ArgumentBracketPresenceOptions
                                    )
                                );
                        }
                        else
                        {
                            if (bracketedExpressions.Count() > 1)
                            {
                                throw new ArgumentException("If bracketed content is not for an argument list then it's invalid for there to be multiple expressions within it");
                            }
                            expressionSegments.Add(
                                WrapExpressionSegments(bracketedExpressions.Single().Segments, unwrapSingleBracketedTerm: false)
                                );
                        }
                    }
                    continue;
                }

                var operatorToken = token as OperatorToken;
                if (operatorToken != null)
                {
                    if (accessorBuffer.Any())
                    {
                        expressionSegments.Add(
                            GetCallOrNewOrValueExpressionSegment(
                                accessorBuffer,
                                new Expression[0],
                                directedWithReferenceIfAny,
                                argumentsAreBracketed: false, // zero-argument content not bracketed
                                willBeFirstSegmentInCallExpression: WillBeFirstSegmentInCallExpression(expressionSegments),
                                warningLogger: warningLogger
                                )
                            );
                        accessorBuffer.Clear();
                    }
                    expressionSegments.Add(
                        new OperationExpressionSegment(operatorToken)
                        );
                    tokenNavigator.MoveNext();
                    continue;
                }

                accessorBuffer.Add(token);
                tokenNavigator.MoveNext();
            }
            if (accessorBuffer.Any())
            {
                expressionSegments.Add(
                    GetCallOrNewOrValueExpressionSegment(
                        accessorBuffer,
                        new Expression[0],
                        directedWithReferenceIfAny,
                        argumentsAreBracketed: false, // zero-argument content not bracketed
                        willBeFirstSegmentInCallExpression: WillBeFirstSegmentInCallExpression(expressionSegments),
                        warningLogger: warningLogger
                        )
                    );
                accessorBuffer.Clear();
            }
            if (expressionSegments.Any())
            {
                expressions.Add(GetExpression(expressionSegments));
                expressionSegments.Clear();
            }
            return(expressions);
        }