]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexPascal.cxx
434f88d4fe493c6a6b39bc0b1be7302eb4f90153
[wxWidgets.git] / src / stc / scintilla / src / LexPascal.cxx
1 // Scintilla source code edit control
2 /** @file LexPascal.cxx
3 ** Lexer for Pascal.
4 ** Written by Laurent le Tynevez
5 ** Updated by Simon Steele <s.steele@pnotepad.org> September 2002
6 ** Updated by Mathias Rauen <scite@madshi.net> May 2003 (Delphi adjustments)
7 **/
8
9 #include <stdlib.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <stdio.h>
13 #include <stdarg.h>
14
15 #include "Platform.h"
16
17 #include "PropSet.h"
18 #include "Accessor.h"
19 #include "KeyWords.h"
20 #include "Scintilla.h"
21 #include "SciLexer.h"
22 #include "StyleContext.h"
23
24 static void getRange(unsigned int start,
25 unsigned int end,
26 Accessor &styler,
27 char *s,
28 unsigned int len) {
29 unsigned int i = 0;
30 while ((i < end - start + 1) && (i < len-1)) {
31 s[i] = static_cast<char>(tolower(styler[start + i]));
32 i++;
33 }
34 s[i] = '\0';
35 }
36
37 static bool IsStreamCommentStyle(int style) {
38 return style == SCE_C_COMMENT ||
39 style == SCE_C_COMMENTDOC ||
40 style == SCE_C_COMMENTDOCKEYWORD ||
41 style == SCE_C_COMMENTDOCKEYWORDERROR;
42 }
43
44 static void ColourTo(Accessor &styler, unsigned int end, unsigned int attr, bool bInAsm) {
45 if ((bInAsm) && (attr == SCE_C_OPERATOR || attr == SCE_C_NUMBER || attr == SCE_C_DEFAULT || attr == SCE_C_WORD || attr == SCE_C_IDENTIFIER)) {
46 styler.ColourTo(end, SCE_C_REGEX);
47 } else
48 styler.ColourTo(end, attr);
49 }
50
51 // returns 1 if the item starts a class definition, and -1 if the word is "end", and 2 if the word is "asm"
52 static int classifyWordPascal(unsigned int start, unsigned int end, /*WordList &keywords*/WordList *keywordlists[], Accessor &styler, bool bInClass, bool bInAsm) {
53 int ret = 0;
54
55 WordList& keywords = *keywordlists[0];
56 WordList& classwords = *keywordlists[1];
57
58 char s[100];
59 getRange(start, end, styler, s, sizeof(s));
60
61 char chAttr = SCE_C_IDENTIFIER;
62 if (isdigit(s[0]) || (s[0] == '.') ||(s[0] == '$')) {
63 chAttr = SCE_C_NUMBER;
64 }
65 else {
66 if (s[0] == '#') {
67 chAttr = SCE_C_CHARACTER;
68 }
69 else {
70 if (keywords.InList(s)) {
71 chAttr = SCE_C_WORD;
72
73 if(strcmp(s, "class") == 0) {
74 ret = 1;
75 }
76 else if (strcmp(s, "asm") == 0) {
77 ret = 2;
78 }
79 else if (strcmp(s, "end") == 0) {
80 ret = -1;
81 }
82 } else if (bInClass) {
83 if (classwords.InList(s)) {
84 chAttr = SCE_C_WORD;
85 }
86 }
87 }
88 }
89 ColourTo(styler, end, chAttr, (bInAsm && ret != -1));
90 return ret;
91 }
92
93 static int classifyFoldPointPascal(const char* s) {
94 int lev = 0;
95 if (!(isdigit(s[0]) || (s[0] == '.'))) {
96 if (strcmp(s, "begin") == 0 ||
97 strcmp(s, "object") == 0 ||
98 strcmp(s, "case") == 0 ||
99 strcmp(s, "class") == 0 ||
100 strcmp(s, "record") == 0 ||
101 strcmp(s, "try") == 0) {
102 lev=1;
103 } else if (strcmp(s, "end") == 0) {
104 lev=-1;
105 }
106 }
107 return lev;
108 }
109
110 static void ColourisePascalDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
111 Accessor &styler) {
112
113 styler.StartAt(startPos);
114
115 int state = initStyle;
116 if (state == SCE_C_CHARACTER) // Does not leak onto next line
117 state = SCE_C_DEFAULT;
118 char chPrev = ' ';
119 char chNext = styler[startPos];
120 unsigned int lengthDoc = startPos + length;
121
122 bool bInClassDefinition;
123
124 int currentLine = styler.GetLine(startPos);
125 if (currentLine > 0) {
126 styler.SetLineState(currentLine, styler.GetLineState(currentLine-1));
127 bInClassDefinition = (styler.GetLineState(currentLine) == 1);
128 } else {
129 styler.SetLineState(currentLine, 0);
130 bInClassDefinition = false;
131 }
132
133 bool bInAsm = (state == SCE_C_REGEX);
134 if (bInAsm)
135 state = SCE_C_DEFAULT;
136
137 styler.StartSegment(startPos);
138 for (unsigned int i = startPos; i < lengthDoc; i++) {
139 char ch = chNext;
140
141 chNext = styler.SafeGetCharAt(i + 1);
142
143 if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
144 // Trigger on CR only (Mac style) or either on LF from CR+LF (Dos/Win) or on LF alone (Unix)
145 // Avoid triggering two times on Dos/Win
146 // End of line
147 if (state == SCE_C_CHARACTER) {
148 ColourTo(styler, i, state, bInAsm);
149 state = SCE_C_DEFAULT;
150 }
151 currentLine++;
152 styler.SetLineState(currentLine, (bInClassDefinition ? 1 : 0));
153 }
154
155 if (styler.IsLeadByte(ch)) {
156 chNext = styler.SafeGetCharAt(i + 2);
157 chPrev = ' ';
158 i += 1;
159 continue;
160 }
161
162 if (state == SCE_C_DEFAULT) {
163 if (iswordstart(ch) || ch == '#' || ch == '$' || (ch == '@' && bInAsm)) {
164 ColourTo(styler, i-1, state, bInAsm);
165 state = SCE_C_IDENTIFIER;
166 } else if (ch == '{' && chNext != '$' && chNext != '&') {
167 ColourTo(styler, i-1, state, bInAsm);
168 state = SCE_C_COMMENT;
169 } else if (ch == '(' && chNext == '*'
170 && styler.SafeGetCharAt(i + 2) != '$'
171 && styler.SafeGetCharAt(i + 2) != '&') {
172 ColourTo(styler, i-1, state, bInAsm);
173 state = SCE_C_COMMENTDOC;
174 } else if (ch == '/' && chNext == '/') {
175 ColourTo(styler, i-1, state, bInAsm);
176 state = SCE_C_COMMENTLINE;
177 } else if (ch == '\'') {
178 ColourTo(styler, i-1, state, bInAsm);
179 state = SCE_C_CHARACTER;
180 } else if (ch == '{' && (chNext == '$' || chNext=='&')) {
181 ColourTo(styler, i-1, state, bInAsm);
182 state = SCE_C_PREPROCESSOR;
183 } else if (isoperator(ch)) {
184 ColourTo(styler, i-1, state, bInAsm);
185 ColourTo(styler, i, SCE_C_OPERATOR, bInAsm);
186
187 }
188 } else if (state == SCE_C_IDENTIFIER) {
189 bool bDoublePoint = ((ch == '.') && (chPrev == '.'));
190 if ((!iswordchar(ch) && ch != '$' && ch != '#' && (ch != '@' || !bInAsm)) || bDoublePoint) {
191 if (bDoublePoint) i--;
192 int lStateChange = classifyWordPascal(styler.GetStartSegment(), i - 1, keywordlists, styler, bInClassDefinition, bInAsm);
193
194 if(lStateChange == 1) {
195 styler.SetLineState(currentLine, 1);
196 bInClassDefinition = true;
197 } else if(lStateChange == 2) {
198 bInAsm = true;
199 } else if(lStateChange == -1) {
200 styler.SetLineState(currentLine, 0);
201 bInClassDefinition = false;
202 bInAsm = false;
203 }
204 if (bDoublePoint) {
205 i++;
206 ColourTo(styler, i-1, SCE_C_DEFAULT, bInAsm);
207 }
208
209 state = SCE_C_DEFAULT;
210 chNext = styler.SafeGetCharAt(i + 1);
211 if (ch == '{' && chNext != '$' && chNext != '&') {
212 state = SCE_C_COMMENT;
213 } else if (ch == '(' && chNext == '*'
214 && styler.SafeGetCharAt(i + 2) != '$'
215 && styler.SafeGetCharAt(i + 2) != '&') {
216 ColourTo(styler, i-1, state, bInAsm);
217 state = SCE_C_COMMENTDOC;
218 } else if (ch == '/' && chNext == '/') {
219 state = SCE_C_COMMENTLINE;
220 } else if (ch == '\'') {
221 state = SCE_C_CHARACTER;
222 } else if (isoperator(ch)) {
223 ColourTo(styler, i, SCE_C_OPERATOR, bInAsm);
224 }
225 }
226 } else {
227 if (state == SCE_C_PREPROCESSOR) {
228 if (ch=='}'){
229 ColourTo(styler, i, state, bInAsm);
230 state = SCE_C_DEFAULT;
231 } else {
232 if ((ch == '\r' || ch == '\n') && !(chPrev == '\\' || chPrev == '\r')) {
233 ColourTo(styler, i-1, state, bInAsm);
234 state = SCE_C_DEFAULT;
235 }
236 }
237 } else if (state == SCE_C_COMMENT) {
238 if (ch == '}' ) {
239 ColourTo(styler, i, state, bInAsm);
240 state = SCE_C_DEFAULT;
241 }
242 } else if (state == SCE_C_COMMENTDOC) {
243 if (ch == ')' && chPrev == '*') {
244 if (((i > styler.GetStartSegment() + 2) || (
245 (initStyle == SCE_C_COMMENTDOC) &&
246 (styler.GetStartSegment() == static_cast<unsigned int>(startPos))))) {
247 ColourTo(styler, i, state, bInAsm);
248 state = SCE_C_DEFAULT;
249 }
250 }
251 } else if (state == SCE_C_COMMENTLINE) {
252 if (ch == '\r' || ch == '\n') {
253 ColourTo(styler, i-1, state, bInAsm);
254 state = SCE_C_DEFAULT;
255 }
256 } else if (state == SCE_C_CHARACTER) {
257 if (ch == '\'') {
258 ColourTo(styler, i, state, bInAsm);
259 state = SCE_C_DEFAULT;
260 }
261 }
262 }
263 chPrev = ch;
264 }
265 ColourTo(styler, lengthDoc - 1, state, bInAsm);
266 }
267
268 static void FoldPascalDoc(unsigned int startPos, int length, int initStyle, WordList *[],
269 Accessor &styler) {
270 bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
271 bool foldPreprocessor = styler.GetPropertyInt("fold.preprocessor") != 0;
272 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
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
282 int lastStart = 0;
283
284 for (unsigned int i = startPos; i < endPos; i++) {
285 char ch = chNext;
286 chNext = styler.SafeGetCharAt(i + 1);
287 int stylePrev = style;
288 style = styleNext;
289 styleNext = styler.StyleAt(i + 1);
290 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
291
292 if (stylePrev == SCE_C_DEFAULT && style == SCE_C_WORD)
293 {
294 // Store last word start point.
295 lastStart = i;
296 }
297
298 if (stylePrev == SCE_C_WORD) {
299 if(iswordchar(ch) && !iswordchar(chNext)) {
300 char s[100];
301 getRange(lastStart, i, styler, s, sizeof(s));
302 levelCurrent += classifyFoldPointPascal(s);
303 }
304 }
305
306 if (foldComment && (style == SCE_C_COMMENTLINE)) {
307 if ((ch == '/') && (chNext == '/')) {
308 char chNext2 = styler.SafeGetCharAt(i + 2);
309 if (chNext2 == '{') {
310 levelCurrent++;
311 } else if (chNext2 == '}') {
312 levelCurrent--;
313 }
314 }
315 }
316
317 if (foldPreprocessor && (style == SCE_C_PREPROCESSOR)) {
318 if (ch == '{' && chNext == '$') {
319 unsigned int j=i+2; // skip {$
320 while ((j<endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
321 j++;
322 }
323 if (styler.Match(j, "region") || styler.Match(j, "if")) {
324 levelCurrent++;
325 } else if (styler.Match(j, "end")) {
326 levelCurrent--;
327 }
328 }
329 }
330
331 if (foldComment && IsStreamCommentStyle(style)) {
332 if (!IsStreamCommentStyle(stylePrev)) {
333 levelCurrent++;
334 } else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
335 // Comments don't end at end of line and the next character may be unstyled.
336 levelCurrent--;
337 }
338 }
339
340 if (atEOL) {
341 int lev = levelPrev;
342 if (visibleChars == 0 && foldCompact)
343 lev |= SC_FOLDLEVELWHITEFLAG;
344 if ((levelCurrent > levelPrev) && (visibleChars > 0))
345 lev |= SC_FOLDLEVELHEADERFLAG;
346 if (lev != styler.LevelAt(lineCurrent)) {
347 styler.SetLevel(lineCurrent, lev);
348 }
349 lineCurrent++;
350 levelPrev = levelCurrent;
351 visibleChars = 0;
352 }
353
354 if (!isspacechar(ch))
355 visibleChars++;
356 }
357
358 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
359 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
360 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
361 }
362
363 static const char * const pascalWordListDesc[] = {
364 "Keywords",
365 "Classwords",
366 0
367 };
368
369 LexerModule lmPascal(SCLEX_PASCAL, ColourisePascalDoc, "pascal", FoldPascalDoc, pascalWordListDesc);