106f32e7eSjoerg //===--- CommentLexer.h - Lexer for structured comments ---------*- C++ -*-===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg //  This file defines lexer for structured comments and supporting token class.
1006f32e7eSjoerg //
1106f32e7eSjoerg //===----------------------------------------------------------------------===//
1206f32e7eSjoerg 
1306f32e7eSjoerg #ifndef LLVM_CLANG_AST_COMMENTLEXER_H
1406f32e7eSjoerg #define LLVM_CLANG_AST_COMMENTLEXER_H
1506f32e7eSjoerg 
1606f32e7eSjoerg #include "clang/Basic/Diagnostic.h"
1706f32e7eSjoerg #include "clang/Basic/SourceManager.h"
1806f32e7eSjoerg #include "llvm/ADT/SmallString.h"
1906f32e7eSjoerg #include "llvm/ADT/StringRef.h"
2006f32e7eSjoerg #include "llvm/Support/Allocator.h"
2106f32e7eSjoerg #include "llvm/Support/raw_ostream.h"
2206f32e7eSjoerg 
2306f32e7eSjoerg namespace clang {
2406f32e7eSjoerg namespace comments {
2506f32e7eSjoerg 
2606f32e7eSjoerg class Lexer;
2706f32e7eSjoerg class TextTokenRetokenizer;
2806f32e7eSjoerg struct CommandInfo;
2906f32e7eSjoerg class CommandTraits;
3006f32e7eSjoerg 
3106f32e7eSjoerg namespace tok {
3206f32e7eSjoerg enum TokenKind {
3306f32e7eSjoerg   eof,
3406f32e7eSjoerg   newline,
3506f32e7eSjoerg   text,
3606f32e7eSjoerg   unknown_command,   // Command that does not have an ID.
3706f32e7eSjoerg   backslash_command, // Command with an ID, that used backslash marker.
3806f32e7eSjoerg   at_command,        // Command with an ID, that used 'at' marker.
3906f32e7eSjoerg   verbatim_block_begin,
4006f32e7eSjoerg   verbatim_block_line,
4106f32e7eSjoerg   verbatim_block_end,
4206f32e7eSjoerg   verbatim_line_name,
4306f32e7eSjoerg   verbatim_line_text,
4406f32e7eSjoerg   html_start_tag,     // <tag
4506f32e7eSjoerg   html_ident,         // attr
4606f32e7eSjoerg   html_equals,        // =
4706f32e7eSjoerg   html_quoted_string, // "blah\"blah" or 'blah\'blah'
4806f32e7eSjoerg   html_greater,       // >
4906f32e7eSjoerg   html_slash_greater, // />
5006f32e7eSjoerg   html_end_tag        // </tag
5106f32e7eSjoerg };
5206f32e7eSjoerg } // end namespace tok
5306f32e7eSjoerg 
5406f32e7eSjoerg /// Comment token.
5506f32e7eSjoerg class Token {
5606f32e7eSjoerg   friend class Lexer;
5706f32e7eSjoerg   friend class TextTokenRetokenizer;
5806f32e7eSjoerg 
5906f32e7eSjoerg   /// The location of the token.
6006f32e7eSjoerg   SourceLocation Loc;
6106f32e7eSjoerg 
6206f32e7eSjoerg   /// The actual kind of the token.
6306f32e7eSjoerg   tok::TokenKind Kind;
6406f32e7eSjoerg 
6506f32e7eSjoerg   /// Integer value associated with a token.
6606f32e7eSjoerg   ///
6706f32e7eSjoerg   /// If the token is a known command, contains command ID and TextPtr is
6806f32e7eSjoerg   /// unused (command spelling can be found with CommandTraits).  Otherwise,
6906f32e7eSjoerg   /// contains the length of the string that starts at TextPtr.
7006f32e7eSjoerg   unsigned IntVal;
7106f32e7eSjoerg 
72*13fbcb42Sjoerg   /// Length of the token spelling in comment.  Can be 0 for synthenized
73*13fbcb42Sjoerg   /// tokens.
74*13fbcb42Sjoerg   unsigned Length;
75*13fbcb42Sjoerg 
76*13fbcb42Sjoerg   /// Contains text value associated with a token.
77*13fbcb42Sjoerg   const char *TextPtr;
78*13fbcb42Sjoerg 
7906f32e7eSjoerg public:
getLocation()8006f32e7eSjoerg   SourceLocation getLocation() const LLVM_READONLY { return Loc; }
setLocation(SourceLocation SL)8106f32e7eSjoerg   void setLocation(SourceLocation SL) { Loc = SL; }
8206f32e7eSjoerg 
getEndLocation()8306f32e7eSjoerg   SourceLocation getEndLocation() const LLVM_READONLY {
8406f32e7eSjoerg     if (Length == 0 || Length == 1)
8506f32e7eSjoerg       return Loc;
8606f32e7eSjoerg     return Loc.getLocWithOffset(Length - 1);
8706f32e7eSjoerg   }
8806f32e7eSjoerg 
getKind()8906f32e7eSjoerg   tok::TokenKind getKind() const LLVM_READONLY { return Kind; }
setKind(tok::TokenKind K)9006f32e7eSjoerg   void setKind(tok::TokenKind K) { Kind = K; }
9106f32e7eSjoerg 
is(tok::TokenKind K)9206f32e7eSjoerg   bool is(tok::TokenKind K) const LLVM_READONLY { return Kind == K; }
isNot(tok::TokenKind K)9306f32e7eSjoerg   bool isNot(tok::TokenKind K) const LLVM_READONLY { return Kind != K; }
9406f32e7eSjoerg 
getLength()9506f32e7eSjoerg   unsigned getLength() const LLVM_READONLY { return Length; }
setLength(unsigned L)9606f32e7eSjoerg   void setLength(unsigned L) { Length = L; }
9706f32e7eSjoerg 
getText()9806f32e7eSjoerg   StringRef getText() const LLVM_READONLY {
9906f32e7eSjoerg     assert(is(tok::text));
10006f32e7eSjoerg     return StringRef(TextPtr, IntVal);
10106f32e7eSjoerg   }
10206f32e7eSjoerg 
setText(StringRef Text)10306f32e7eSjoerg   void setText(StringRef Text) {
10406f32e7eSjoerg     assert(is(tok::text));
10506f32e7eSjoerg     TextPtr = Text.data();
10606f32e7eSjoerg     IntVal = Text.size();
10706f32e7eSjoerg   }
10806f32e7eSjoerg 
getUnknownCommandName()10906f32e7eSjoerg   StringRef getUnknownCommandName() const LLVM_READONLY {
11006f32e7eSjoerg     assert(is(tok::unknown_command));
11106f32e7eSjoerg     return StringRef(TextPtr, IntVal);
11206f32e7eSjoerg   }
11306f32e7eSjoerg 
setUnknownCommandName(StringRef Name)11406f32e7eSjoerg   void setUnknownCommandName(StringRef Name) {
11506f32e7eSjoerg     assert(is(tok::unknown_command));
11606f32e7eSjoerg     TextPtr = Name.data();
11706f32e7eSjoerg     IntVal = Name.size();
11806f32e7eSjoerg   }
11906f32e7eSjoerg 
getCommandID()12006f32e7eSjoerg   unsigned getCommandID() const LLVM_READONLY {
12106f32e7eSjoerg     assert(is(tok::backslash_command) || is(tok::at_command));
12206f32e7eSjoerg     return IntVal;
12306f32e7eSjoerg   }
12406f32e7eSjoerg 
setCommandID(unsigned ID)12506f32e7eSjoerg   void setCommandID(unsigned ID) {
12606f32e7eSjoerg     assert(is(tok::backslash_command) || is(tok::at_command));
12706f32e7eSjoerg     IntVal = ID;
12806f32e7eSjoerg   }
12906f32e7eSjoerg 
getVerbatimBlockID()13006f32e7eSjoerg   unsigned getVerbatimBlockID() const LLVM_READONLY {
13106f32e7eSjoerg     assert(is(tok::verbatim_block_begin) || is(tok::verbatim_block_end));
13206f32e7eSjoerg     return IntVal;
13306f32e7eSjoerg   }
13406f32e7eSjoerg 
setVerbatimBlockID(unsigned ID)13506f32e7eSjoerg   void setVerbatimBlockID(unsigned ID) {
13606f32e7eSjoerg     assert(is(tok::verbatim_block_begin) || is(tok::verbatim_block_end));
13706f32e7eSjoerg     IntVal = ID;
13806f32e7eSjoerg   }
13906f32e7eSjoerg 
getVerbatimBlockText()14006f32e7eSjoerg   StringRef getVerbatimBlockText() const LLVM_READONLY {
14106f32e7eSjoerg     assert(is(tok::verbatim_block_line));
14206f32e7eSjoerg     return StringRef(TextPtr, IntVal);
14306f32e7eSjoerg   }
14406f32e7eSjoerg 
setVerbatimBlockText(StringRef Text)14506f32e7eSjoerg   void setVerbatimBlockText(StringRef Text) {
14606f32e7eSjoerg     assert(is(tok::verbatim_block_line));
14706f32e7eSjoerg     TextPtr = Text.data();
14806f32e7eSjoerg     IntVal = Text.size();
14906f32e7eSjoerg   }
15006f32e7eSjoerg 
getVerbatimLineID()15106f32e7eSjoerg   unsigned getVerbatimLineID() const LLVM_READONLY {
15206f32e7eSjoerg     assert(is(tok::verbatim_line_name));
15306f32e7eSjoerg     return IntVal;
15406f32e7eSjoerg   }
15506f32e7eSjoerg 
setVerbatimLineID(unsigned ID)15606f32e7eSjoerg   void setVerbatimLineID(unsigned ID) {
15706f32e7eSjoerg     assert(is(tok::verbatim_line_name));
15806f32e7eSjoerg     IntVal = ID;
15906f32e7eSjoerg   }
16006f32e7eSjoerg 
getVerbatimLineText()16106f32e7eSjoerg   StringRef getVerbatimLineText() const LLVM_READONLY {
16206f32e7eSjoerg     assert(is(tok::verbatim_line_text));
16306f32e7eSjoerg     return StringRef(TextPtr, IntVal);
16406f32e7eSjoerg   }
16506f32e7eSjoerg 
setVerbatimLineText(StringRef Text)16606f32e7eSjoerg   void setVerbatimLineText(StringRef Text) {
16706f32e7eSjoerg     assert(is(tok::verbatim_line_text));
16806f32e7eSjoerg     TextPtr = Text.data();
16906f32e7eSjoerg     IntVal = Text.size();
17006f32e7eSjoerg   }
17106f32e7eSjoerg 
getHTMLTagStartName()17206f32e7eSjoerg   StringRef getHTMLTagStartName() const LLVM_READONLY {
17306f32e7eSjoerg     assert(is(tok::html_start_tag));
17406f32e7eSjoerg     return StringRef(TextPtr, IntVal);
17506f32e7eSjoerg   }
17606f32e7eSjoerg 
setHTMLTagStartName(StringRef Name)17706f32e7eSjoerg   void setHTMLTagStartName(StringRef Name) {
17806f32e7eSjoerg     assert(is(tok::html_start_tag));
17906f32e7eSjoerg     TextPtr = Name.data();
18006f32e7eSjoerg     IntVal = Name.size();
18106f32e7eSjoerg   }
18206f32e7eSjoerg 
getHTMLIdent()18306f32e7eSjoerg   StringRef getHTMLIdent() const LLVM_READONLY {
18406f32e7eSjoerg     assert(is(tok::html_ident));
18506f32e7eSjoerg     return StringRef(TextPtr, IntVal);
18606f32e7eSjoerg   }
18706f32e7eSjoerg 
setHTMLIdent(StringRef Name)18806f32e7eSjoerg   void setHTMLIdent(StringRef Name) {
18906f32e7eSjoerg     assert(is(tok::html_ident));
19006f32e7eSjoerg     TextPtr = Name.data();
19106f32e7eSjoerg     IntVal = Name.size();
19206f32e7eSjoerg   }
19306f32e7eSjoerg 
getHTMLQuotedString()19406f32e7eSjoerg   StringRef getHTMLQuotedString() const LLVM_READONLY {
19506f32e7eSjoerg     assert(is(tok::html_quoted_string));
19606f32e7eSjoerg     return StringRef(TextPtr, IntVal);
19706f32e7eSjoerg   }
19806f32e7eSjoerg 
setHTMLQuotedString(StringRef Str)19906f32e7eSjoerg   void setHTMLQuotedString(StringRef Str) {
20006f32e7eSjoerg     assert(is(tok::html_quoted_string));
20106f32e7eSjoerg     TextPtr = Str.data();
20206f32e7eSjoerg     IntVal = Str.size();
20306f32e7eSjoerg   }
20406f32e7eSjoerg 
getHTMLTagEndName()20506f32e7eSjoerg   StringRef getHTMLTagEndName() const LLVM_READONLY {
20606f32e7eSjoerg     assert(is(tok::html_end_tag));
20706f32e7eSjoerg     return StringRef(TextPtr, IntVal);
20806f32e7eSjoerg   }
20906f32e7eSjoerg 
setHTMLTagEndName(StringRef Name)21006f32e7eSjoerg   void setHTMLTagEndName(StringRef Name) {
21106f32e7eSjoerg     assert(is(tok::html_end_tag));
21206f32e7eSjoerg     TextPtr = Name.data();
21306f32e7eSjoerg     IntVal = Name.size();
21406f32e7eSjoerg   }
21506f32e7eSjoerg 
21606f32e7eSjoerg   void dump(const Lexer &L, const SourceManager &SM) const;
21706f32e7eSjoerg };
21806f32e7eSjoerg 
21906f32e7eSjoerg /// Comment lexer.
22006f32e7eSjoerg class Lexer {
22106f32e7eSjoerg private:
22206f32e7eSjoerg   Lexer(const Lexer &) = delete;
22306f32e7eSjoerg   void operator=(const Lexer &) = delete;
22406f32e7eSjoerg 
22506f32e7eSjoerg   /// Allocator for strings that are semantic values of tokens and have to be
22606f32e7eSjoerg   /// computed (for example, resolved decimal character references).
22706f32e7eSjoerg   llvm::BumpPtrAllocator &Allocator;
22806f32e7eSjoerg 
22906f32e7eSjoerg   DiagnosticsEngine &Diags;
23006f32e7eSjoerg 
23106f32e7eSjoerg   const CommandTraits &Traits;
23206f32e7eSjoerg 
23306f32e7eSjoerg   const char *const BufferStart;
23406f32e7eSjoerg   const char *const BufferEnd;
23506f32e7eSjoerg 
23606f32e7eSjoerg   const char *BufferPtr;
23706f32e7eSjoerg 
23806f32e7eSjoerg   /// One past end pointer for the current comment.  For BCPL comments points
23906f32e7eSjoerg   /// to newline or BufferEnd, for C comments points to star in '*/'.
24006f32e7eSjoerg   const char *CommentEnd;
24106f32e7eSjoerg 
242*13fbcb42Sjoerg   SourceLocation FileLoc;
243*13fbcb42Sjoerg 
244*13fbcb42Sjoerg   /// If true, the commands, html tags, etc will be parsed and reported as
245*13fbcb42Sjoerg   /// separate tokens inside the comment body. If false, the comment text will
246*13fbcb42Sjoerg   /// be parsed into text and newline tokens.
247*13fbcb42Sjoerg   bool ParseCommands;
248*13fbcb42Sjoerg 
249*13fbcb42Sjoerg   enum LexerCommentState : uint8_t {
25006f32e7eSjoerg     LCS_BeforeComment,
25106f32e7eSjoerg     LCS_InsideBCPLComment,
25206f32e7eSjoerg     LCS_InsideCComment,
25306f32e7eSjoerg     LCS_BetweenComments
25406f32e7eSjoerg   };
25506f32e7eSjoerg 
25606f32e7eSjoerg   /// Low-level lexer state, track if we are inside or outside of comment.
25706f32e7eSjoerg   LexerCommentState CommentState;
25806f32e7eSjoerg 
259*13fbcb42Sjoerg   enum LexerState : uint8_t {
26006f32e7eSjoerg     /// Lexing normal comment text
26106f32e7eSjoerg     LS_Normal,
26206f32e7eSjoerg 
26306f32e7eSjoerg     /// Finished lexing verbatim block beginning command, will lex first body
26406f32e7eSjoerg     /// line.
26506f32e7eSjoerg     LS_VerbatimBlockFirstLine,
26606f32e7eSjoerg 
26706f32e7eSjoerg     /// Lexing verbatim block body line-by-line, skipping line-starting
26806f32e7eSjoerg     /// decorations.
26906f32e7eSjoerg     LS_VerbatimBlockBody,
27006f32e7eSjoerg 
27106f32e7eSjoerg     /// Finished lexing verbatim line beginning command, will lex text (one
27206f32e7eSjoerg     /// line).
27306f32e7eSjoerg     LS_VerbatimLineText,
27406f32e7eSjoerg 
27506f32e7eSjoerg     /// Finished lexing \verbatim <TAG \endverbatim part, lexing tag attributes.
27606f32e7eSjoerg     LS_HTMLStartTag,
27706f32e7eSjoerg 
27806f32e7eSjoerg     /// Finished lexing \verbatim </TAG \endverbatim part, lexing '>'.
27906f32e7eSjoerg     LS_HTMLEndTag
28006f32e7eSjoerg   };
28106f32e7eSjoerg 
28206f32e7eSjoerg   /// Current lexing mode.
28306f32e7eSjoerg   LexerState State;
28406f32e7eSjoerg 
28506f32e7eSjoerg   /// If State is LS_VerbatimBlock, contains the name of verbatim end
28606f32e7eSjoerg   /// command, including command marker.
28706f32e7eSjoerg   SmallString<16> VerbatimBlockEndCommandName;
28806f32e7eSjoerg 
28906f32e7eSjoerg   /// Given a character reference name (e.g., "lt"), return the character that
29006f32e7eSjoerg   /// it stands for (e.g., "<").
29106f32e7eSjoerg   StringRef resolveHTMLNamedCharacterReference(StringRef Name) const;
29206f32e7eSjoerg 
29306f32e7eSjoerg   /// Given a Unicode codepoint as base-10 integer, return the character.
29406f32e7eSjoerg   StringRef resolveHTMLDecimalCharacterReference(StringRef Name) const;
29506f32e7eSjoerg 
29606f32e7eSjoerg   /// Given a Unicode codepoint as base-16 integer, return the character.
29706f32e7eSjoerg   StringRef resolveHTMLHexCharacterReference(StringRef Name) const;
29806f32e7eSjoerg 
29906f32e7eSjoerg   void formTokenWithChars(Token &Result, const char *TokEnd,
30006f32e7eSjoerg                           tok::TokenKind Kind);
30106f32e7eSjoerg 
formTextToken(Token & Result,const char * TokEnd)30206f32e7eSjoerg   void formTextToken(Token &Result, const char *TokEnd) {
30306f32e7eSjoerg     StringRef Text(BufferPtr, TokEnd - BufferPtr);
30406f32e7eSjoerg     formTokenWithChars(Result, TokEnd, tok::text);
30506f32e7eSjoerg     Result.setText(Text);
30606f32e7eSjoerg   }
30706f32e7eSjoerg 
getSourceLocation(const char * Loc)30806f32e7eSjoerg   SourceLocation getSourceLocation(const char *Loc) const {
30906f32e7eSjoerg     assert(Loc >= BufferStart && Loc <= BufferEnd &&
31006f32e7eSjoerg            "Location out of range for this buffer!");
31106f32e7eSjoerg 
31206f32e7eSjoerg     const unsigned CharNo = Loc - BufferStart;
31306f32e7eSjoerg     return FileLoc.getLocWithOffset(CharNo);
31406f32e7eSjoerg   }
31506f32e7eSjoerg 
Diag(SourceLocation Loc,unsigned DiagID)31606f32e7eSjoerg   DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
31706f32e7eSjoerg     return Diags.Report(Loc, DiagID);
31806f32e7eSjoerg   }
31906f32e7eSjoerg 
32006f32e7eSjoerg   /// Eat string matching regexp \code \s*\* \endcode.
32106f32e7eSjoerg   void skipLineStartingDecorations();
32206f32e7eSjoerg 
32306f32e7eSjoerg   /// Lex comment text, including commands if ParseCommands is set to true.
32406f32e7eSjoerg   void lexCommentText(Token &T);
32506f32e7eSjoerg 
32606f32e7eSjoerg   void setupAndLexVerbatimBlock(Token &T, const char *TextBegin, char Marker,
32706f32e7eSjoerg                                 const CommandInfo *Info);
32806f32e7eSjoerg 
32906f32e7eSjoerg   void lexVerbatimBlockFirstLine(Token &T);
33006f32e7eSjoerg 
33106f32e7eSjoerg   void lexVerbatimBlockBody(Token &T);
33206f32e7eSjoerg 
33306f32e7eSjoerg   void setupAndLexVerbatimLine(Token &T, const char *TextBegin,
33406f32e7eSjoerg                                const CommandInfo *Info);
33506f32e7eSjoerg 
33606f32e7eSjoerg   void lexVerbatimLineText(Token &T);
33706f32e7eSjoerg 
33806f32e7eSjoerg   void lexHTMLCharacterReference(Token &T);
33906f32e7eSjoerg 
34006f32e7eSjoerg   void setupAndLexHTMLStartTag(Token &T);
34106f32e7eSjoerg 
34206f32e7eSjoerg   void lexHTMLStartTag(Token &T);
34306f32e7eSjoerg 
34406f32e7eSjoerg   void setupAndLexHTMLEndTag(Token &T);
34506f32e7eSjoerg 
34606f32e7eSjoerg   void lexHTMLEndTag(Token &T);
34706f32e7eSjoerg 
34806f32e7eSjoerg public:
34906f32e7eSjoerg   Lexer(llvm::BumpPtrAllocator &Allocator, DiagnosticsEngine &Diags,
35006f32e7eSjoerg         const CommandTraits &Traits, SourceLocation FileLoc,
35106f32e7eSjoerg         const char *BufferStart, const char *BufferEnd,
35206f32e7eSjoerg         bool ParseCommands = true);
35306f32e7eSjoerg 
35406f32e7eSjoerg   void lex(Token &T);
35506f32e7eSjoerg 
35606f32e7eSjoerg   StringRef getSpelling(const Token &Tok, const SourceManager &SourceMgr) const;
35706f32e7eSjoerg };
35806f32e7eSjoerg 
35906f32e7eSjoerg } // end namespace comments
36006f32e7eSjoerg } // end namespace clang
36106f32e7eSjoerg 
36206f32e7eSjoerg #endif
36306f32e7eSjoerg 
364