~efargaspro/+junk/codeblocks-16.01-release

« back to all changes in this revision

Viewing changes to src/plugins/contrib/wxSmithSTC/stc/scintilla/src/LexPython.cxx

  • Committer: damienlmoore at gmail
  • Date: 2016-02-02 02:43:22 UTC
  • Revision ID: damienlmoore@gmail.com-20160202024322-yql5qmtbwdyamdwd
Code::BlocksĀ 16.01

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Scintilla source code edit control
 
2
/** @file LexPython.cxx
 
3
 ** Lexer for Python.
 
4
 **/
 
5
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
 
6
// The License.txt file describes the conditions under which this software may be distributed.
 
7
 
 
8
#include <stdlib.h>
 
9
#include <string.h>
 
10
#include <ctype.h>
 
11
#include <stdio.h>
 
12
#include <stdarg.h>
 
13
 
 
14
#include "Platform.h"
 
15
 
 
16
#include "PropSet.h"
 
17
#include "Accessor.h"
 
18
#include "StyleContext.h"
 
19
#include "KeyWords.h"
 
20
#include "Scintilla.h"
 
21
#include "SciLexer.h"
 
22
 
 
23
enum kwType { kwOther, kwClass, kwDef, kwImport };
 
24
 
 
25
static bool IsPyComment(Accessor &styler, int pos, int len) {
 
26
        return len > 0 && styler[pos] == '#';
 
27
}
 
28
 
 
29
static bool IsPyStringStart(int ch, int chNext, int chNext2) {
 
30
        if (ch == '\'' || ch == '"')
 
31
                return true;
 
32
        if (ch == 'u' || ch == 'U') {
 
33
                if (chNext == '"' || chNext == '\'')
 
34
                        return true;
 
35
                if ((chNext == 'r' || chNext == 'R') && (chNext2 == '"' || chNext2 == '\''))
 
36
                        return true;
 
37
        }
 
38
        if ((ch == 'r' || ch == 'R') && (chNext == '"' || chNext == '\''))
 
39
                return true;
 
40
 
 
41
        return false;
 
42
}
 
43
 
 
44
/* Return the state to use for the string starting at i; *nextIndex will be set to the first index following the quote(s) */
 
45
static int GetPyStringState(Accessor &styler, int i, unsigned int *nextIndex) {
 
46
        char ch = styler.SafeGetCharAt(i);
 
47
        char chNext = styler.SafeGetCharAt(i + 1);
 
48
 
 
49
        // Advance beyond r, u, or ur prefix, but bail if there are any unexpected chars
 
50
        if (ch == 'r' || ch == 'R') {
 
51
                i++;
 
52
                ch = styler.SafeGetCharAt(i);
 
53
                chNext = styler.SafeGetCharAt(i + 1);
 
54
        } else if (ch == 'u' || ch == 'U') {
 
55
                if (chNext == 'r' || chNext == 'R')
 
56
                        i += 2;
 
57
                else
 
58
                        i += 1;
 
59
                ch = styler.SafeGetCharAt(i);
 
60
                chNext = styler.SafeGetCharAt(i + 1);
 
61
        }
 
62
 
 
63
        if (ch != '"' && ch != '\'') {
 
64
                *nextIndex = i + 1;
 
65
                return SCE_P_DEFAULT;
 
66
        }
 
67
 
 
68
        if (ch == chNext && ch == styler.SafeGetCharAt(i + 2)) {
 
69
                *nextIndex = i + 3;
 
70
 
 
71
                if (ch == '"')
 
72
                        return SCE_P_TRIPLEDOUBLE;
 
73
                else
 
74
                        return SCE_P_TRIPLE;
 
75
        } else {
 
76
                *nextIndex = i + 1;
 
77
 
 
78
                if (ch == '"')
 
79
                        return SCE_P_STRING;
 
80
                else
 
81
                        return SCE_P_CHARACTER;
 
82
        }
 
83
}
 
