]> git.saurik.com Git - wxWidgets.git/blame - src/stc/scintilla/src/LexCPP.cxx
Added compatibility file
[wxWidgets.git] / src / stc / scintilla / src / LexCPP.cxx
CommitLineData
65ec6247
RD
1// Scintilla source code edit control
2/** @file LexCPP.cxx
3 ** Lexer for C++, C, Java, and Javascript.
4 **/
5// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
f6bcfd97
BP
6// The License.txt file describes the conditions under which this software may be distributed.
7
65ec6247
RD
8#include <stdlib.h>
9#include <string.h>
10#include <ctype.h>
11#include <stdio.h>
12#include <stdarg.h>
f6bcfd97
BP
13
14#include "Platform.h"
15
16#include "PropSet.h"
17#include "Accessor.h"
b8b0e402 18#include "StyleContext.h"
f6bcfd97
BP
19#include "KeyWords.h"
20#include "Scintilla.h"
21#include "SciLexer.h"
22
b8b0e402 23static bool IsOKBeforeRE(const int ch) {
65ec6247
RD
24 return (ch == '(') || (ch == '=') || (ch == ',');
25}
26
b8b0e402 27inline bool IsAWordChar(const int ch) {
65ec6247
RD
28 return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
29}
30
b8b0e402 31inline bool IsAWordStart(const int ch) {
65ec6247
RD
32 return (ch < 0x80) && (isalnum(ch) || ch == '_');
33}
34
b8b0e402
RD
35inline bool IsADoxygenChar(const int ch) {
36 return (islower(ch) || ch == '$' || ch == '@' ||
37 ch == '\\' || ch == '&' || ch == '<' ||
38 ch == '>' || ch == '#' || ch == '{' ||
39 ch == '}' || ch == '[' || ch == ']');
65ec6247
RD
40}
41
b8b0e402
RD
42inline bool IsStateComment(const int state) {
43 return ((state == SCE_C_COMMENT) ||
44 (state == SCE_C_COMMENTLINE) ||
45 (state == SCE_C_COMMENTDOC) ||
46 (state == SCE_C_COMMENTDOCKEYWORD) ||
47 (state == SCE_C_COMMENTDOCKEYWORDERROR));
48}
65ec6247 49
b8b0e402
RD
50inline bool IsStateString(const int state) {
51 return ((state == SCE_C_STRING) || (state == SCE_C_VERBATIM));
52}
65ec6247
RD
53
54static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
55 Accessor &styler) {
f6bcfd97 56
f6bcfd97 57 WordList &keywords = *keywordlists[0];
65ec6247 58 WordList &keywords2 = *keywordlists[1];
b8b0e402 59 WordList &keywords3 = *keywordlists[2];
65ec6247 60
d134f170 61 bool stylingWithinPreprocessor = styler.GetPropertyInt("styling.within.preprocessor");
f6bcfd97 62
b8b0e402
RD
63 // Do not leak onto next line
64 if (initStyle == SCE_C_STRINGEOL)
65ec6247
RD
65 initStyle = SCE_C_DEFAULT;
66
67 int chPrevNonWhite = ' ';
d134f170 68 int visibleChars = 0;
b8b0e402 69 int noDocChars = 0;
f6bcfd97 70 bool lastWordWasUUID = false;
f6bcfd97 71
b8b0e402 72 StyleContext sc(startPos, length, initStyle, styler);
f6bcfd97 73
b8b0e402
RD
74 for (; sc.More(); sc.Forward()) {
75
76 // Handle line continuation generically.
77 if (sc.ch == '\\') {
78 if (sc.Match("\\\n")) {
79 sc.Forward();
80 sc.Forward();
81 continue;
65ec6247 82 }
b8b0e402
RD
83 if (sc.Match("\\\r\n")) {
84 sc.Forward();
85 sc.Forward();
86 sc.Forward();
87 continue;
f6bcfd97 88 }
b8b0e402
RD
89 }
90
91 // Determine if the current state should terminate.
92 if (sc.state == SCE_C_OPERATOR) {
93 sc.SetState(SCE_C_DEFAULT);
94 } else if (sc.state == SCE_C_NUMBER) {
95 if (!IsAWordChar(sc.ch)) {
96 sc.SetState(SCE_C_DEFAULT);
97 }
98 } else if (sc.state == SCE_C_IDENTIFIER) {
99 if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
65ec6247 100 char s[100];
b8b0e402 101 sc.GetCurrent(s, sizeof(s));
65ec6247
RD
102 if (keywords.InList(s)) {
103 lastWordWasUUID = strcmp(s, "uuid") == 0;
b8b0e402 104 sc.ChangeState(SCE_C_WORD);
65ec6247 105 } else if (keywords2.InList(s)) {
b8b0e402 106 sc.ChangeState(SCE_C_WORD2);
f6bcfd97 107 }
b8b0e402 108 sc.SetState(SCE_C_DEFAULT);
f6bcfd97 109 }
b8b0e402 110 } else if (sc.state == SCE_C_PREPROCESSOR) {
65ec6247 111 if (stylingWithinPreprocessor) {
b8b0e402
RD
112 if (IsASpace(sc.ch)) {
113 sc.SetState(SCE_C_DEFAULT);
f6bcfd97 114 }
65ec6247 115 } else {
b8b0e402
RD
116 if (sc.atLineEnd) {
117 sc.SetState(SCE_C_DEFAULT);
f6bcfd97 118 }
65ec6247 119 }
b8b0e402
RD
120 } else if (sc.state == SCE_C_COMMENT) {
121 if (sc.Match('*', '/')) {
122 sc.Forward();
123 sc.ForwardSetState(SCE_C_DEFAULT);
124 }
125 } else if (sc.state == SCE_C_COMMENTDOC) {
126 if (sc.Match('*', '/')) {
127 sc.Forward();
128 sc.ForwardSetState(SCE_C_DEFAULT);
129 } else if ((sc.ch == '@' || sc.ch == '\\') && (noDocChars == 0)) {
130 sc.SetState(SCE_C_COMMENTDOCKEYWORD);
131 } else if (sc.atLineEnd) {
132 noDocChars = 0;
133 } else if (!isspace(sc.ch) && (sc.ch != '*')) {
134 noDocChars++;
65ec6247 135 }
b8b0e402
RD
136 } else if (sc.state == SCE_C_COMMENTLINE || sc.state == SCE_C_COMMENTLINEDOC) {
137 if (sc.atLineEnd) {
138 sc.SetState(SCE_C_DEFAULT);
139 visibleChars = 0;
65ec6247 140 }
b8b0e402
RD
141 } else if (sc.state == SCE_C_COMMENTDOCKEYWORD) {
142 if (sc.Match('*', '/')) {
143 sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
144 sc.Forward();
145 sc.ForwardSetState(SCE_C_DEFAULT);
146 } else if (!IsADoxygenChar(sc.ch)) {
147 char s[100];
148 sc.GetCurrent(s, sizeof(s));
149 if (!isspace(sc.ch) || !keywords3.InList(s+1)) {
150 sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
151 }
152 sc.SetState(SCE_C_COMMENTDOC);
65ec6247 153 }
b8b0e402
RD
154 } else if (sc.state == SCE_C_STRING) {
155 if (sc.ch == '\\') {
156 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
157 sc.Forward();
f6bcfd97 158 }
b8b0e402
RD
159 } else if (sc.ch == '\"') {
160 sc.ForwardSetState(SCE_C_DEFAULT);
161 } else if (sc.atLineEnd) {
162 sc.ChangeState(SCE_C_STRINGEOL);
163 sc.ForwardSetState(SCE_C_DEFAULT);
164 visibleChars = 0;
65ec6247 165 }
b8b0e402
RD
166 } else if (sc.state == SCE_C_CHARACTER) {
167 if (sc.atLineEnd) {
168 sc.ChangeState(SCE_C_STRINGEOL);
169 sc.ForwardSetState(SCE_C_DEFAULT);
170 visibleChars = 0;
171 } else if (sc.ch == '\\') {
172 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
173 sc.Forward();
f6bcfd97 174 }
b8b0e402
RD
175 } else if (sc.ch == '\'') {
176 sc.ForwardSetState(SCE_C_DEFAULT);
65ec6247 177 }
b8b0e402
RD
178 } else if (sc.state == SCE_C_REGEX) {
179 if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == '/') {
180 sc.ForwardSetState(SCE_C_DEFAULT);
181 } else if (sc.ch == '\\') {
65ec6247 182 // Gobble up the quoted character
b8b0e402
RD
183 if (sc.chNext == '\\' || sc.chNext == '/') {
184 sc.Forward();
d134f170 185 }
65ec6247 186 }
b8b0e402
RD
187 } else if (sc.state == SCE_C_VERBATIM) {
188 if (sc.ch == '\"') {
189 if (sc.chNext == '\"') {
190 sc.Forward();
65ec6247 191 } else {
b8b0e402 192 sc.ForwardSetState(SCE_C_DEFAULT);
d134f170 193 }
65ec6247 194 }
b8b0e402
RD
195 } else if (sc.state == SCE_C_UUID) {
196 if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ')') {
197 sc.SetState(SCE_C_DEFAULT);
65ec6247
RD
198 }
199 }
200
b8b0e402
RD
201 // Determine if a new state should be entered.
202 if (sc.state == SCE_C_DEFAULT) {
203 if (sc.Match('@', '\"')) {
204 sc.SetState(SCE_C_VERBATIM);
205 sc.Forward();
206 } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
65ec6247 207 if (lastWordWasUUID) {
b8b0e402 208 sc.SetState(SCE_C_UUID);
65ec6247
RD
209 lastWordWasUUID = false;
210 } else {
b8b0e402 211 sc.SetState(SCE_C_NUMBER);
f6bcfd97 212 }
b8b0e402 213 } else if (IsAWordStart(sc.ch) || (sc.ch == '@')) {
65ec6247 214 if (lastWordWasUUID) {
b8b0e402 215 sc.SetState(SCE_C_UUID);
65ec6247
RD
216 lastWordWasUUID = false;
217 } else {
b8b0e402 218 sc.SetState(SCE_C_IDENTIFIER);
f6bcfd97 219 }
b8b0e402
RD
220 } else if (sc.Match('/', '*')) {
221 if (sc.Match("/**") || sc.Match("/*!")) { // Support of Qt/Doxygen doc. style
222 noDocChars = 0;
223 sc.SetState(SCE_C_COMMENTDOC);
224 } else {
225 sc.SetState(SCE_C_COMMENT);
226 }
227 sc.Forward(); // Eat the * so it isn't used for the end of the comment
228 } else if (sc.Match('/', '/')) {
229 if (sc.Match("///") || sc.Match("//!")) // Support of Qt/Doxygen doc. style
230 sc.SetState(SCE_C_COMMENTLINEDOC);
65ec6247 231 else
b8b0e402
RD
232 sc.SetState(SCE_C_COMMENTLINE);
233 } else if (sc.ch == '/' && IsOKBeforeRE(chPrevNonWhite)) {
234 sc.SetState(SCE_C_REGEX);
235 } else if (sc.ch == '\"') {
236 sc.SetState(SCE_C_STRING);
237 } else if (sc.ch == '\'') {
238 sc.SetState(SCE_C_CHARACTER);
239 } else if (sc.ch == '#' && visibleChars == 0) {
65ec6247 240 // Preprocessor commands are alone on their line
b8b0e402 241 sc.SetState(SCE_C_PREPROCESSOR);
65ec6247
RD
242 // Skip whitespace between # and preprocessor word
243 do {
b8b0e402
RD
244 sc.Forward();
245 } while ((sc.ch == ' ') && (sc.ch == '\t') && sc.More());
246 if (sc.atLineEnd) {
247 sc.SetState(SCE_C_DEFAULT);
248 }
249 } else if (isoperator(static_cast<char>(sc.ch))) {
250 sc.SetState(SCE_C_OPERATOR);
f6bcfd97 251 }
f6bcfd97 252 }
b8b0e402
RD
253
254 if (sc.atLineEnd) {
65ec6247
RD
255 // Reset states to begining of colourise so no surprises
256 // if different sets of lines lexed.
257 chPrevNonWhite = ' ';
258 visibleChars = 0;
259 lastWordWasUUID = false;
260 }
b8b0e402
RD
261 if (!IsASpace(sc.ch)) {
262 chPrevNonWhite = sc.ch;
65ec6247
RD
263 visibleChars++;
264 }
f6bcfd97 265 }
b8b0e402 266 sc.Complete();
65ec6247 267}
f6bcfd97 268
65ec6247
RD
269static void FoldCppDoc(unsigned int startPos, int length, int initStyle, WordList *[],
270 Accessor &styler) {
271 bool foldComment = styler.GetPropertyInt("fold.comment");
272 bool foldCompact = styler.GetPropertyInt("fold.compact", 1);
273 unsigned int endPos = startPos + length;
274 int visibleChars = 0;
275 int lineCurrent = styler.GetLine(startPos);
276 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
277 int levelCurrent = levelPrev;
278 char chNext = styler[startPos];
279 int styleNext = styler.StyleAt(startPos);
280 int style = initStyle;
281 for (unsigned int i = startPos; i < endPos; i++) {
282 char ch = chNext;
283 chNext = styler.SafeGetCharAt(i + 1);
284 int stylePrev = style;
285 style = styleNext;
286 styleNext = styler.StyleAt(i + 1);
287 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
288 if (foldComment &&
289 (style == SCE_C_COMMENT || style == SCE_C_COMMENTDOC)) {
290 if (style != stylePrev) {
291 levelCurrent++;
292 } else if ((style != styleNext) && !atEOL) {
293 // Comments don't end at end of line and the next character may be unstyled.
294 levelCurrent--;
295 }
296 }
297 if (style == SCE_C_OPERATOR) {
298 if (ch == '{') {
299 levelCurrent++;
300 } else if (ch == '}') {
301 levelCurrent--;
302 }
303 }
304 if (atEOL) {
305 int lev = levelPrev;
306 if (visibleChars == 0 && foldCompact)
307 lev |= SC_FOLDLEVELWHITEFLAG;
308 if ((levelCurrent > levelPrev) && (visibleChars > 0))
309 lev |= SC_FOLDLEVELHEADERFLAG;
310 if (lev != styler.LevelAt(lineCurrent)) {
311 styler.SetLevel(lineCurrent, lev);
312 }
313 lineCurrent++;
314 levelPrev = levelCurrent;
315 visibleChars = 0;
316 }
317 if (!isspacechar(ch))
318 visibleChars++;
f6bcfd97 319 }
65ec6247
RD
320 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
321 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
322 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
f6bcfd97
BP
323}
324
65ec6247
RD
325LexerModule lmCPP(SCLEX_CPP, ColouriseCppDoc, "cpp", FoldCppDoc);
326LexerModule lmTCL(SCLEX_TCL, ColouriseCppDoc, "tcl", FoldCppDoc);