Exemple #1
0
    private StateResult QuotedLiteral(char quote, Func <char, bool> isEndQuotedLiteral, SyntaxKind literalType)
    {
        TakeUntil(isEndQuotedLiteral);
        if (CurrentCharacter == '\\')
        {
            TakeCurrent(); // Take the '\'

            // If the next char is the same quote that started this
            if (CurrentCharacter == quote || CurrentCharacter == '\\')
            {
                TakeCurrent(); // Take it so that we don't prematurely end the literal.
            }
            return(Stay());
        }
        else if (EndOfFile || ParserHelpers.IsNewLine(CurrentCharacter))
        {
            CurrentErrors.Add(
                RazorDiagnosticFactory.CreateParsing_UnterminatedStringLiteral(
                    new SourceSpan(CurrentStart, contentLength: 1 /* " */)));
        }
        else
        {
            TakeCurrent(); // No-op if at EOF
        }
        return(Transition(CSharpTokenizerState.Data, EndToken(literalType)));
    }
Exemple #2
0
    // CSharp Spec §2.4.2
    private StateResult Identifier()
    {
        Debug.Assert(IsIdentifierStart(CurrentCharacter));
        TakeCurrent();
        TakeUntil(c => !IsIdentifierPart(c));
        SyntaxToken token = null;

        if (HaveContent)
        {
            CSharpKeyword keyword;
            var           type         = SyntaxKind.Identifier;
            var           tokenContent = Buffer.ToString();
            if (_keywords.TryGetValue(tokenContent, out keyword))
            {
                type = SyntaxKind.Keyword;
            }

            token = SyntaxFactory.Token(type, tokenContent);

            Buffer.Clear();
            CurrentErrors.Clear();
        }

        return(Stay(token));
    }
Exemple #3
0
        // CSharp Spec §2.4.2
        private StateResult Identifier()
        {
            Debug.Assert(IsIdentifierStart(CurrentCharacter));
            TakeCurrent();
            TakeUntil(c => !IsIdentifierPart(c));
            CSharpSymbol symbol = null;

            if (HaveContent)
            {
                CSharpKeyword keyword;
                var           type          = CSharpSymbolType.Identifier;
                var           symbolContent = Buffer.ToString();
                if (_keywords.TryGetValue(symbolContent, out keyword))
                {
                    type = CSharpSymbolType.Keyword;
                }

                symbol = new CSharpSymbol(symbolContent, type)
                {
                    Keyword = type == CSharpSymbolType.Keyword ? (CSharpKeyword?)keyword : null,
                };

                Buffer.Clear();
                CurrentErrors.Clear();
            }

            return(Stay(symbol));
        }
Exemple #4
0
        private StateResult QuotedLiteral(char quote, CSharpSymbolType literalType)
        {
            TakeUntil(c => c == '\\' || c == quote || ParserHelpers.IsNewLine(c));
            if (CurrentCharacter == '\\')
            {
                TakeCurrent(); // Take the '\'

                // If the next char is the same quote that started this
                if (CurrentCharacter == quote || CurrentCharacter == '\\')
                {
                    TakeCurrent(); // Take it so that we don't prematurely end the literal.
                }
                return(Stay());
            }
            else if (EndOfFile || ParserHelpers.IsNewLine(CurrentCharacter))
            {
                CurrentErrors.Add(
                    new RazorError(
                        RazorResources.ParseError_Unterminated_String_Literal,
                        CurrentStart,
                        length: 1 /* " */));
            }
            else
            {
                TakeCurrent(); // No-op if at EOF
            }
            return(Transition(EndSymbol(literalType), Data));
        }
