1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#ifndef QMAKEPARSER_H
5#define QMAKEPARSER_H
6
7#include "qmake_global.h"
8#include "qmakevfs.h"
9#include "proitems.h"
10
11#include <qhash.h>
12#include <qstack.h>
13#ifdef PROPARSER_THREAD_SAFE
14# include <qmutex.h>
15# include <qwaitcondition.h>
16#endif
17
18QT_BEGIN_NAMESPACE
19class QMAKE_EXPORT QMakeParserHandler
20{
21public:
22 enum {
23 CategoryMask = 0xf00,
24 InfoMessage = 0x100,
25 WarningMessage = 0x200,
26 ErrorMessage = 0x300,
27
28 SourceMask = 0xf0,
29 SourceParser = 0,
30
31 CodeMask = 0xf,
32 WarnLanguage = 0,
33 WarnDeprecated,
34
35 ParserWarnLanguage = SourceParser | WarningMessage | WarnLanguage,
36 ParserWarnDeprecated = SourceParser | WarningMessage | WarnDeprecated,
37
38 ParserIoError = ErrorMessage | SourceParser,
39 ParserError
40 };
41 virtual void message(int type, const QString &msg,
42 const QString &fileName = QString(), int lineNo = 0) = 0;
43};
44
45class ProFileCache;
46class QMakeVfs;
47
48class QMAKE_EXPORT QMakeParser
49{
50public:
51 // Call this from a concurrency-free context
52 static void initialize();
53
54 enum ParseFlag {
55 ParseDefault = 0,
56 ParseUseCache = 1,
57 ParseReportMissing = 4,
58#ifdef PROEVALUATOR_DUAL_VFS
59 ParseCumulative = 8
60#else
61 ParseCumulative = 0
62#endif
63 };
64 Q_DECLARE_FLAGS(ParseFlags, ParseFlag)
65
66 QMakeParser(ProFileCache *cache, QMakeVfs *vfs, QMakeParserHandler *handler);
67
68 enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar };
69 // fileName is expected to be absolute and cleanPath()ed.
70 ProFile *parsedProFile(const QString &fileName, ParseFlags flags = ParseDefault);
71 ProFile *parsedProBlock(QStringView contents, int id, const QString &name, int line = 0,
72 SubGrammar grammar = FullGrammar);
73
74 void discardFileFromCache(int id);
75
76#ifdef PROPARSER_DEBUG
77 static QString formatProBlock(const QString &block);
78#endif
79
80private:
81 enum ScopeNesting {
82 NestNone = 0,
83 NestLoop = 1,
84 NestFunction = 2
85 };
86
87 struct BlockScope {
88 BlockScope() : start(nullptr), braceLevel(0), special(false), inBranch(false), nest(NestNone) {}
89 ushort *start; // Where this block started; store length here
90 int braceLevel; // Nesting of braces in scope
91 bool special; // Single-line conditionals inside loops, etc. cannot have else branches
92 bool inBranch; // The 'else' branch of the previous TokBranch is still open
93 uchar nest; // Into what control structures we are nested
94 };
95
96 enum ScopeState {
97 StNew, // Fresh scope
98 StCtrl, // Control statement (for or else) met on current line
99 StCond // Conditionals met on current line
100 };
101
102 enum Context { CtxTest, CtxValue, CtxPureValue, CtxArgs };
103 struct ParseCtx {
104 int parens; // Nesting of non-functional parentheses
105 int argc; // Number of arguments in current function call
106 int wordCount; // Number of words in current expression
107 Context context;
108 ushort quote; // Enclosing quote type
109 ushort terminator; // '}' if replace function call is braced, ':' if test function
110 };
111
112 bool readFile(int id, QMakeParser::ParseFlags flags, QString *contents);
113 void read(ProFile *pro, QStringView content, int line, SubGrammar grammar);
114
115 ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok);
116 ALWAYS_INLINE void putBlockLen(ushort *&tokPtr, uint len);
117 ALWAYS_INLINE void putBlock(ushort *&tokPtr, const ushort *buf, uint len);
118 void putHashStr(ushort *&pTokPtr, const ushort *buf, uint len);
119 void finalizeHashStr(ushort *buf, uint len);
120 void putLineMarker(ushort *&tokPtr);
121 ALWAYS_INLINE bool resolveVariable(ushort *xprPtr, int tlen, int needSep, ushort **ptr,
122 ushort **buf, QString *xprBuff,
123 ushort **tokPtr, QString *tokBuff,
124 const ushort *cur, QStringView in);
125 void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount);
126 void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc);
127 void warnOperator(const char *msg);
128 bool failOperator(const char *msg);
129 bool acceptColon(const char *msg);
130 void putOperator(ushort *&tokPtr);
131 void finalizeTest(ushort *&tokPtr);
132 void bogusTest(ushort *&tokPtr, const QString &msg);
133 void enterScope(ushort *&tokPtr, bool special, ScopeState state);
134 void leaveScope(ushort *&tokPtr);
135 void flushCond(ushort *&tokPtr);
136 void flushScopes(ushort *&tokPtr);
137
138 void message(int type, const QString &msg) const;
139 void parseError(const QString &msg) const
140 {
141 message(type: QMakeParserHandler::ParserError, msg);
142 m_proFile->setOk(false);
143 }
144 void languageWarning(const QString &msg) const
145 { message(type: QMakeParserHandler::ParserWarnLanguage, msg); }
146 void deprecationWarning(const QString &msg) const
147 { message(type: QMakeParserHandler::ParserWarnDeprecated, msg); }
148
149 // Current location
150 ProFile *m_proFile;
151 int m_lineNo;
152
153 QStack<BlockScope> m_blockstack;
154 ScopeState m_state;
155 int m_markLine; // Put marker for this line
156 bool m_inError; // Current line had a parsing error; suppress followup error messages
157 bool m_canElse; // Conditionals met on previous line, but no scope was opened
158 int m_invert; // Pending conditional is negated
159 enum { NoOperator, AndOperator, OrOperator } m_operator; // Pending conditional is ORed/ANDed
160
161 QString m_tmp; // Temporary for efficient toQString
162
163 ProFileCache *m_cache;
164 QMakeParserHandler *m_handler;
165 QMakeVfs *m_vfs;
166
167 // This doesn't help gcc 3.3 ...
168 template<typename T> friend class QTypeInfo;
169
170 friend class ProFileCache;
171};
172
173Q_DECLARE_OPERATORS_FOR_FLAGS(QMakeParser::ParseFlags)
174
175class QMAKE_EXPORT ProFileCache
176{
177public:
178 ProFileCache();
179 ~ProFileCache();
180
181 void discardFile(int id);
182 void discardFile(const QString &fileName, QMakeVfs *vfs);
183 void discardFiles(const QString &prefix, QMakeVfs *vfs);
184
185private:
186 struct Entry {
187 ProFile *pro;
188#ifdef PROPARSER_THREAD_SAFE
189 struct Locker {
190 Locker() : waiters(0), done(false) {}
191 QWaitCondition cond;
192 int waiters;
193 bool done;
194 };
195 Locker *locker;
196#endif
197 };
198
199 QHash<int, Entry> parsed_files;
200#ifdef PROPARSER_THREAD_SAFE
201 QMutex mutex;
202#endif
203
204 friend class QMakeParser;
205};
206
207#if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
208Q_DECLARE_TYPEINFO(QMakeParser::BlockScope, Q_RELOCATABLE_TYPE);
209Q_DECLARE_TYPEINFO(QMakeParser::Context, Q_PRIMITIVE_TYPE);
210#endif
211
212QT_END_NAMESPACE
213
214#endif // PROFILEPARSER_H
215

source code of qttools/src/linguist/shared/qmakeparser.h