1 //===--- UnwrappedLineParser.h - Format C++ code ----------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief This file contains the declaration of the UnwrappedLineParser,
12 /// which turns a stream of tokens into UnwrappedLines.
13 ///
14 //===----------------------------------------------------------------------===//
15 
16 #ifndef LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H
17 #define LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H
18 
19 #include "clang/Basic/IdentifierTable.h"
20 #include "clang/Format/Format.h"
21 #include "FormatToken.h"
22 #include <list>
23 
24 namespace clang {
25 namespace format {
26 
27 /// \brief An unwrapped line is a sequence of \c Token, that we would like to
28 /// put on a single line if there was no column limit.
29 ///
30 /// This is used as a main interface between the \c UnwrappedLineParser and the
31 /// \c UnwrappedLineFormatter. The key property is that changing the formatting
32 /// within an unwrapped line does not affect any other unwrapped lines.
33 struct UnwrappedLine {
34   UnwrappedLine() : Level(0), InPPDirective(false), MustBeDeclaration(false) {
35   }
36 
37   // FIXME: Don't use std::list here.
38   /// \brief The \c Tokens comprising this \c UnwrappedLine.
39   std::list<FormatToken *> Tokens;
40 
41   /// \brief The indent level of the \c UnwrappedLine.
42   unsigned Level;
43 
44   /// \brief Whether this \c UnwrappedLine is part of a preprocessor directive.
45   bool InPPDirective;
46 
47   bool MustBeDeclaration;
48 };
49 
50 class UnwrappedLineConsumer {
51 public:
52   virtual ~UnwrappedLineConsumer() {
53   }
54   virtual void consumeUnwrappedLine(const UnwrappedLine &Line) = 0;
55 };
56 
57 class FormatTokenSource;
58 
59 class UnwrappedLineParser {
60 public:
61   UnwrappedLineParser(const FormatStyle &Style, ArrayRef<FormatToken *> Tokens,
62                       UnwrappedLineConsumer &Callback);
63 
64   /// Returns true in case of a structural error.
65   bool parse();
66 
67 private:
68   void parseFile();
69   void parseLevel(bool HasOpeningBrace);
70   void parseBlock(bool MustBeDeclaration, unsigned AddLevels = 1);
71   void parsePPDirective();
72   void parsePPDefine();
73   void parsePPIf();
74   void parsePPIfdef();
75   void parsePPElIf();
76   void parsePPElse();
77   void parsePPEndIf();
78   void parsePPUnknown();
79   void parseStructuralElement();
80   bool tryToParseBracedList();
81   void parseBracedList();
82   void parseReturn();
83   void parseParens();
84   void parseIfThenElse();
85   void parseForOrWhileLoop();
86   void parseDoWhile();
87   void parseLabel();
88   void parseCaseLabel();
89   void parseSwitch();
90   void parseNamespace();
91   void parseAccessSpecifier();
92   void parseEnum();
93   void parseRecord();
94   void parseObjCProtocolList();
95   void parseObjCUntilAtEnd();
96   void parseObjCInterfaceOrImplementation();
97   void parseObjCProtocol();
98   void addUnwrappedLine();
99   bool eof() const;
100   void nextToken();
101   void readToken();
102   void flushComments(bool NewlineBeforeNext);
103   void pushToken(FormatToken *Tok);
104   void calculateBraceTypes();
105   void pushPPConditional();
106 
107   // Represents what type of block a left brace opens.
108   enum LBraceState {
109     BS_Unknown,
110     BS_Block,
111     BS_BracedInit
112   };
113 
114   // FIXME: We are constantly running into bugs where Line.Level is incorrectly
115   // subtracted from beyond 0. Introduce a method to subtract from Line.Level
116   // and use that everywhere in the Parser.
117   OwningPtr<UnwrappedLine> Line;
118 
119   // Comments are sorted into unwrapped lines by whether they are in the same
120   // line as the previous token, or not. If not, they belong to the next token.
121   // Since the next token might already be in a new unwrapped line, we need to
122   // store the comments belonging to that token.
123   SmallVector<FormatToken *, 1> CommentsBeforeNextToken;
124   FormatToken *FormatTok;
125   bool MustBreakBeforeNextToken;
126 
127   // The parsed lines. Only added to through \c CurrentLines.
128   std::vector<UnwrappedLine> Lines;
129 
130   // Preprocessor directives are parsed out-of-order from other unwrapped lines.
131   // Thus, we need to keep a list of preprocessor directives to be reported
132   // after an unwarpped line that has been started was finished.
133   std::vector<UnwrappedLine> PreprocessorDirectives;
134 
135   // New unwrapped lines are added via CurrentLines.
136   // Usually points to \c &Lines. While parsing a preprocessor directive when
137   // there is an unfinished previous unwrapped line, will point to
138   // \c &PreprocessorDirectives.
139   std::vector<UnwrappedLine> *CurrentLines;
140 
141   // We store for each line whether it must be a declaration depending on
142   // whether we are in a compound statement or not.
143   std::vector<bool> DeclarationScopeStack;
144 
145   // Will be true if we encounter an error that leads to possibily incorrect
146   // indentation levels.
147   bool StructuralError;
148 
149   const FormatStyle &Style;
150   FormatTokenSource *Tokens;
151   UnwrappedLineConsumer &Callback;
152 
153   // FIXME: This is a temporary measure until we have reworked the ownership
154   // of the format tokens. The goal is to have the actual tokens created and
155   // owned outside of and handed into the UnwrappedLineParser.
156   ArrayRef<FormatToken *> AllTokens;
157 
158   // FIXME: Currently we cannot store attributes with tokens, as we treat
159   // them as read-only; thus, we now store the brace state indexed by the
160   // position of the token in the stream (see \c AllTokens).
161   SmallVector<LBraceState, 16> LBraces;
162 
163   // Represents preprocessor branch type, so we can find matching
164   // #if/#else/#endif directives.
165   enum PPBranchKind {
166     PP_Conditional,  // Any #if, #ifdef, #ifndef, #elif, block outside #if 0
167     PP_Unreachable   // #if 0 or a conditional preprocessor block inside #if 0
168   };
169 
170   // Keeps a stack of currently active preprocessor branching directives.
171   SmallVector<PPBranchKind, 16> PPStack;
172 
173   friend class ScopedLineState;
174 };
175 
176 } // end namespace format
177 } // end namespace clang
178 
179 #endif // LLVM_CLANG_FORMAT_UNWRAPPED_LINE_PARSER_H
180