Exemple #5
0
        /// <summary>
        /// Tokenizes a quoted literal.
        /// </summary>
        /// <param name="quote">The quote character.</param>
        /// <returns>The state result.</returns>
        private StateResult QuotedLiteral(char quote)
        {
            TakeUntil(c => c == '\\' || c == quote || ParserHelpers.IsNewLine(c));
            if (CurrentCharacter == '\\')
            {
                TakeCurrent();

                if (CurrentCharacter == quote || CurrentCharacter == '\\')
                {
                    TakeCurrent();
                }

                return(Stay());
            }

            if (EndOfFile || ParserHelpers.IsNewLine(CurrentCharacter))
            {
                CurrentErrors.Add(new Error("Untermined string literal", CurrentStart));
            }
            else
            {
                TakeCurrent();
            }

            return(Stay(EndSymbol(HandlebarsSymbolType.StringLiteral)));
        }
Exemple #6
0
        protected TSymbol EndSymbol(SourceLocation start, TSymbolType type)
        {
            TSymbol sym = null;

            if (HaveContent)
            {
                sym = CreateSymbol(start, Buffer.ToString(), type, CurrentErrors.ToArray());
            }
            StartSymbol();
            return(sym);
        }
Exemple #7
0
 // CSharp Spec §2.3.2
 private StateResult BlockComment()
 {
     TakeUntil(c => c == '*');
     if (EndOfFile)
     {
         CurrentErrors.Add(new RazorError(RazorResources.ParseError_BlockComment_Not_Terminated, CurrentStart));
         return(Transition(EndSymbol(CSharpSymbolType.Comment), Data));
     }
     if (CurrentCharacter == '*')
     {
         TakeCurrent();
         if (CurrentCharacter == '/')
         {
             TakeCurrent();
             return(Transition(EndSymbol(CSharpSymbolType.Comment), Data));
         }
     }
     return(Stay());
 }
Exemple #8
0
 private StateResult VerbatimStringLiteral()
 {
     TakeUntil(c => c == '"');
     if (CurrentCharacter == '"')
     {
         TakeCurrent();
         if (CurrentCharacter == '"')
         {
             TakeCurrent();
             // Stay in the literal, this is an escaped "
             return(Stay());
         }
     }
     else if (EndOfFile)
     {
         CurrentErrors.Add(new RazorError(RazorResources.ParseError_Unterminated_String_Literal, CurrentStart));
     }
     return(Transition(EndSymbol(CSharpSymbolType.StringLiteral), Data));
 }
 private StateResult QuotedLiteral(char quote, CSharpSymbolType literalType)
 {
     TakeUntil(c => c == '\\' || c == quote || ParserHelpers.IsNewLine(c));
     if (CurrentCharacter == '\\')
     {
         TakeCurrent(); // Take the '\'
         TakeCurrent(); // Take the next char as well (multi-char escapes don't matter)
         return(Stay());
     }
     else if (EndOfFile || ParserHelpers.IsNewLine(CurrentCharacter))
     {
         CurrentErrors.Add(new RazorError(RazorResources.ParseError_Unterminated_String_Literal, CurrentStart));
     }
     else
     {
         TakeCurrent(); // No-op if at EOF
     }
     return(Transition(EndSymbol(literalType), Data));
 }
Exemple #10
0
 private StateResult VerbatimStringLiteral()
 {
     TakeUntil(c => c == '"');
     if (CurrentCharacter == '"')
     {
         TakeCurrent();
         if (CurrentCharacter == '"')
         {
             TakeCurrent();
             // Stay in the literal, this is an escaped "
             return(Stay());
         }
     }
     else if (EndOfFile)
     {
         CurrentErrors.Add(
             RazorDiagnosticFactory.CreateParsing_UnterminatedStringLiteral(
                 new SourceSpan(CurrentStart, contentLength: 1 /* end of file */)));
     }
     return(Transition(CSharpTokenizerState.Data, EndToken(SyntaxKind.StringLiteral)));
 }
