1 // Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com>
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 // THE SOFTWARE.
20 
21 #pragma once
22 
23 #include "CPlusPlusForwardDeclarations.h"
24 #include "ASTfwd.h"
25 #include "Token.h"
26 #include "DiagnosticClient.h"
27 #include <cstdio>
28 #include <unordered_map>
29 #include <vector>
30 
31 namespace CPlusPlus {
32 
33 class CPLUSPLUS_EXPORT TranslationUnit
34 {
35     TranslationUnit(const TranslationUnit &other);
36     void operator =(const TranslationUnit &other);
37 
38 public:
39     TranslationUnit(Control *control, const StringLiteral *fileId);
40     ~TranslationUnit();
41 
42     Control *control() const;
43 
44     const StringLiteral *fileId() const;
45     const char *fileName() const;
46     int fileNameLength() const;
47 
48     const char *firstSourceChar() const;
49     const char *lastSourceChar() const;
50     int sourceLength() const;
51 
52     void setSource(const char *source, int size);
53 
tokenCount()54     int tokenCount() const { return _tokens ? int(_tokens->size()) : 0; }
tokenAt(int index)55     const Token &tokenAt(int index) const
56     { return _tokens && index < tokenCount() ? (*_tokens)[index] : nullToken; }
57 
tokenKind(int index)58     Kind tokenKind(int index) const { return tokenAt(index).kind(); }
59     const char *spell(int index) const;
60 
61     int commentCount() const;
62     const Token &commentAt(int index) const;
63 
64     int matchingBrace(int index) const;
65     const Identifier *identifier(int index) const;
66     const Literal *literal(int index) const;
67     const StringLiteral *stringLiteral(int index) const;
68     const NumericLiteral *numericLiteral(int index) const;
69 
70     MemoryPool *memoryPool() const;
71     AST *ast() const;
72 
blockErrors()73     bool blockErrors() const { return f._blockErrors; }
blockErrors(bool block)74     bool blockErrors(bool block)
75     {
76         const bool previous = f._blockErrors;
77         f._blockErrors = block;
78         return previous;
79     }
80 
81     void warning(int index, const char *fmt, ...);
82     void error(int index, const char *fmt, ...);
83     void fatal(int index, const char *fmt, ...);
84 
85     void message(DiagnosticClient::Level level, int index,
86                  const char *format, va_list ap);
87 
88     bool isTokenized() const;
89     void tokenize();
90 
91     bool skipFunctionBody() const;
92     void setSkipFunctionBody(bool skipFunctionBody);
93 
94     bool isParsed() const;
95 
96     enum ParseMode {
97         ParseTranlationUnit,
98         ParseDeclaration,
99         ParseExpression,
100         ParseDeclarator,
101         ParseStatement
102     };
103 
104     bool parse(ParseMode mode = ParseTranlationUnit);
105 
106     void resetAST();
107     void release();
108 
109     void getTokenStartPosition(int index, int *line,
110                                int *column = nullptr,
111                                const StringLiteral **fileName = nullptr) const;
112 
113     void getTokenEndPosition(int index, int *line,
114                              int *column = nullptr,
115                              const StringLiteral **fileName = nullptr) const;
116 
117     void getPosition(int utf16charOffset,
118                      int *line,
119                      int *column = nullptr,
120                      const StringLiteral **fileName = nullptr) const;
121 
122     void getTokenPosition(int index,
123                           int *line,
124                           int *column = nullptr,
125                           const StringLiteral **fileName = nullptr) const;
126 
127     void pushLineOffset(int offset);
128     void pushPreprocessorLine(int utf16charOffset,
129                               int line,
130                               const StringLiteral *fileName);
131 
132     int findPreviousLineOffset(int tokenIndex) const;
133 
134     bool maybeSplitGreaterGreaterToken(int tokenIndex);
135 
languageFeatures()136     LanguageFeatures languageFeatures() const { return _languageFeatures; }
setLanguageFeatures(LanguageFeatures features)137     void setLanguageFeatures(LanguageFeatures features) { _languageFeatures = features; }
138 
139 private:
140     struct PPLine {
141         int utf16charOffset;
142         int line;
143         const StringLiteral *fileName;
144 
145         PPLine(int utf16charOffset = 0,
146                int line = 0,
147                const StringLiteral *fileName = nullptr)
utf16charOffsetPPLine148             : utf16charOffset(utf16charOffset), line(line), fileName(fileName)
149         { }
150 
151         bool operator == (const PPLine &other) const
152         { return utf16charOffset == other.utf16charOffset; }
153 
154         bool operator != (const PPLine &other) const
155         { return utf16charOffset != other.utf16charOffset; }
156 
157         bool operator < (const PPLine &other) const
158         { return utf16charOffset < other.utf16charOffset; }
159     };
160 
161     void releaseTokensAndComments();
162     int findLineNumber(int utf16charOffset) const;
163     int findColumnNumber(int utf16CharOffset, int lineNumber) const;
164     PPLine findPreprocessorLine(int utf16charOffset) const;
165 
166     static const Token nullToken;
167 
168     Control *_control;
169     const StringLiteral *_fileId;
170     const char *_firstSourceChar;
171     const char *_lastSourceChar;
172     std::vector<Token> *_tokens;
173     std::vector<Token> *_comments;
174     std::vector<int> _lineOffsets;
175     std::vector<PPLine> _ppLines;
176     typedef std::unordered_map<unsigned, std::pair<int, int> > TokenLineColumn;
177     TokenLineColumn _expandedLineColumn;
178     MemoryPool *_pool;
179     AST *_ast;
180     TranslationUnit *_previousTranslationUnit;
181     struct Flags {
182         unsigned _tokenized: 1;
183         unsigned _parsed: 1;
184         unsigned _blockErrors: 1;
185         unsigned _skipFunctionBody: 1;
186     };
187     union {
188         unsigned _flags;
189         Flags f;
190     };
191     LanguageFeatures _languageFeatures;
192 };
193 
194 } // namespace CPlusPlus
195