scintilla: Update scintilla with changeset 3662:1d1c06df8a2f using gtk+3
[anjuta-extras.git] / plugins / scintilla / scintilla / LexFortran.cxx
blob6c61c540fc5c3e5c7fcc36614e4db2282e84ec48
1 // Scintilla source code edit control
2 /** @file LexFortran.cxx
3 ** Lexer for Fortran.
4 ** Writen by Chuan-jian Shen, Last changed Sep. 2003
5 **/
6 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
8 /***************************************/
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <assert.h>
14 #include <ctype.h>
15 /***************************************/
16 #include "ILexer.h"
17 #include "Scintilla.h"
18 #include "SciLexer.h"
20 #include "WordList.h"
21 #include "LexAccessor.h"
22 #include "Accessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
26 /***************************************/
28 #ifdef SCI_NAMESPACE
29 using namespace Scintilla;
30 #endif
32 /***********************************************/
33 static inline bool IsAWordChar(const int ch) {
34 return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '%');
36 /**********************************************/
37 static inline bool IsAWordStart(const int ch) {
38 return (ch < 0x80) && (isalnum(ch));
40 /***************************************/
41 inline bool IsABlank(unsigned int ch) {
42 return (ch == ' ') || (ch == 0x09) || (ch == 0x0b) ;
44 /***************************************/
45 inline bool IsALineEnd(char ch) {
46 return ((ch == '\n') || (ch == '\r')) ;
48 /***************************************/
49 unsigned int GetContinuedPos(unsigned int pos, Accessor &styler) {
50 while (!IsALineEnd(styler.SafeGetCharAt(pos++))) continue;
51 if (styler.SafeGetCharAt(pos) == '\n') pos++;
52 while (IsABlank(styler.SafeGetCharAt(pos++))) continue;
53 char chCur = styler.SafeGetCharAt(pos);
54 if (chCur == '&') {
55 while (IsABlank(styler.SafeGetCharAt(++pos))) continue;
56 return pos;
57 } else {
58 return pos;
61 /***************************************/
62 static void ColouriseFortranDoc(unsigned int startPos, int length, int initStyle,
63 WordList *keywordlists[], Accessor &styler, bool isFixFormat) {
64 WordList &keywords = *keywordlists[0];
65 WordList &keywords2 = *keywordlists[1];
66 WordList &keywords3 = *keywordlists[2];
67 /***************************************/
68 int posLineStart = 0, numNonBlank = 0, prevState = 0;
69 int endPos = startPos + length;
70 /***************************************/
71 // backtrack to the nearest keyword
72 while ((startPos > 1) && (styler.StyleAt(startPos) != SCE_F_WORD)) {
73 startPos--;
75 startPos = styler.LineStart(styler.GetLine(startPos));
76 initStyle = styler.StyleAt(startPos - 1);
77 StyleContext sc(startPos, endPos-startPos, initStyle, styler);
78 /***************************************/
79 for (; sc.More(); sc.Forward()) {
80 // remember the start position of the line
81 if (sc.atLineStart) {
82 posLineStart = sc.currentPos;
83 numNonBlank = 0;
84 sc.SetState(SCE_F_DEFAULT);
86 if (!IsASpaceOrTab(sc.ch)) numNonBlank ++;
87 /***********************************************/
88 // Handle the fix format generically
89 int toLineStart = sc.currentPos - posLineStart;
90 if (isFixFormat && (toLineStart < 6 || toLineStart > 72)) {
91 if ((toLineStart == 0 && (tolower(sc.ch) == 'c' || sc.ch == '*')) || sc.ch == '!') {
92 if (sc.MatchIgnoreCase("cdec$") || sc.MatchIgnoreCase("*dec$") || sc.MatchIgnoreCase("!dec$") ||
93 sc.MatchIgnoreCase("cdir$") || sc.MatchIgnoreCase("*dir$") || sc.MatchIgnoreCase("!dir$") ||
94 sc.MatchIgnoreCase("cms$") || sc.MatchIgnoreCase("*ms$") || sc.MatchIgnoreCase("!ms$") ||
95 sc.chNext == '$') {
96 sc.SetState(SCE_F_PREPROCESSOR);
97 } else {
98 sc.SetState(SCE_F_COMMENT);
101 while (!sc.atLineEnd && sc.More()) sc.Forward(); // Until line end
102 } else if (toLineStart > 72) {
103 sc.SetState(SCE_F_COMMENT);
104 while (!sc.atLineEnd && sc.More()) sc.Forward(); // Until line end
105 } else if (toLineStart < 5) {
106 if (IsADigit(sc.ch))
107 sc.SetState(SCE_F_LABEL);
108 else
109 sc.SetState(SCE_F_DEFAULT);
110 } else if (toLineStart == 5) {
111 if (!IsASpace(sc.ch) && sc.ch != '0') {
112 sc.SetState(SCE_F_CONTINUATION);
113 sc.ForwardSetState(prevState);
114 } else
115 sc.SetState(SCE_F_DEFAULT);
117 continue;
119 /***************************************/
120 // Handle line continuation generically.
121 if (!isFixFormat && sc.ch == '&') {
122 char chTemp = ' ';
123 int j = 1;
124 while (IsABlank(chTemp) && j<132) {
125 chTemp = static_cast<char>(sc.GetRelative(j));
126 j++;
128 if (chTemp == '!') {
129 sc.SetState(SCE_F_CONTINUATION);
130 if (sc.chNext == '!') sc.ForwardSetState(SCE_F_COMMENT);
131 } else if (chTemp == '\r' || chTemp == '\n') {
132 int currentState = sc.state;
133 sc.SetState(SCE_F_CONTINUATION);
134 sc.ForwardSetState(SCE_F_DEFAULT);
135 while (IsASpace(sc.ch) && sc.More()) sc.Forward();
136 if (sc.ch == '&') {
137 sc.SetState(SCE_F_CONTINUATION);
138 sc.Forward();
140 sc.SetState(currentState);
143 /***************************************/
144 // Determine if the current state should terminate.
145 if (sc.state == SCE_F_OPERATOR) {
146 sc.SetState(SCE_F_DEFAULT);
147 } else if (sc.state == SCE_F_NUMBER) {
148 if (!(IsAWordChar(sc.ch) || sc.ch=='\'' || sc.ch=='\"' || sc.ch=='.')) {
149 sc.SetState(SCE_F_DEFAULT);
151 } else if (sc.state == SCE_F_IDENTIFIER) {
152 if (!IsAWordChar(sc.ch) || (sc.ch == '%')) {
153 char s[100];
154 sc.GetCurrentLowered(s, sizeof(s));
155 if (keywords.InList(s)) {
156 sc.ChangeState(SCE_F_WORD);
157 } else if (keywords2.InList(s)) {
158 sc.ChangeState(SCE_F_WORD2);
159 } else if (keywords3.InList(s)) {
160 sc.ChangeState(SCE_F_WORD3);
162 sc.SetState(SCE_F_DEFAULT);
164 } else if (sc.state == SCE_F_COMMENT || sc.state == SCE_F_PREPROCESSOR) {
165 if (sc.ch == '\r' || sc.ch == '\n') {
166 sc.SetState(SCE_F_DEFAULT);
168 } else if (sc.state == SCE_F_STRING1) {
169 prevState = sc.state;
170 if (sc.ch == '\'') {
171 if (sc.chNext == '\'') {
172 sc.Forward();
173 } else {
174 sc.ForwardSetState(SCE_F_DEFAULT);
175 prevState = SCE_F_DEFAULT;
177 } else if (sc.atLineEnd) {
178 sc.ChangeState(SCE_F_STRINGEOL);
179 sc.ForwardSetState(SCE_F_DEFAULT);
181 } else if (sc.state == SCE_F_STRING2) {
182 prevState = sc.state;
183 if (sc.atLineEnd) {
184 sc.ChangeState(SCE_F_STRINGEOL);
185 sc.ForwardSetState(SCE_F_DEFAULT);
186 } else if (sc.ch == '\"') {
187 if (sc.chNext == '\"') {
188 sc.Forward();
189 } else {
190 sc.ForwardSetState(SCE_F_DEFAULT);
191 prevState = SCE_F_DEFAULT;
194 } else if (sc.state == SCE_F_OPERATOR2) {
195 if (sc.ch == '.') {
196 sc.ForwardSetState(SCE_F_DEFAULT);
198 } else if (sc.state == SCE_F_CONTINUATION) {
199 sc.SetState(SCE_F_DEFAULT);
200 } else if (sc.state == SCE_F_LABEL) {
201 if (!IsADigit(sc.ch)) {
202 sc.SetState(SCE_F_DEFAULT);
203 } else {
204 if (isFixFormat && sc.currentPos-posLineStart > 4)
205 sc.SetState(SCE_F_DEFAULT);
206 else if (numNonBlank > 5)
207 sc.SetState(SCE_F_DEFAULT);
210 /***************************************/
211 // Determine if a new state should be entered.
212 if (sc.state == SCE_F_DEFAULT) {
213 if (sc.ch == '!') {
214 if (sc.MatchIgnoreCase("!dec$") || sc.MatchIgnoreCase("!dir$") ||
215 sc.MatchIgnoreCase("!ms$") || sc.chNext == '$') {
216 sc.SetState(SCE_F_PREPROCESSOR);
217 } else {
218 sc.SetState(SCE_F_COMMENT);
220 } else if ((!isFixFormat) && IsADigit(sc.ch) && numNonBlank == 1) {
221 sc.SetState(SCE_F_LABEL);
222 } else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
223 sc.SetState(SCE_F_NUMBER);
224 } else if ((tolower(sc.ch) == 'b' || tolower(sc.ch) == 'o' ||
225 tolower(sc.ch) == 'z') && (sc.chNext == '\"' || sc.chNext == '\'')) {
226 sc.SetState(SCE_F_NUMBER);
227 sc.Forward();
228 } else if (sc.ch == '.' && isalpha(sc.chNext)) {
229 sc.SetState(SCE_F_OPERATOR2);
230 } else if (IsAWordStart(sc.ch)) {
231 sc.SetState(SCE_F_IDENTIFIER);
232 } else if (sc.ch == '\"') {
233 sc.SetState(SCE_F_STRING2);
234 } else if (sc.ch == '\'') {
235 sc.SetState(SCE_F_STRING1);
236 } else if (isoperator(static_cast<char>(sc.ch))) {
237 sc.SetState(SCE_F_OPERATOR);
241 sc.Complete();
243 /***************************************/
244 // To determine the folding level depending on keywords
245 static int classifyFoldPointFortran(const char* s, const char* prevWord, const char chNextNonBlank) {
246 int lev = 0;
247 if ((strcmp(prevWord, "else") == 0 && strcmp(s, "if") == 0) || strcmp(s, "elseif") == 0)
248 return -1;
249 if (strcmp(s, "associate") == 0 || strcmp(s, "block") == 0
250 || strcmp(s, "blockdata") == 0 || strcmp(s, "select") == 0
251 || strcmp(s, "do") == 0 || strcmp(s, "enum") ==0
252 || strcmp(s, "function") == 0 || strcmp(s, "interface") == 0
253 || strcmp(s, "module") == 0 || strcmp(s, "program") == 0
254 || strcmp(s, "subroutine") == 0 || strcmp(s, "then") == 0
255 || (strcmp(s, "type") == 0 && chNextNonBlank != '(') ){
256 if (strcmp(prevWord, "end") == 0)
257 lev = 0;
258 else
259 lev = 1;
260 } else if ((strcmp(s, "end") == 0 && chNextNonBlank != '=')
261 || strcmp(s, "endassociate") == 0 || strcmp(s, "endblock") == 0
262 || strcmp(s, "endblockdata") == 0 || strcmp(s, "endselect") == 0
263 || strcmp(s, "enddo") == 0 || strcmp(s, "endenum") ==0
264 || strcmp(s, "endif") == 0 || strcmp(s, "endforall") == 0
265 || strcmp(s, "endfunction") == 0 || strcmp(s, "endinterface") == 0
266 || strcmp(s, "endmodule") == 0 || strcmp(s, "endprogram") == 0
267 || strcmp(s, "endsubroutine") == 0 || strcmp(s, "endtype") == 0
268 || strcmp(s, "endwhere") == 0
269 || (strcmp(s, "procedure") == 0 && strcmp(prevWord,"module")==0) ) { // Take care of the module procedure statement
270 lev = -1;
271 } else if (strcmp(prevWord, "end") == 0 && strcmp(s, "if") == 0){ // end if
272 lev = 0;
274 return lev;
276 // Folding the code
277 static void FoldFortranDoc(unsigned int startPos, int length, int initStyle,
278 Accessor &styler, bool isFixFormat) {
280 // bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
281 // Do not know how to fold the comment at the moment.
283 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
284 unsigned int endPos = startPos + length;
285 int visibleChars = 0;
286 int lineCurrent = styler.GetLine(startPos);
287 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
288 int levelCurrent = levelPrev;
289 char chNext = styler[startPos];
290 char chNextNonBlank;
291 int styleNext = styler.StyleAt(startPos);
292 int style = initStyle;
293 /***************************************/
294 int lastStart = 0;
295 char prevWord[32] = "";
296 char Label[6] = "";
297 // Variables for do label folding.
298 static int doLabels[100];
299 static int posLabel=-1;
300 /***************************************/
301 for (unsigned int i = startPos; i < endPos; i++) {
302 char ch = chNext;
303 chNext = styler.SafeGetCharAt(i + 1);
304 chNextNonBlank = chNext;
305 unsigned int j=i+1;
306 while(IsABlank(chNextNonBlank) && j<endPos) {
307 j ++ ;
308 chNextNonBlank = styler.SafeGetCharAt(j);
310 int stylePrev = style;
311 style = styleNext;
312 styleNext = styler.StyleAt(i + 1);
313 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
315 if (stylePrev == SCE_F_DEFAULT && (style == SCE_F_WORD || style == SCE_F_LABEL)) {
316 // Store last word and label start point.
317 lastStart = i;
319 /***************************************/
320 if (style == SCE_F_WORD) {
321 if(iswordchar(ch) && !iswordchar(chNext)) {
322 char s[32];
323 unsigned int k;
324 for(k=0; (k<31 ) && (k<i-lastStart+1 ); k++) {
325 s[k] = static_cast<char>(tolower(styler[lastStart+k]));
327 s[k] = '\0';
328 // Handle the forall and where statement and structure.
329 if (strcmp(s, "forall") == 0 || strcmp(s, "where") == 0) {
330 if (strcmp(prevWord, "end") != 0) {
331 j = i + 1;
332 char chBrace = '(', chSeek = ')', ch1 = styler.SafeGetCharAt(j);
333 // Find the position of the first (
334 while (ch1 != chBrace && j<endPos) {
335 j++;
336 ch1 = styler.SafeGetCharAt(j);
338 char styBrace = styler.StyleAt(j);
339 int depth = 1;
340 char chAtPos;
341 char styAtPos;
342 while (j<endPos) {
343 j++;
344 chAtPos = styler.SafeGetCharAt(j);
345 styAtPos = styler.StyleAt(j);
346 if (styAtPos == styBrace) {
347 if (chAtPos == chBrace) depth++;
348 if (chAtPos == chSeek) depth--;
349 if (depth == 0) break;
352 while (j<endPos) {
353 j++;
354 chAtPos = styler.SafeGetCharAt(j);
355 styAtPos = styler.StyleAt(j);
356 if (styAtPos == SCE_F_COMMENT || IsABlank(chAtPos)) continue;
357 if (isFixFormat) {
358 if (!IsALineEnd(chAtPos)) {
359 break;
360 } else {
361 if (lineCurrent < styler.GetLine(styler.Length()-1)) {
362 j = styler.LineStart(lineCurrent+1);
363 if (styler.StyleAt(j+5) == SCE_F_CONTINUATION) {
364 j += 5;
365 continue;
366 } else {
367 levelCurrent++;
368 break;
372 } else {
373 if (chAtPos == '&' && styler.StyleAt(j) == SCE_F_CONTINUATION) {
374 j = GetContinuedPos(j+1, styler);
375 continue;
376 } else if (IsALineEnd(chAtPos)) {
377 levelCurrent ++;
378 break;
379 } else {
380 break;
385 } else {
386 levelCurrent += classifyFoldPointFortran(s, prevWord, chNextNonBlank);
387 // Store the do Labels into array
388 if (strcmp(s, "do") == 0 && IsADigit(chNextNonBlank)) {
389 unsigned int k = 0;
390 for (i=j; (i<j+5 && i<endPos); i++) {
391 ch = styler.SafeGetCharAt(i);
392 if (IsADigit(ch))
393 Label[k++] = ch;
394 else
395 break;
397 Label[k] = '\0';
398 posLabel ++;
399 doLabels[posLabel] = atoi(Label);
402 strcpy(prevWord, s);
404 } else if (style == SCE_F_LABEL) {
405 if(IsADigit(ch) && !IsADigit(chNext)) {
406 for(j = 0; ( j < 5 ) && ( j < i-lastStart+1 ); j++) {
407 ch = styler.SafeGetCharAt(lastStart + j);
408 if (IsADigit(ch) && styler.StyleAt(lastStart+j) == SCE_F_LABEL)
409 Label[j] = ch;
410 else
411 break;
413 Label[j] = '\0';
414 while (doLabels[posLabel] == atoi(Label) && posLabel > -1) {
415 levelCurrent--;
416 posLabel--;
420 if (atEOL) {
421 int lev = levelPrev;
422 if (visibleChars == 0 && foldCompact)
423 lev |= SC_FOLDLEVELWHITEFLAG;
424 if ((levelCurrent > levelPrev) && (visibleChars > 0))
425 lev |= SC_FOLDLEVELHEADERFLAG;
426 if (lev != styler.LevelAt(lineCurrent)) {
427 styler.SetLevel(lineCurrent, lev);
429 lineCurrent++;
430 levelPrev = levelCurrent;
431 visibleChars = 0;
432 strcpy(prevWord, "");
434 /***************************************/
435 if (!isspacechar(ch)) visibleChars++;
437 /***************************************/
438 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
439 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
440 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
442 /***************************************/
443 static const char * const FortranWordLists[] = {
444 "Primary keywords and identifiers",
445 "Intrinsic functions",
446 "Extended and user defined functions",
449 /***************************************/
450 static void ColouriseFortranDocFreeFormat(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
451 Accessor &styler) {
452 ColouriseFortranDoc(startPos, length, initStyle, keywordlists, styler, false);
454 /***************************************/
455 static void ColouriseFortranDocFixFormat(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
456 Accessor &styler) {
457 ColouriseFortranDoc(startPos, length, initStyle, keywordlists, styler, true);
459 /***************************************/
460 static void FoldFortranDocFreeFormat(unsigned int startPos, int length, int initStyle,
461 WordList *[], Accessor &styler) {
462 FoldFortranDoc(startPos, length, initStyle,styler, false);
464 /***************************************/
465 static void FoldFortranDocFixFormat(unsigned int startPos, int length, int initStyle,
466 WordList *[], Accessor &styler) {
467 FoldFortranDoc(startPos, length, initStyle,styler, true);
469 /***************************************/
470 LexerModule lmFortran(SCLEX_FORTRAN, ColouriseFortranDocFreeFormat, "fortran", FoldFortranDocFreeFormat, FortranWordLists);
471 LexerModule lmF77(SCLEX_F77, ColouriseFortranDocFixFormat, "f77", FoldFortranDocFixFormat, FortranWordLists);