Exemple #11
0
        /// <summary>
        /// Attempts to begin a tag by matching the opening braces.
        /// </summary>
        /// <returns>The state result.</returns>
        private StateResult BeginTag()
        {
            var type = HandlebarsSymbolType.OpenTag;

            if (CurrentCharacter != '{')
            {
                CurrentErrors.Add(new Error("Expected '{'", CurrentLocation));

                // We can't process this any more, so stop.
                return(Transition(Stop));
            }

            TakeCurrent();

            if (CurrentCharacter != '{')
            {
                CurrentErrors.Add(new Error("Expected '{'", CurrentLocation));

                // We can't process this any more, so stop.
                return(Transition(Stop));
            }

            TakeCurrent();

            if (CurrentCharacter == '{')
            {
                // We're at a raw tag '{{{'
                TakeCurrent();
                // Change the symbol type.
                type = HandlebarsSymbolType.RawOpenTag;
            }
            else if (CurrentCharacter == '#')
            {
                // We're at the start of a block tag.
                return(Transition(EndSymbol(type), () => BeginTagContent(false)));
            }

            // Transition to the start of tag content.
            return(Transition(EndSymbol(type), () => BeginTagContent(type == HandlebarsSymbolType.RawOpenTag)));
        }
Exemple #12
0
        /// <summary>
        /// Attempts to end a tag by matching the closing braces.
        /// </summary>
        /// <param name="raw">True if we are expected to end a raw tag '}}}'</param>
        /// <returns>The state result.</returns>
        private StateResult EndTag(bool raw)
        {
            if (CurrentCharacter != '}')
            {
                CurrentErrors.Add(new Error("Expected '}'", CurrentLocation));

                // We can't process this any more, so stop.
                return(Transition(Stop));
            }

            TakeCurrent();

            if (CurrentCharacter != '}')
            {
                CurrentErrors.Add(new Error("Expected '}'", CurrentLocation));

                // We can't process this any more, so stop.
                return(Transition(Stop));
            }

            TakeCurrent();

            if (CurrentCharacter != '}' && raw)
            {
                CurrentErrors.Add(new Error("Expected '}'", CurrentLocation));

                // We can't process this any more, so stop.
                return(Transition(Stop));
            }

            if (CurrentCharacter == '}' && raw)
            {
                TakeCurrent();
                // We're done processing this '}}}' sequence, so let's finish here and return to the Data state.
                return(Transition(EndSymbol(HandlebarsSymbolType.RawCloseTag), Data));
            }

            // We're done processing this '}}' sequence, so let's finish here and return to the Data state.
            return(Transition(EndSymbol(HandlebarsSymbolType.CloseTag), Data));
        }
Exemple #13
0
    // CSharp Spec §2.3.2
    private StateResult BlockComment()
    {
        TakeUntil(c => c == '*');
        if (EndOfFile)
        {
            CurrentErrors.Add(
                RazorDiagnosticFactory.CreateParsing_BlockCommentNotTerminated(
                    new SourceSpan(CurrentStart, contentLength: 1 /* end of file */)));

            return(Transition(CSharpTokenizerState.Data, EndToken(SyntaxKind.CSharpComment)));
        }
        if (CurrentCharacter == '*')
        {
            TakeCurrent();
            if (CurrentCharacter == '/')
            {
                TakeCurrent();
                return(Transition(CSharpTokenizerState.Data, EndToken(SyntaxKind.CSharpComment)));
            }
        }
        return(Stay());
    }
Exemple #14
0
        protected TSymbol EndSymbol(TSymbolType type)
        {
            TSymbol symbol = null;

            if (HaveContent)
            {
                // Perf: Don't allocate a new errors array unless necessary.
                var errors = CurrentErrors.Count == 0 ? RazorDiagnostic.EmptyArray : new RazorDiagnostic[CurrentErrors.Count];
                for (var i = 0; i < CurrentErrors.Count; i++)
                {
                    errors[i] = CurrentErrors[i];
                }

                var symbolContent = GetSymbolContent(type);
                Debug.Assert(string.Equals(symbolContent, Buffer.ToString(), StringComparison.Ordinal));
                symbol = CreateSymbol(symbolContent, type, errors);

                Buffer.Clear();
                CurrentErrors.Clear();
            }

            return(symbol);
        }
