OSDN Git Service

c62168f8bf092d76a682bd8371f4a60c2791c393
[qt-creator-jp/qt-creator-jp.git] / src / plugins / texteditor / generichighlighter / rule.cpp
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
68 Rule::Rule(bool consumesNonSpace) :
69     m_lookAhead(false), m_firstNonSpace(false), m_column(-1), m_consumesNonSpace(consumesNonSpace)
70 {}
71
72 Rule::~Rule()
73 {}
74
75 void Rule::setContext(const QString &context)
76 { m_context = context; }
77
78 const QString &Rule::context() const
79 { return m_context; }
80
81 void Rule::setItemData(const QString &itemData)
82 { m_itemData = itemData; }
83
84 const QString &Rule::itemData() const
85 { return m_itemData; }
86
87 void Rule::setBeginRegion(const QString &begin)
88 { m_beginRegion = begin; }
89
90 const QString &Rule::beginRegion() const
91 { return m_beginRegion; }
92
93 void Rule::setEndRegion(const QString &end)
94 { m_endRegion = end; }
95
96 const QString &Rule::endRegion() const
97 { return m_endRegion; }
98
99 void Rule::setLookAhead(const QString &lookAhead)
100 { m_lookAhead = toBool(lookAhead); }
101
102 bool Rule::isLookAhead() const
103 { return m_lookAhead; }
104
105 void Rule::setFirstNonSpace(const QString &firstNonSpace)
106 { m_firstNonSpace = toBool(firstNonSpace); }
107
108 bool Rule::isFirstNonSpace() const
109 { return m_firstNonSpace; }
110
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
119 int Rule::column() const
120 { return m_column; }
121
122 void Rule::addChild(const QSharedPointer<Rule> &rule)
123 { m_children.append(rule); }
124
125 bool Rule::hasChildren() const
126 { return !m_children.isEmpty(); }
127
128 const QList<QSharedPointer<Rule> > &Rule::children() const
129 { return m_children; }
130
131 void Rule::setDefinition(const QSharedPointer<HighlightDefinition> &definition)
132 { m_definition = definition; }
133
134 const QSharedPointer<HighlightDefinition> &Rule::definition() const
135 { return m_definition; }
136
137 template <class predicate_t>
138 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
153 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
161 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
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
191 Rule *Rule::clone() const
192 { return doClone(); }
193
194 void Rule::progressFinished()
195 { doProgressFinished(); }
196
197 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
216 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
240 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
270 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 }