84
 
 
85
static inline bool IsAWordChar(int ch) {
 
86
        return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
 
87
}
 
88
 
 
89
static inline bool IsAWordStart(int ch) {
 
90
        return (ch < 0x80) && (isalnum(ch) || ch == '_');
 
91
}
 
92
 
 
93
static void ColourisePyDoc(unsigned int startPos, int length, int initStyle,
 
94
                           WordList *keywordlists[], Accessor &styler) {
 
95
 
 
96
        int endPos = startPos + length;
 
97
 
 
98
        // Backtrack to previous line in case need to fix its tab whinging
 
99
        int lineCurrent = styler.GetLine(startPos);
 
100
        if (startPos > 0) {
 
101
                if (lineCurrent > 0) {
 
102
                        lineCurrent--;
 
103
                        startPos = styler.LineStart(lineCurrent);
 
104
                        if (startPos == 0)
 
105
                                initStyle = SCE_P_DEFAULT;
 
106
                        else
 
107
                                initStyle = styler.StyleAt(startPos - 1);
 
108
                }
 
109
        }
 
110
 
 
111
        WordList &keywords = *keywordlists[0];
 
112
        WordList &keywords2 = *keywordlists[1];
 
113
 
 
114
        const int whingeLevel = styler.GetPropertyInt("tab.timmy.whinge.level");
 
115
 
 
116
        initStyle = initStyle & 31;
 
117
        if (initStyle == SCE_P_STRINGEOL) {
 
118
                initStyle = SCE_P_DEFAULT;
 
119
        }
 
120
 
 
121
        kwType kwLast = kwOther;
 
122
        int spaceFlags = 0;
 
123
        styler.IndentAmount(lineCurrent, &spaceFlags, IsPyComment);
 
124
        bool hexadecimal = false;
 
125
 
 
126
        // Python uses a different mask because bad indentation is marked by oring with 32
 
127
        StyleContext sc(startPos, endPos - startPos, initStyle, styler, 0x7f);
 
128
 
 
129
        for (; sc.More(); sc.Forward()) {
 
130
 
 
131
                if (sc.atLineStart) {
 
132
                        const char chBad = static_cast<char>(64);
 
133
                        const char chGood = static_cast<char>(0);
 
134
                        char chFlags = chGood;
 
135
                        if (whingeLevel == 1) {
 
136
                                chFlags = (spaceFlags & wsInconsistent) ? chBad : chGood;
 
137
                        } else if (whingeLevel == 2) {
 
138
                                chFlags = (spaceFlags & wsSpaceTab) ? chBad : chGood;
 
139
                        } else if (whingeLevel == 3) {
 
140
                                chFlags = (spaceFlags & wsSpace) ? chBad : chGood;
 
141
                        } else if (whingeLevel == 4) {
 
142
                                chFlags = (spaceFlags & wsTab) ? chBad : chGood;
 
143
                        }
 
144
                        sc.SetState(sc.state);
 
145
                        styler.SetFlags(chFlags, static_cast<char>(sc.state));
 
146
                }
 
147
 
 
148
                if (sc.atLineEnd) {
 
149
                        if ((sc.state == SCE_P_DEFAULT) ||
 
150
                                (sc.state == SCE_P_TRIPLE) ||
 
151
                                (sc.state == SCE_P_TRIPLEDOUBLE)) {
 
152
                                // Perform colourisation of white space and triple quoted strings at end of each line to allow
 
153
                                // tab marking to work inside white space and triple quoted strings
 
154
                                sc.SetState(sc.state);
 
155
                        }
 
156
                        lineCurrent++;
 
157
                        styler.IndentAmount(lineCurrent, &spaceFlags, IsPyComment);
 
158
                        if ((sc.state == SCE_P_STRING) || (sc.state == SCE_P_CHARACTER)) {
 
159
                                sc.ChangeState(SCE_P_STRINGEOL);
 
160
                                sc.ForwardSetState(SCE_P_DEFAULT);
 
161
                        }
 
162
                        if (!sc.More())
 
163
                                break;
 
164
                }
 
165
 
 
166
                bool needEOLCheck = false;
 
167
 
 
168
                // Check for a state end
 
169
                if (sc.state == SCE_P_OPERATOR) {
 
170
                        kwLast = kwOther;
 
171
                        sc.SetState(SCE_P_DEFAULT);
 
172
                } else if (sc.state == SCE_P_NUMBER) {
 
173
                        if (!IsAWordChar(sc.ch) &&
 
174
                                !(!hexadecimal && ((sc.ch == '+' || sc.ch == '-') && (sc.chPrev == 'e' || sc.chPrev == 'E')))) {
 
175
                                sc.SetState(SCE_P_DEFAULT);
 
176
                        }
 
177
                } else if (sc.state == SCE_P_IDENTIFIER) {
 
178
                        if ((sc.ch == '.') || (!IsAWordChar(sc.ch))) {
 
179
                                char s[100];
 
180
                                sc.GetCurrent(s, sizeof(s));
 
181
                                int style = SCE_P_IDENTIFIER;
 
182
                                if ((kwLast == kwImport) && (strcmp(s, "as") == 0)) {
 
183
                                        style = SCE_P_WORD;
 
184
                                } else if (keywords.InList(s)) {
 
185
                                        style = SCE_P_WORD;
 
186
                                } else if (kwLast == kwClass) {
 
187
                                        style = SCE_P_CLASSNAME;
 
188
                                } else if (kwLast == kwDef) {
 
189
                                        style = SCE_P_DEFNAME;
 
190
                                } else if (keywords2.InList(s)) {
 
191
                                        style = SCE_P_WORD2;
 
192
                                }
 
193
                                sc.ChangeState(style);
 
194
                                sc.SetState(SCE_P_DEFAULT);
 
195
                                if (style == SCE_P_WORD) {
 
196
                                        if (0 == strcmp(s, "class"))
 
197
                                                kwLast = kwClass;
 
198
                                        else if (0 == strcmp(s, "def"))
 
199
                                                kwLast = kwDef;
 
200
                                        else if (0 == strcmp(s, "import"))
 
201
                                                kwLast = kwImport;
 
202
                                        else
 
203
                                                kwLast = kwOther;
 
204
                                } else {
 
205
                                        kwLast = kwOther;
 
206
                                }
 
207
                        }
 
208
                } else if ((sc.state == SCE_P_COMMENTLINE) || (sc.state == SCE_P_COMMENTBLOCK)) {
 
209
                        if (sc.ch == '\r' || sc.ch == '\n') {
 
210
                                sc.SetState(SCE_P_DEFAULT);
 
211
                        }
 
212
                } else if (sc.state == SCE_P_DECORATOR) {
 
213
                        if (sc.ch == '\r' || sc.ch == '\n') {
 
214
                                sc.SetState(SCE_P_DEFAULT);
 
215
                        } else if (sc.ch == '#') {
 
216
                                sc.SetState((sc.chNext == '#') ? SCE_P_COMMENTBLOCK  :  SCE_P_COMMENTLINE);
 
217
                        }
 
218
                } else if ((sc.state == SCE_P_STRING) || (sc.state == SCE_P_CHARACTER)) {
 
219
                        if (sc.ch == '\\') {
 
220
                                if ((sc.chNext == '\r') && (sc.GetRelative(2) == '\n')) {
 
221
                                        sc.Forward();
 
222
                                }
 
223
                                sc.Forward();
 
224
                        } else if ((sc.state == SCE_P_STRING) && (sc.ch == '\"')) {
 
225
                                sc.ForwardSetState(SCE_P_DEFAULT);
 
226
                                needEOLCheck = true;
 
227
                        } else if ((sc.state == SCE_P_CHARACTER) && (sc.ch == '\'')) {
 
228
                                sc.ForwardSetState(SCE_P_DEFAULT);
 
229
                                needEOLCheck = true;
 
230
                        }
 
231
                } else if (sc.state == SCE_P_TRIPLE) {
 
232
                        if (sc.ch == '\\') {
 
233
                                sc.Forward();
 
234
                        } else if (sc.Match("\'\'\'")) {
 
235
                                sc.Forward();
 
236
                                sc.Forward();
 
237
                                sc.ForwardSetState(SCE_P_DEFAULT);
 
238
                                needEOLCheck = true;
 
239
                        }
 
240
                } else if (sc.state == SCE_P_TRIPLEDOUBLE) {
 
241
                        if (sc.ch == '\\') {
 
242
                                sc.Forward();
 
243
                        } else if (sc.Match("\"\"\"")) {
 
244
                                sc.Forward();
 
245
                                sc.Forward();
 
246
                                sc.ForwardSetState(SCE_P_DEFAULT);
 
247
                                needEOLCheck = true;
 
248
                        }
 
249
                }
 
250
 
 
251
                // State exit code may have moved on to end of line
 
252
                if (needEOLCheck && sc.atLineEnd) {
 
253
                        lineCurrent++;
 
254
                        styler.IndentAmount(lineCurrent, &spaceFlags, IsPyComment);
 
255
                        if (!sc.More())
 
256
                                break;
 
257
                }
 
258
 
 
259
                // Check for a new state starting character
 
260
                if (sc.state == SCE_P_DEFAULT) {
 
261
                        if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
 
262
                                if (sc.ch == '0' && (sc.chNext == 'x' || sc.chNext == 'X')) {
 
263
                                        hexadecimal = true;
 
264
                                } else {
 
265
                                        hexadecimal = false;
 
266
                                }
 
267
                                sc.SetState(SCE_P_NUMBER);
 
268
                        } else if (isascii(sc.ch) && isoperator(static_cast<char>(sc.ch)) || sc.ch == '`') {
 
269
                                sc.SetState(SCE_P_OPERATOR);
 
270
                        } else if (sc.ch == '#') {
 
271
                                sc.SetState(sc.chNext == '#' ? SCE_P_COMMENTBLOCK : SCE_P_COMMENTLINE);
 
272
                        } else if (sc.ch == '@') {
 
273
                                sc.SetState(SCE_P_DECORATOR);
 
274
                        } else if (IsPyStringStart(sc.ch, sc.chNext, sc.GetRelative(2))) {
 
275
                                unsigned int nextIndex = 0;
 
276
                                sc.SetState(GetPyStringState(styler, sc.currentPos, &nextIndex));
 
277
                                while (nextIndex > (sc.currentPos + 1) && sc.More()) {
 
278
                                        sc.Forward();
 
279
                                }
 
280
                        } else if (IsAWordStart(sc.ch)) {
 
281
                                sc.SetState(SCE_P_IDENTIFIER);
 
282
                        }
 
283
                }
 
284
        }
 
