1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
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, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "rule.h"
35 #include "highlighterexception.h"
36 #include "progressdata.h"
37 #include "highlightdefinition.h"
38 #include "reuse.h"
39
40 #include <QtCore/QStringList>
41
42 #include <functional>
43
44 using namespace TextEditor;
45 using namespace Internal;
46
47 const QLatin1Char Rule::kBackSlash('\\');
48 const QLatin1Char Rule::kUnderscore('_');
49 const QLatin1Char Rule::kDot('.');
50 const QLatin1Char Rule::kPlus('+');
51 const QLatin1Char Rule::kMinus('-');
52 const QLatin1Char Rule::kZero('0');
53 const QLatin1Char Rule::kQuote('\"');
54 const QLatin1Char Rule::kSingleQuote('\'');
55 const QLatin1Char Rule::kQuestion('?');
56 const QLatin1Char Rule::kX('x');
57 const QLatin1Char Rule::kA('a');
58 const QLatin1Char Rule::kB('b');
59 const QLatin1Char Rule::kE('e');
60 const QLatin1Char Rule::kF('f');
61 const QLatin1Char Rule::kN('n');
62 const QLatin1Char Rule::kR('r');
63 const QLatin1Char Rule::kT('t');
64 const QLatin1Char Rule::kV('v');
65 const QLatin1Char Rule::kOpeningBrace('{');
66 const QLatin1Char Rule::kClosingBrace('}');
67
Rule(bool consumesNonSpace)68 Rule::Rule(bool consumesNonSpace) :
69 m_lookAhead(false), m_firstNonSpace(false), m_column(-1), m_consumesNonSpace(consumesNonSpace)
70 {}
71
~Rule()72 Rule::~Rule()
73 {}
74
setContext(const QString & context)75 void Rule::setContext(const QString &context)
76 { m_context = context; }
77
context() const78 const QString &Rule::context() const
79 { return m_context; }
80
setItemData(const QString & itemData)81 void Rule::setItemData(const QString &itemData)
82 { m_itemData = itemData; }
83
itemData() const84 const QString &Rule::itemData() const
85 { return m_itemData; }
86
setBeginRegion(const QString & begin)87 void Rule::setBeginRegion(const QString &begin)
88 { m_beginRegion = begin; }
89
beginRegion() const90 const QString &Rule::beginRegion() const
91 { return m_beginRegion; }
92
setEndRegion(const QString & end)93 void Rule::setEndRegion(const QString &end)
94 { m_endRegion = end; }
95
endRegion() const96 const QString &Rule::endRegion() const
97 { return m_endRegion; }
98
setLookAhead(const QString & lookAhead)99 void Rule::setLookAhead(const QString &lookAhead)
100 { m_lookAhead = toBool(lookAhead); }
101
isLookAhead() const102 bool Rule::isLookAhead() const
103 { return m_lookAhead; }
104
setFirstNonSpace(const QString & firstNonSpace)105 void Rule::setFirstNonSpace(const QString &firstNonSpace)
106 { m_firstNonSpace = toBool(firstNonSpace); }
107
isFirstNonSpace() const108 bool Rule::isFirstNonSpace() const
109 { return m_firstNonSpace; }
110
setColumn(const QString & column)111 void Rule::setColumn(const QString &column)
112 {
113 bool ok;
114 m_column = column.toInt(&ok);
115 if (!ok)
116 m_column = -1;
117 }
118
column() const119 int Rule::column() const
120 { return m_column; }
121
addChild(const QSharedPointer<Rule> & rule)122 void Rule::addChild(const QSharedPointer<Rule> &rule)
123 { m_children.append(rule); }
124
hasChildren() const125 bool Rule::hasChildren() const
126 { return !m_children.isEmpty(); }
127
children() const128 const QList<QSharedPointer<Rule> > &Rule::children() const
129 { return m_children; }
130
setDefinition(const QSharedPointer<HighlightDefinition> & definition)131 void Rule::setDefinition(const QSharedPointer<HighlightDefinition> &definition)
132 { m_definition = definition; }
133
definition() const134 const QSharedPointer<HighlightDefinition> &Rule::definition() const
135 { return m_definition; }
136
137 template <class predicate_t>
predicateMatchSucceed(const QString & text,const int length,ProgressData * progress,const predicate_t & p) const138 bool Rule::predicateMatchSucceed(const QString &text,
139 const int length,
140 ProgressData *progress,
141 const predicate_t &p) const
142 {
143 int original = progress->offset();
144 while (progress->offset() < length && p(text.at(progress->offset())))
145 progress->incrementOffset();
146
147 if (original != progress->offset())
148 return true;
149
150 return false;
151 }
152
charPredicateMatchSucceed(const QString & text,const int length,ProgressData * progress,bool (QChar::* predicate)()const) const153 bool Rule::charPredicateMatchSucceed(const QString &text,
154 const int length,
155 ProgressData *progress,
156 bool (QChar::* predicate)() const) const
157 {
158 return predicateMatchSucceed(text, length, progress, std::mem_fun_ref(predicate));
159 }
160
charPredicateMatchSucceed(const QString & text,const int length,ProgressData * progress,bool (* predicate)(const QChar &)) const161 bool Rule::charPredicateMatchSucceed(const QString &text,
162 const int length,
163 ProgressData *progress,
164 bool (*predicate)(const QChar &)) const
165 {
166 return predicateMatchSucceed(text, length, progress, std::ptr_fun(predicate));
167 }
168
matchSucceed(const QString & text,const int length,ProgressData * progress)169 bool Rule::matchSucceed(const QString &text, const int length, ProgressData *progress)
170 {
171 if (m_firstNonSpace && !progress->isOnlySpacesSoFar())
172 return false;
173
174 if (m_column != -1 && m_column != progress->offset())
175 return false;
176
177 int original = progress->offset();
178 if (doMatchSucceed(text, length, progress)) {
179 if (progress->isOnlySpacesSoFar() && !m_lookAhead && m_consumesNonSpace)
180 progress->setOnlySpacesSoFar(false);
181
182 if (m_lookAhead)
183 progress->setOffset(original);
184
185 return true;
186 }
187
188 return false;
189 }
190
clone() const191 Rule *Rule::clone() const
192 { return doClone(); }
193
progressFinished()194 void Rule::progressFinished()
195 { doProgressFinished(); }
196
matchCharacter(const QString & text,const int length,ProgressData * progress,const QChar & c,bool saveRestoreOffset) const197 bool Rule::matchCharacter(const QString &text,
198 const int length,
199 ProgressData *progress,
200 const QChar &c,
201 bool saveRestoreOffset) const
202 {
203 Q_UNUSED(length)
204 Q_ASSERT(progress->offset() < length);
205
206 if (text.at(progress->offset()) == c) {
207 if (saveRestoreOffset)
208 progress->saveOffset();
209 progress->incrementOffset();
210 return true;
211 }
212
213 return false;
214 }
215
matchEscapeSequence(const QString & text,const int length,ProgressData * progress,bool saveRestoreOffset) const216 bool Rule::matchEscapeSequence(const QString &text,
217 const int length,
218 ProgressData *progress,
219 bool saveRestoreOffset) const
220 {
221 if (matchCharacter(text, length, progress, kBackSlash, saveRestoreOffset)) {
222
223 if (progress->offset() < length) {
224 const QChar &c = text.at(progress->offset());
225 if (c == kA || c == kB || c == kE || c == kF || c == kN || c == kR || c == kT ||
226 c == kV || c == kQuestion || c == kSingleQuote || c == kQuote || c == kBackSlash) {
227 progress->incrementOffset();
228 return true;
229 } else if (saveRestoreOffset) {
230 progress->restoreOffset();
231 }
232 } else if (saveRestoreOffset) {
233 progress->restoreOffset();
234 }
235 }
236
237 return false;
238 }
239
matchOctalSequence(const QString & text,const int length,ProgressData * progress,bool saveRestoreOffset) const240 bool Rule::matchOctalSequence(const QString &text,
241 const int length,
242 ProgressData *progress,
243 bool saveRestoreOffset) const
244 {
245 // An octal sequence is identified as in the C++ Standard.
246 // octal-escape-sequence:
247 // \ octal-digit
248 // \ octal-digit octal-digit
249 // \ octal-digit octal-digit octal-digit
250
251 if (matchCharacter(text, length, progress, kBackSlash, saveRestoreOffset)) {
252
253 int count = 0;
254 while (progress->offset() < length &&
255 count < 3 &&
256 isOctalDigit(text.at(progress->offset()))) {
257 ++count;
258 progress->incrementOffset();
259 }
260
261 if (count > 0)
262 return true;
263 else if (saveRestoreOffset)
264 progress->restoreOffset();
265 }
266
267 return false;
268 }
269
matchHexSequence(const QString & text,const int length,ProgressData * progress,bool saveRestoreOffset) const270 bool Rule::matchHexSequence(const QString &text,
271 const int length,
272 ProgressData *progress,
273 bool saveRestoreOffset) const
274 {
275 // An hex sequence is identified as in the C++ Standard.
276 // hexadecimal-escape-sequence:
277 // \x hexadecimal-digit
278 // hexadecimal-escape-sequence hexadecimal-digit
279
280 if (matchCharacter(text, length, progress, kBackSlash, saveRestoreOffset)) {
281
282 if (progress->offset() < length && matchCharacter(text, length, progress, kX, false)) {
283 bool found = false;
284 while (progress->offset() < length && isHexDigit(text.at(progress->offset()))) {
285 if (!found)
286 found = true;
287 progress->incrementOffset();
288 }
289
290 if (found)
291 return true;
292 else if (saveRestoreOffset)
293 progress->restoreOffset();
294 } else if (saveRestoreOffset) {
295 progress->restoreOffset();
296 }
297 }
298
299 return false;
300 }
301