Exemple #15
0
    protected SyntaxToken EndToken(SyntaxKind type)
    {
        SyntaxToken token = null;

        if (HaveContent)
        {
            // Perf: Don't allocate a new errors array unless necessary.
            var errors = CurrentErrors.Count == 0 ? RazorDiagnostic.EmptyArray : new RazorDiagnostic[CurrentErrors.Count];
            for (var i = 0; i < CurrentErrors.Count; i++)
            {
                errors[i] = CurrentErrors[i];
            }

            var tokenContent = GetTokenContent(type);
            Debug.Assert(string.Equals(tokenContent, Buffer.ToString(), StringComparison.Ordinal));
            token = CreateToken(tokenContent, type, errors);

            Buffer.Clear();
            CurrentErrors.Clear();
        }

        return(token);
    }
Exemple #16
0
 private StateResult VerbatimStringLiteral()
 {
     TakeUntil(c => c == '"');
     if (CurrentCharacter == '"')
     {
         TakeCurrent();
         if (CurrentCharacter == '"')
         {
             TakeCurrent();
             // Stay in the literal, this is an escaped "
             return(Stay());
         }
     }
     else if (EndOfFile)
     {
         CurrentErrors.Add(
             new RazorError(
                 LegacyResources.ParseError_Unterminated_String_Literal,
                 CurrentStart,
                 length: 1 /* end of file */));
     }
     return(Transition(CSharpTokenizerState.Data, EndSymbol(CSharpSymbolType.StringLiteral)));
 }
Exemple #17
0
 // CSharp Spec §2.3.2
 private StateResult BlockComment()
 {
     TakeUntil(c => c == '*');
     if (EndOfFile)
     {
         CurrentErrors.Add(
             new RazorError(
                 LegacyResources.ParseError_BlockComment_Not_Terminated,
                 CurrentStart,
                 length: 1 /* end of file */));
         return(Transition(CSharpTokenizerState.Data, EndSymbol(CSharpSymbolType.Comment)));
     }
     if (CurrentCharacter == '*')
     {
         TakeCurrent();
         if (CurrentCharacter == '/')
         {
             TakeCurrent();
             return(Transition(CSharpTokenizerState.Data, EndSymbol(CSharpSymbolType.Comment)));
         }
     }
     return(Stay());
 }
Exemple #18
0
 protected void StartSymbol()
 {
     Buffer.Clear();
     CurrentStart = CurrentLocation;
     CurrentErrors.Clear();
 }
Exemple #19
0
        /// <summary>
        /// Attempts to begin matching the content of a tag.
        /// </summary>
        /// <param name="raw">True if we are expected a raw tag.</param>
        /// <returns>The state result.</returns>
        private StateResult BeginTagContent(bool raw)
        {
            switch (CurrentCharacter)
            {
            case '~':
            {
                TakeCurrent();
                // We've matched a ~ character - this is for ensuring the tag braces are expanded as whitespace instead of being collapsed.
                return(Stay(EndSymbol(HandlebarsSymbolType.Tilde)));
            }

            case '!':
            {
                if (raw)
                {
                    // This is an invalid tag, so set and error and exit.
                    CurrentErrors.Add(new Error("Unexpected '!' in raw tag.", CurrentLocation));
                    return(Transition(Stop));
                }
                TakeCurrent();
                // We've matched a ! character - this is the start of a comment.
                return(Transition(EndSymbol(HandlebarsSymbolType.Bang), BeginComment));
            }

            case '>':
            {
                if (raw)
                {
                    // This is an invalid tag, so set and error and exit.
                    CurrentErrors.Add(new Error("Unexpected '>' in raw tag.", CurrentLocation));
                    return(Transition(Stop));
                }
                TakeCurrent();
                // We've matched a > character - this is the start of a reference to a partial template.
                return(Transition(EndSymbol(HandlebarsSymbolType.RightArrow), () => ContinueTagContent(false)));
            }

            case '^':
            {
                if (raw)
                {
                    // This is an invalid tag, so set and error and exit.
                    CurrentErrors.Add(new Error("Unexpected '^' in raw tag.", CurrentLocation));
                    return(Transition(Stop));
                }
                TakeCurrent();
                // We've matched a ^ character - this is the start of a negation.
                return(Transition(EndSymbol(HandlebarsSymbolType.Negate), () => ContinueTagContent(false)));
            }

            case '#':
            {
                if (raw)
                {
                    // This is an invalid tag, so set and error and exit.
                    CurrentErrors.Add(new Error("Unexpected '#' in raw tag.", CurrentLocation));
                    return(Transition(Stop));
                }
                TakeCurrent();
                // We've matched a ^ character - this is the start of a negation.
                return(Transition(EndSymbol(HandlebarsSymbolType.Hash), () => ContinueTagContent(false)));
            }

            case '&':
            {
                TakeCurrent();
                // We've matched a & character
                return(Transition(EndSymbol(HandlebarsSymbolType.Ampersand), () => ContinueTagContent(false)));
            }

            case '@':
            {
                TakeCurrent();
                // We've matched a variable reference character.
                return(Transition(EndSymbol(HandlebarsSymbolType.At), () => ContinueTagContent(false)));
            }

            default:
            {
                // Transition to the tag content.
                return(Transition(() => ContinueTagContent(raw)));
            }
            }
        }