285
        sc.Complete();
 
286
}
 
287
 
 
288
static bool IsCommentLine(int line, Accessor &styler) {
 
289
        int pos = styler.LineStart(line);
 
290
        int eol_pos = styler.LineStart(line + 1) - 1;
 
291
        for (int i = pos; i < eol_pos; i++) {
 
292
                char ch = styler[i];
 
293
                if (ch == '#')
 
294
                        return true;
 
295
                else if (ch != ' ' && ch != '\t')
 
296
                        return false;
 
297
        }
 
298
        return false;
 
299
}
 
300
 
 
301
static bool IsQuoteLine(int line, Accessor &styler) {
 
302
        int style = styler.StyleAt(styler.LineStart(line)) & 31;
 
303
        return ((style == SCE_P_TRIPLE) || (style == SCE_P_TRIPLEDOUBLE));
 
304
}
 
305
 
 
306
 
 
307
static void FoldPyDoc(unsigned int startPos, int length, int /*initStyle - unused*/,
 
308
                      WordList *[], Accessor &styler) {
 
309
        const int maxPos = startPos + length;
 
310
        const int maxLines = styler.GetLine(maxPos - 1);             // Requested last line
 
311
        const int docLines = styler.GetLine(styler.Length() - 1);  // Available last line
 
312
        const bool foldComment = styler.GetPropertyInt("fold.comment.python") != 0;
 
313
        const bool foldQuotes = styler.GetPropertyInt("fold.quotes.python") != 0;
 
314
 
 
315
        // Backtrack to previous non-blank line so we can determine indent level
 
316
        // for any white space lines (needed esp. within triple quoted strings)
 
317
        // and so we can fix any preceding fold level (which is why we go back
 
318
        // at least one line in all cases)
 
319
        int spaceFlags = 0;
 
320
        int lineCurrent = styler.GetLine(startPos);
 
321
        int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL);
 
