public virtual State ParseClosingBracket <T> (char c, IParseContext context, State stateToReturn) where T : XNode
        {
            bool isEnding  = false;
            var  rootState = RootState as RazorFreeState;

            if (rootState.UseSimplifiedBracketTracker)
            {
                if (bracketsBuilder.Length > 0)
                {
                    bracketsBuilder.Remove(0, 1);
                }
                if (bracketsBuilder.Length == 0)
                {
                    isEnding = true;
                }
            }
            else if (!rootState.UseSimplifiedBracketTracker && CorrespondingBlock.IsEndingBracket(context.LocationMinus(1)))
            {
                isEnding = true;
            }

            if (isEnding)
            {
                StateEngineService.EndCodeFragment <T> (context);
                return(stateToReturn);
            }

            return(null);
        }
        public override State PushChar(char c, IParseContext context, ref string rollback)
        {
            if (context.CurrentStateLength == 1)
            {
                context.Nodes.Push(new RazorComment(context.LocationMinus(2)));
                return(null);
            }

            switch (context.StateTag)
            {
            case NOMATCH:
                if (c == '*')
                {
                    context.StateTag = STAR;
                }
                break;

            case STAR:
                if (c == '@')
                {
                    StateEngineService.EndCodeFragment <RazorComment> (context);
                    return(Parent);
                }
                else
                {
                    context.StateTag = NOMATCH;
                }
                break;
            }

            return(null);
        }
        public override State PushChar(char c, IParseContext context, ref string rollback)
        {
            if (context.CurrentStateLength == 1)
            {
                bracketsBuilder.Clear();
                var directive = context.Nodes.FirstOrDefault(n => n is RazorDirective);
                if (directive == null)
                {
                    if (context.PreviousState is XmlClosingTagState && CorrespondingDirective != null)
                    {
                        context.Nodes.Push(CorrespondingDirective);
                    }
                    else
                    {
                        Debug.Fail("Directive should be pushed before changing the state to DirectiveState");
                        return(Parent);
                    }
                }
                else
                {
                    CorrespondingBlock = directive as RazorDirective;
                }
            }

            if (CorrespondingDirective.IsSimpleDirective)
            {
                if (c == '<')
                {
                    IsInsideGenerics = true;
                }
                else if (c == '\n')
                {
                    StateEngineService.EndCodeFragment <RazorDirective> (context);
                    return(Parent.Parent);
                }
                // using directives can be placed in one line, e.g. @using foo @using bar
                else if (CorrespondingDirective.Name == "using" &&
                         !(Char.IsLetterOrDigit(c) || c == ' ' || c == '=' || c == '.'))
                {
                    rollback = String.Empty;
                    StateEngineService.EndCodeFragment <RazorDirective> (context, 1);
                    return(Parent.Parent);
                }
                return(null);
            }
            else
            {
                switch (c)
                {
                case '{':
                    if (context.StateTag != TRANSITION)
                    {
                        return(ParseOpeningBracket(c, context));
                    }
                    break;

                case '}':
                    return(ParseClosingBracket <RazorDirective> (c, context, Parent.Parent));
                }
            }

            return(base.PushChar(c, context, ref rollback));
        }
        public override State PushChar(char c, IParseContext context, ref string rollback)
        {
            if (context.CurrentStateLength == 1)
            {
                switch (c)
                {
                case '(':
                    context.StateTag = NONE_EXPLICIT;
                    context.Nodes.Push(new RazorExplicitExpression(context.LocationMinus(2)));
                    return(null);

                default:
                    context.StateTag = NONE_IMPLICIT;
                    if (!(context.PreviousState is RazorSpeculativeState))
                    {
                        context.Nodes.Push(new RazorImplicitExpression(context.LocationMinus(2)));
                    }
                    break;
                }
            }

            switch (c)
            {
            case '(':
                if (context.StateTag == NONE_EXPLICIT)
                {
                    context.StateTag = INSIDE_BRACKET_EXPLICIT;
                }
                else if (context.StateTag == NONE_IMPLICIT)
                {
                    context.StateTag = INSIDE_BRACKET_IMPLICIT;
                }
                context.KeywordBuilder.Append(c);
                break;

            case ')':
                if (context.StateTag == NONE_EXPLICIT)
                {
                    StateEngineService.EndCodeFragment <RazorExplicitExpression> (context);
                    return(Parent);
                }
                else if (context.StateTag != NONE_IMPLICIT)
                {
                    if (context.KeywordBuilder.Length > 0)
                    {
                        context.KeywordBuilder.Remove(0, 1);
                    }
                    if (context.KeywordBuilder.Length == 0)
                    {
                        context.StateTag = (context.StateTag == INSIDE_BRACKET_IMPLICIT ? NONE_IMPLICIT : NONE_EXPLICIT);
                    }
                }
                break;

            default:
                // Space between function's name and open bracket not allowed in razor, e.g. @Html.Raw (foo)
                if (!(Char.IsLetterOrDigit(c) || allowedChars.Any(ch => ch == c)) &&
                    context.StateTag == NONE_IMPLICIT)
                {
                    StateEngineService.EndCodeFragment <RazorImplicitExpression> (context, 1);
                    rollback = String.Empty;
                    if (Parent is RazorSpeculativeState)
                    {
                        return(Parent.Parent);
                    }
                    return(Parent);
                }
                break;
            }

            return(null);
        }