1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the Qt Linguist of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef PROFILEPARSER_H
43#define PROFILEPARSER_H
44
45#include "proparser_global.h"
46#include "proitems.h"
47#include <QtCore/QHash>
48#include <QtCore/QStack>
49#ifdef PROPARSER_THREAD_SAFE
50# include <QtCore/QMutex>
51# include <QtCore/QWaitCondition>
52#endif
53
54// Be fast even for debug builds
55#ifdef __GNUC__
56# define ALWAYS_INLINE inline __attribute__((always_inline))
57#elif defined(_MSC_VER)
58# define ALWAYS_INLINE __forceinline
59#else
60# define ALWAYS_INLINE inline
61#endif
62
63QT_BEGIN_NAMESPACE
64class PROPARSER_EXPORT ProFileParserHandler
65{
66public:
67 // Some error during parsing
68 virtual void parseError(const QString &filename, int lineNo, const QString &msg) = 0;
69};
70
71class ProFileCache;
72
73class PROPARSER_EXPORT ProFileParser
74{
75public:
76 // Call this from a concurrency-free context
77 static void initialize();
78
79 ProFileParser(ProFileCache *cache, ProFileParserHandler *handler);
80
81 // fileName is expected to be absolute and cleanPath()ed.
82 // If contents is non-null, it will be used instead of the file's actual content
83 ProFile *parsedProFile(const QString &fileName, bool cache = false,
84 const QString *contents = 0);
85 ProFile *parsedProBlock(const QString &name, const QString &contents)
86 { return parsedProFile(name, false, &contents); }
87
88private:
89 struct BlockScope {
90 BlockScope() : start(0), braceLevel(0), special(false), inBranch(false) {}
91 BlockScope(const BlockScope &other) { *this = other; }
92 ushort *start; // Where this block started; store length here
93 int braceLevel; // Nesting of braces in scope
94 bool special; // Single-line conditionals inside loops, etc. cannot have else branches
95 bool inBranch; // The 'else' branch of the previous TokBranch is still open
96 };
97
98 enum ScopeState {
99 StNew, // Fresh scope
100 StCtrl, // Control statement (for or else) met on current line
101 StCond // Conditionals met on current line
102 };
103
104 enum Context { CtxTest, CtxValue, CtxArgs };
105 struct ParseCtx {
106 int parens; // Nesting of non-functional parentheses
107 int argc; // Number of arguments in current function call
108 int wordCount; // Number of words in current expression
109 Context context;
110 ushort quote; // Enclosing quote type
111 ushort terminator; // '}' if replace function call is braced, ':' if test function
112 };
113
114 bool read(ProFile *pro);
115 bool read(ProFile *pro, const QString &content);
116
117 ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok);
118 ALWAYS_INLINE void putBlockLen(ushort *&tokPtr, uint len);
119 ALWAYS_INLINE void putBlock(ushort *&tokPtr, const ushort *buf, uint len);
120 void putHashStr(ushort *&pTokPtr, const ushort *buf, uint len);
121 void finalizeHashStr(ushort *buf, uint len);
122 void putLineMarker(ushort *&tokPtr);
123 void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount);
124 void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc);
125 void finalizeTest(ushort *&tokPtr);
126 void bogusTest(ushort *&tokPtr);
127 void enterScope(ushort *&tokPtr, bool special, ScopeState state);
128 void leaveScope(ushort *&tokPtr);
129 void flushCond(ushort *&tokPtr);
130 void flushScopes(ushort *&tokPtr);
131
132 void parseError(const QString &msg) const;
133
134 // Current location
135 ProFile *m_proFile;
136 int m_lineNo;
137
138 QStack<BlockScope> m_blockstack;
139 ScopeState m_state;
140 int m_markLine; // Put marker for this line
141 bool m_inError; // Current line had a parsing error; suppress followup error messages
142 bool m_canElse; // Conditionals met on previous line, but no scope was opened
143 bool m_invert; // Pending conditional is negated
144 enum { NoOperator, AndOperator, OrOperator } m_operator; // Pending conditional is ORed/ANDed
145
146 QString m_tmp; // Temporary for efficient toQString
147
148 ProFileCache *m_cache;
149 ProFileParserHandler *m_handler;
150
151 // This doesn't help gcc 3.3 ...
152 template<typename T> friend class QTypeInfo;
153
154 friend class ProFileCache;
155};
156
157class PROPARSER_EXPORT ProFileCache
158{
159public:
160 ProFileCache() {}
161 ~ProFileCache();
162
163 void discardFile(const QString &fileName);
164 void discardFiles(const QString &prefix);
165
166private:
167 struct Entry {
168 ProFile *pro;
169#ifdef PROPARSER_THREAD_SAFE
170 struct Locker {
171 Locker() : waiters(0), done(false) {}
172 QWaitCondition cond;
173 int waiters;
174 bool done;
175 };
176 Locker *locker;
177#endif
178 };
179
180 QHash<QString, Entry> parsed_files;
181#ifdef PROPARSER_THREAD_SAFE
182 QMutex mutex;
183#endif
184
185 friend class ProFileParser;
186};
187
188#if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
189Q_DECLARE_TYPEINFO(ProFileParser::BlockScope, Q_MOVABLE_TYPE);
190Q_DECLARE_TYPEINFO(ProFileParser::Context, Q_PRIMITIVE_TYPE);
191#endif
192
193QT_END_NAMESPACE
194
195#endif // PROFILEPARSER_H
196