322
        while (lineCurrent > 0) {
 
323
                lineCurrent--;
 
324
                indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, NULL);
 
325
                if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG) &&
 
326
                        (!IsCommentLine(lineCurrent, styler)) &&
 
327
                        (!IsQuoteLine(lineCurrent, styler)))
 
328
                        break;
 
329
        }
 
330
        int indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK;
 
331
 
 
332
        // Set up initial loop state
 
333
        startPos = styler.LineStart(lineCurrent);
 
334
        int prev_state = SCE_P_DEFAULT & 31;
 
335
        if (lineCurrent >= 1)
 
336
                prev_state = styler.StyleAt(startPos - 1) & 31;
 
337
        int prevQuote = foldQuotes && ((prev_state == SCE_P_TRIPLE) || (prev_state == SCE_P_TRIPLEDOUBLE));
 
338
        int prevComment = 0;
 
339
        if (lineCurrent >= 1)
 
340
                prevComment = foldComment && IsCommentLine(lineCurrent - 1, styler);
 
341
 
 
342
        // Process all characters to end of requested range or end of any triple quote
 
343
        // or comment that hangs over the end of the range.  Cap processing in all cases
 
344
        // to end of document (in case of unclosed quote or comment at end).
 
345
        while ((lineCurrent <= docLines) && ((lineCurrent <= maxLines) || prevQuote || prevComment)) {
 
346
 
 
347
                // Gather info
 
348
                int lev = indentCurrent;
 
349
                int lineNext = lineCurrent + 1;
 
350
                int indentNext = indentCurrent;
 
351
                int quote = false;
 
352
                if (lineNext <= docLines) {
 
353
                        // Information about next line is only available if not at end of document
 
354
                        indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL);
 
355
                        int style = styler.StyleAt(styler.LineStart(lineNext)) & 31;
 
356
                        quote = foldQuotes && ((style == SCE_P_TRIPLE) || (style == SCE_P_TRIPLEDOUBLE));
 
357
                }
 
