]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/lexers/LexNimrod.cxx
1 // Scintilla source code edit control
3 // (c) 2009 Andreas Rumpf
4 /** @file LexNimrod.cxx
7 // Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
8 // The License.txt file describes the conditions under which this software may be distributed.
18 #include "Scintilla.h"
22 #include "LexAccessor.h"
24 #include "StyleContext.h"
25 #include "CharacterSet.h"
26 #include "LexerModule.h"
29 using namespace Scintilla
;
32 static inline bool IsAWordChar(int ch
) {
33 return (ch
>= 0x80) || isalnum(ch
) || ch
== '_';
36 static int tillEndOfTripleQuote(Accessor
&styler
, int pos
, int max
) {
39 if (styler
.SafeGetCharAt(pos
, '\0') == '\0') return pos
;
40 if (pos
>= max
) return pos
;
41 if (styler
.Match(pos
, "\"\"\"")) {
48 #define CR 13 /* use both because Scite allows changing the line ending */
51 static bool inline isNewLine(int ch
) {
52 return ch
== CR
|| ch
== LF
;
55 static int scanString(Accessor
&styler
, int pos
, int max
, bool rawMode
) {
57 if (pos
>= max
) return pos
;
58 char ch
= styler
.SafeGetCharAt(pos
, '\0');
59 if (ch
== CR
|| ch
== LF
|| ch
== '\0') return pos
;
60 if (ch
== '"') return pos
;
61 if (ch
== '\\' && !rawMode
) {
69 static int scanChar(Accessor
&styler
, int pos
, int max
) {
71 if (pos
>= max
) return pos
;
72 char ch
= styler
.SafeGetCharAt(pos
, '\0');
73 if (ch
== CR
|| ch
== LF
|| ch
== '\0') return pos
;
74 if (ch
== '\'' && !isalnum(styler
.SafeGetCharAt(pos
+1, '\0')) )
84 static int scanIdent(Accessor
&styler
, int pos
, WordList
&keywords
) {
85 char buf
[100]; /* copy to lowercase and ignore underscores */
89 char ch
= styler
.SafeGetCharAt(pos
, '\0');
90 if (!IsAWordChar(ch
)) break;
91 if (ch
!= '_' && i
< ((int)sizeof(buf
))-1) {
92 buf
[i
] = static_cast<char>(tolower(ch
));
98 /* look for keyword */
99 if (keywords
.InList(buf
)) {
100 styler
.ColourTo(pos
-1, SCE_P_WORD
);
102 styler
.ColourTo(pos
-1, SCE_P_IDENTIFIER
);
107 static int scanNumber(Accessor
&styler
, int pos
) {
109 ch
= styler
.SafeGetCharAt(pos
, '\0');
110 ch2
= styler
.SafeGetCharAt(pos
+1, '\0');
111 if (ch
== '0' && (ch2
== 'b' || ch2
== 'B')) {
115 ch
= styler
.SafeGetCharAt(pos
, '\0');
116 if (ch
== '_' || (ch
>= '0' && ch
<= '1')) ++pos
;
119 } else if (ch
== '0' &&
120 (ch2
== 'o' || ch2
== 'O' || ch2
== 'c' || ch2
== 'C')) {
124 ch
= styler
.SafeGetCharAt(pos
, '\0');
125 if (ch
== '_' || (ch
>= '0' && ch
<= '7')) ++pos
;
128 } else if (ch
== '0' && (ch2
== 'x' || ch2
== 'X')) {
129 /* hexadecimal number: */
132 ch
= styler
.SafeGetCharAt(pos
, '\0');
133 if (ch
== '_' || (ch
>= '0' && ch
<= '9')
134 || (ch
>= 'a' && ch
<= 'f')
135 || (ch
>= 'A' && ch
<= 'F')) ++pos
;
139 // skip decimal part:
141 ch
= styler
.SafeGetCharAt(pos
, '\0');
142 if (ch
== '_' || (ch
>= '0' && ch
<= '9')) ++pos
;
145 ch2
= styler
.SafeGetCharAt(pos
+1, '\0');
146 if (ch
== '.' && ch2
>= '0' && ch2
<= '9') {
149 ch
= styler
.SafeGetCharAt(pos
, '\0');
150 if (ch
== '_' || (ch
>= '0' && ch
<= '9')) ++pos
;
154 if (ch
== 'e' || ch
== 'E') {
156 ch
= styler
.SafeGetCharAt(pos
, '\0');
157 if (ch
== '-' || ch
== '+') ++pos
;
159 ch
= styler
.SafeGetCharAt(pos
, '\0');
160 if (ch
== '_' || (ch
>= '0' && ch
<= '9')) ++pos
;
169 ch
= styler
.SafeGetCharAt(pos
);
170 if ((ch
>= '0' && ch
<= '9') || (ch
>= 'A' && ch
<= 'Z')
171 || (ch
>= 'a' && ch
<= 'z') || ch
== '_') ++pos
;
175 styler
.ColourTo(pos
-1, SCE_P_NUMBER
);
179 /* rewritten from scratch, because I couldn't get rid of the bugs...
180 (A character based approach sucks!)
182 static void ColouriseNimrodDoc(unsigned int startPos
, int length
, int initStyle
,
183 WordList
*keywordlists
[], Accessor
&styler
) {
185 int max
= startPos
+ length
;
187 WordList
&keywords
= *keywordlists
[0];
189 styler
.StartAt(startPos
);
190 styler
.StartSegment(startPos
);
193 /* check where we are: */
194 case SCE_P_TRIPLEDOUBLE
:
195 pos
= tillEndOfTripleQuote(styler
, pos
, max
);
196 styler
.ColourTo(pos
, SCE_P_TRIPLEDOUBLE
);
199 default: /* nothing to do: */
203 ch
= styler
.SafeGetCharAt(pos
, '\0');
207 bool doccomment
= (styler
.SafeGetCharAt(pos
+1) == '#');
208 while (pos
< max
&& !isNewLine(styler
.SafeGetCharAt(pos
, LF
))) pos
++;
210 styler
.ColourTo(pos
, SCE_C_COMMENTLINEDOC
);
212 styler
.ColourTo(pos
, SCE_P_COMMENTLINE
);
214 case 'r': case 'R': {
215 if (styler
.SafeGetCharAt(pos
+1) == '"') {
216 pos
= scanString(styler
, pos
+2, max
, true);
217 styler
.ColourTo(pos
, SCE_P_STRING
);
220 pos
= scanIdent(styler
, pos
, keywords
);
224 if (styler
.Match(pos
+1, "\"\"")) {
225 pos
= tillEndOfTripleQuote(styler
, pos
+3, max
);
226 styler
.ColourTo(pos
, SCE_P_TRIPLEDOUBLE
);
228 pos
= scanString(styler
, pos
+1, max
, false);
229 styler
.ColourTo(pos
, SCE_P_STRING
);
234 pos
= scanChar(styler
, pos
+1, max
);
235 styler
.ColourTo(pos
, SCE_P_CHARACTER
);
238 default: // identifers, numbers, operators, whitespace
239 if (ch
>= '0' && ch
<= '9') {
240 pos
= scanNumber(styler
, pos
);
241 } else if (IsAWordChar(ch
)) {
242 pos
= scanIdent(styler
, pos
, keywords
);
243 } else if (ch
== '`') {
246 ch
= styler
.SafeGetCharAt(pos
, LF
);
251 if (ch
== CR
|| ch
== LF
) break;
254 styler
.ColourTo(pos
, SCE_P_IDENTIFIER
);
255 } else if (strchr("()[]{}:=;-\\/&%$!+<>|^?,.*~@", ch
)) {
256 styler
.ColourTo(pos
, SCE_P_OPERATOR
);
259 styler
.ColourTo(pos
, SCE_P_DEFAULT
);
267 static bool IsCommentLine(int line
, Accessor
&styler
) {
268 int pos
= styler
.LineStart(line
);
269 int eol_pos
= styler
.LineStart(line
+ 1) - 1;
270 for (int i
= pos
; i
< eol_pos
; i
++) {
274 else if (ch
!= ' ' && ch
!= '\t')
280 static bool IsQuoteLine(int line
, Accessor
&styler
) {
281 int style
= styler
.StyleAt(styler
.LineStart(line
)) & 31;
282 return ((style
== SCE_P_TRIPLE
) || (style
== SCE_P_TRIPLEDOUBLE
));
286 static void FoldNimrodDoc(unsigned int startPos
, int length
,
287 int /*initStyle - unused*/,
288 WordList
*[], Accessor
&styler
) {
289 const int maxPos
= startPos
+ length
;
290 const int maxLines
= styler
.GetLine(maxPos
- 1); // Requested last line
291 const int docLines
= styler
.GetLine(styler
.Length() - 1); // Available last line
292 const bool foldComment
= styler
.GetPropertyInt("fold.comment.nimrod") != 0;
293 const bool foldQuotes
= styler
.GetPropertyInt("fold.quotes.nimrod") != 0;
295 // Backtrack to previous non-blank line so we can determine indent level
296 // for any white space lines (needed esp. within triple quoted strings)
297 // and so we can fix any preceding fold level (which is why we go back
298 // at least one line in all cases)
300 int lineCurrent
= styler
.GetLine(startPos
);
301 int indentCurrent
= styler
.IndentAmount(lineCurrent
, &spaceFlags
, NULL
);
302 while (lineCurrent
> 0) {
304 indentCurrent
= styler
.IndentAmount(lineCurrent
, &spaceFlags
, NULL
);
305 if (!(indentCurrent
& SC_FOLDLEVELWHITEFLAG
) &&
306 (!IsCommentLine(lineCurrent
, styler
)) &&
307 (!IsQuoteLine(lineCurrent
, styler
)))
310 int indentCurrentLevel
= indentCurrent
& SC_FOLDLEVELNUMBERMASK
;
312 // Set up initial loop state
313 startPos
= styler
.LineStart(lineCurrent
);
314 int prev_state
= SCE_P_DEFAULT
& 31;
315 if (lineCurrent
>= 1)
316 prev_state
= styler
.StyleAt(startPos
- 1) & 31;
317 int prevQuote
= foldQuotes
&& ((prev_state
== SCE_P_TRIPLE
) ||
318 (prev_state
== SCE_P_TRIPLEDOUBLE
));
320 if (lineCurrent
>= 1)
321 prevComment
= foldComment
&& IsCommentLine(lineCurrent
- 1, styler
);
323 // Process all characters to end of requested range or end of any triple quote
324 // or comment that hangs over the end of the range. Cap processing in all cases
325 // to end of document (in case of unclosed quote or comment at end).
326 while ((lineCurrent
<= docLines
) && ((lineCurrent
<= maxLines
) ||
327 prevQuote
|| prevComment
)) {
330 int lev
= indentCurrent
;
331 int lineNext
= lineCurrent
+ 1;
332 int indentNext
= indentCurrent
;
334 if (lineNext
<= docLines
) {
335 // Information about next line is only available if not at end of document
336 indentNext
= styler
.IndentAmount(lineNext
, &spaceFlags
, NULL
);
337 int style
= styler
.StyleAt(styler
.LineStart(lineNext
)) & 31;
338 quote
= foldQuotes
&& ((style
== SCE_P_TRIPLE
) || (style
== SCE_P_TRIPLEDOUBLE
));
340 const int quote_start
= (quote
&& !prevQuote
);
341 const int quote_continue
= (quote
&& prevQuote
);
342 const int comment
= foldComment
&& IsCommentLine(lineCurrent
, styler
);
343 const int comment_start
= (comment
&& !prevComment
&& (lineNext
<= docLines
) &&
344 IsCommentLine(lineNext
, styler
) &&
345 (lev
> SC_FOLDLEVELBASE
));
346 const int comment_continue
= (comment
&& prevComment
);
347 if ((!quote
|| !prevQuote
) && !comment
)
348 indentCurrentLevel
= indentCurrent
& SC_FOLDLEVELNUMBERMASK
;
350 indentNext
= indentCurrentLevel
;
351 if (indentNext
& SC_FOLDLEVELWHITEFLAG
)
352 indentNext
= SC_FOLDLEVELWHITEFLAG
| indentCurrentLevel
;
355 // Place fold point at start of triple quoted string
356 lev
|= SC_FOLDLEVELHEADERFLAG
;
357 } else if (quote_continue
|| prevQuote
) {
358 // Add level to rest of lines in the string
360 } else if (comment_start
) {
361 // Place fold point at start of a block of comments
362 lev
|= SC_FOLDLEVELHEADERFLAG
;
363 } else if (comment_continue
) {
364 // Add level to rest of lines in the block
368 // Skip past any blank lines for next indent level info; we skip also
369 // comments (all comments, not just those starting in column 0)
370 // which effectively folds them into surrounding code rather
371 // than screwing up folding.
374 (lineNext
< docLines
) &&
375 ((indentNext
& SC_FOLDLEVELWHITEFLAG
) ||
376 (lineNext
<= docLines
&& IsCommentLine(lineNext
, styler
)))) {
379 indentNext
= styler
.IndentAmount(lineNext
, &spaceFlags
, NULL
);
382 const int levelAfterComments
= indentNext
& SC_FOLDLEVELNUMBERMASK
;
383 const int levelBeforeComments
=
384 Maximum(indentCurrentLevel
,levelAfterComments
);
386 // Now set all the indent levels on the lines we skipped
387 // Do this from end to start. Once we encounter one line
388 // which is indented more than the line after the end of
389 // the comment-block, use the level of the block before
391 int skipLine
= lineNext
;
392 int skipLevel
= levelAfterComments
;
394 while (--skipLine
> lineCurrent
) {
395 int skipLineIndent
= styler
.IndentAmount(skipLine
, &spaceFlags
, NULL
);
397 if ((skipLineIndent
& SC_FOLDLEVELNUMBERMASK
) > levelAfterComments
)
398 skipLevel
= levelBeforeComments
;
400 int whiteFlag
= skipLineIndent
& SC_FOLDLEVELWHITEFLAG
;
402 styler
.SetLevel(skipLine
, skipLevel
| whiteFlag
);
405 // Set fold header on non-quote/non-comment line
406 if (!quote
&& !comment
&& !(indentCurrent
& SC_FOLDLEVELWHITEFLAG
) ) {
407 if ((indentCurrent
& SC_FOLDLEVELNUMBERMASK
) <
408 (indentNext
& SC_FOLDLEVELNUMBERMASK
))
409 lev
|= SC_FOLDLEVELHEADERFLAG
;
412 // Keep track of triple quote and block comment state of previous line
414 prevComment
= comment_start
|| comment_continue
;
416 // Set fold level for this line and move to next line
417 styler
.SetLevel(lineCurrent
, lev
);
418 indentCurrent
= indentNext
;
419 lineCurrent
= lineNext
;
422 // NOTE: Cannot set level of last line here because indentCurrent doesn't have
423 // header flag set; the loop above is crafted to take care of this case!
424 //styler.SetLevel(lineCurrent, indentCurrent);
427 static const char * const nimrodWordListDesc
[] = {
432 LexerModule
lmNimrod(SCLEX_NIMROD
, ColouriseNimrodDoc
, "nimrod", FoldNimrodDoc
,