Exemple #20
0
        /// <summary>
        /// Continues the content of the tag.
        /// </summary>
        /// <param name="raw">True if we are expected a raw tag.</param>
        /// <returns>The state result.</returns>
        private StateResult ContinueTagContent(bool raw)
        {
            if (CurrentCharacter == '@')
            {
                TakeCurrent();

                return(Stay(EndSymbol(HandlebarsSymbolType.At)));
            }

            if (HandlebarsHelpers.IsIdentifierStart(CurrentCharacter))
            {
                return(Identifier());
            }

            if (Char.IsDigit(CurrentCharacter))
            {
                return(NumericLiteral());
            }

            switch (CurrentCharacter)
            {
            case '.':
            {
                TakeCurrent();
                if (CurrentCharacter == '/')
                {
                    // We've matched a link to the current context.
                    TakeCurrent();
                    return(Stay(EndSymbol(HandlebarsSymbolType.CurrentContext)));
                }

                if (CurrentCharacter == '.' && Peek() == '/')
                {
                    // We've matched a link to the parent context.
                    TakeCurrent();
                    TakeCurrent();
                    return(Stay(EndSymbol(HandlebarsSymbolType.ParentContext)));
                }

                // We've matched a dot, which could be part of an expression.
                return(Stay(EndSymbol(HandlebarsSymbolType.Dot)));
            }

            case '/':
            {
                TakeCurrent();
                // We've matched a forward-slash, which could be part of an expression.
                return(Stay(EndSymbol(HandlebarsSymbolType.Slash)));
            }

            case ' ':
            {
                // Take all the available whitespace.
                TakeUntil(c => !ParserHelpers.IsWhiteSpace(c));
                return(Stay(EndSymbol(HandlebarsSymbolType.WhiteSpace)));
            }

            case '~':
            {
                TakeCurrent();
                // We've reached a '~' character, so jump to the end of the tag.
                return(Transition(EndSymbol(HandlebarsSymbolType.Tilde), () => EndTag(raw)));
            }

            case '"':
            case '\'':
            {
                var quote = CurrentCharacter;
                TakeCurrent();
                // We've reached a quoted literal.
                return(QuotedLiteral(quote));
            }

            case '=':
            {
                // We're reached a map assignment.
                TakeCurrent();
                return(Stay(EndSymbol(HandlebarsSymbolType.Assign)));
            }

            case '}':
            {
                // We've reached a closing tag, so transition away.
                return(Transition(() => EndTag(raw)));
            }

            default:
            {
                CurrentErrors.Add(new Error("Unexpected character: " + CurrentCharacter, CurrentLocation));
                return(Transition(Stop));
            }
            }
        }