358
                const int quote_start = (quote && !prevQuote);
 
359
                const int quote_continue = (quote && prevQuote);
 
360
                const int comment = foldComment && IsCommentLine(lineCurrent, styler);
 
361
                const int comment_start = (comment && !prevComment && (lineNext <= docLines) &&
 
362
                                           IsCommentLine(lineNext, styler) && (lev > SC_FOLDLEVELBASE));
 
363
                const int comment_continue = (comment && prevComment);
 
364
                if ((!quote || !prevQuote) && !comment)
 
365
                        indentCurrentLevel = indentCurrent & SC_FOLDLEVELNUMBERMASK;
 
366
                if (quote)
 
367
                        indentNext = indentCurrentLevel;
 
368
                if (indentNext & SC_FOLDLEVELWHITEFLAG)
 
369
                        indentNext = SC_FOLDLEVELWHITEFLAG | indentCurrentLevel;
 
370
 
 
371
                if (quote_start) {
 
372
                        // Place fold point at start of triple quoted string
 
373
                        lev |= SC_FOLDLEVELHEADERFLAG;
 
374
                } else if (quote_continue || prevQuote) {
 
375
                        // Add level to rest of lines in the string
 
376
                        lev = lev + 1;
 
377
                } else if (comment_start) {
 
378
                        // Place fold point at start of a block of comments
 
379
                        lev |= SC_FOLDLEVELHEADERFLAG;
 
380
                } else if (comment_continue) {
 
381
                        // Add level to rest of lines in the block
 
382
                        lev = lev + 1;
 
383
                }
 
384
 
 
385
                // Skip past any blank lines for next indent level info; we skip also
 
386
                // comments (all comments, not just those starting in column 0)
 
387
                // which effectively folds them into surrounding code rather
 
388
                // than screwing up folding.
 
389
 
 
390
                while (!quote &&
 
391
                        (lineNext < docLines) &&
 
392
                        ((indentNext & SC_FOLDLEVELWHITEFLAG) ||
 
393
                         (lineNext <= docLines && IsCommentLine(lineNext, styler)))) {
 
394
 
 
395
                        lineNext++;
 
396
                        indentNext = styler.IndentAmount(lineNext, &spaceFlags, NULL);
 
397
                }
 
398
 
 
399
                const int levelAfterComments = indentNext & SC_FOLDLEVELNUMBERMASK;
 
400
                const int levelBeforeComments = Platform::Maximum(indentCurrentLevel,levelAfterComments);
 
401
 
 
402
                // Now set all the indent levels on the lines we skipped
 
403
                // Do this from end to start.  Once we encounter one line
 
404
                // which is indented more than the line after the end of
 
405
                // the comment-block, use the level of the block before
 
406
 
 
407
                int skipLine = lineNext;
 
408
                int skipLevel = levelAfterComments;
 
409
 
 
410
                while (--skipLine > lineCurrent) {
 
411
                        int skipLineIndent = styler.IndentAmount(skipLine, &spaceFlags, NULL);
 
412
 
 
413
                        if ((skipLineIndent & SC_FOLDLEVELNUMBERMASK) > levelAfterComments)
 
414
                                skipLevel = levelBeforeComments;
 
415
 
 
416
                        int whiteFlag = skipLineIndent & SC_FOLDLEVELWHITEFLAG;
 
417
 
 
418
                        styler.SetLevel(skipLine, skipLevel | whiteFlag);
 
419
                }
 
420
 
 
421
                // Set fold header on non-quote/non-comment line
 
422
                if (!quote && !comment && !(indentCurrent & SC_FOLDLEVELWHITEFLAG) ) {
 
423
                        if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK))
 
424
                                lev |= SC_FOLDLEVELHEADERFLAG;
 
425
                }
 
426
 
 
427
                // Keep track of triple quote and block comment state of previous line
 
428
                prevQuote = quote;
 
429
                prevComment = comment_start || comment_continue;
 
430
 
 
431
                // Set fold level for this line and move to next line
 
432
                styler.SetLevel(lineCurrent, lev);
 
433
                indentCurrent = indentNext;
 
434
                lineCurrent = lineNext;
 
435
        }
 
436
 
 
437
        // NOTE: Cannot set level of last line here because indentCurrent doesn't have
 
438
        // header flag set; the loop above is crafted to take care of this case!
 
439
        //styler.SetLevel(lineCurrent, indentCurrent);
 
440
}
 
441
 
 
442
static const char * const pythonWordListDesc[] = {
 
443
        "Keywords",
 
444
        "Highlighted identifiers",
 
445
        0
 
446
};
 
447
 
 
448
LexerModule lmPython(SCLEX_PYTHON, ColourisePyDoc, "python", FoldPyDoc,
 
449
                                         pythonWordListDesc);