~registry/codeblocks/trunk

« back to all changes in this revision

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

  • Committer: mortenmacfly
  • Date: 2012-02-22 14:40:26 UTC
  • Revision ID: svn-v4:98b59c6a-2706-0410-b7d6-d2fa1a1880c9:trunk:7835
* merged wxSmith branch into trunk
* this brings tons of new wxSmith items, including KWIC, wxImagePanel, wxGridBagSizer and more
* based on work of the community, mainly cryogen
* for more information, see changelog of wxSmith branch
* also, re-factoring of contributed wxWidgets items for wxSmith
* PLEASE DO A CLEAN CHECKOUT AND RE-BUILD EVERYTHING FROM SCRATCH!

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Scintilla source code edit control
 
2
/** @file LexTADS3.cxx
 
3
 ** Lexer for TADS3.
 
4
 **/
 
5
/* Copyright 2005 by Michael Cartmell
 
6
 * Parts copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
 
7
 * In particular FoldTADS3Doc is derived from FoldCppDoc
 
8
 * The License.txt file describes the conditions under which this software may
 
9
 * be distributed.
 
10
 */
 
11
 
 
12
/*
 
13
 * TADS3 is a language designed by Michael J. Roberts for the writing of text
 
14
 * based games.  TADS comes from Text Adventure Development System.  It has good
 
15
 * support for the processing and outputting of formatted text and much of a
 
16
 * TADS program listing consists of strings.
 
17
 *
 
18
 * TADS has two types of strings, those enclosed in single quotes (') and those
 
19
 * enclosed in double quotes (").  These strings have different symantics and
 
20
 * can be given different highlighting if desired.
 
21
 *
 
22
 * There can be embedded within both types of strings html tags
 
23
 * ( <tag key=value> ), library directives ( <.directive> ), and message
 
24
 * parameters ( {The doctor's/his} ).
 
25
 *
 
26
 * Double quoted strings can also contain interpolated expressions
 
27
 * ( << rug.moved ? ' and a hole in the floor. ' : nil >> ).  These expressions
 
28
 * may themselves contain single or double quoted strings, although the double
 
29
 * quoted strings may not contain interpolated expressions.
 
30
 *
 
31
 * These embedded constructs influence the output and formatting and are an
 
32
 * important part of a program and require highlighting.
 
33
 *
 
34
 * LINKS
 
35
 * http://www.tads.org/
 
36
 */
 
37
 
 
38
#include <stdlib.h>
 
39
#include <string.h>
 
40
#include <ctype.h>
 
41
#include <stdio.h>
 
42
#include <stdarg.h>
 
43
 
 
44
#include "Platform.h"
 
45
 
 
46
#include "PropSet.h"
 
47
#include "Accessor.h"
 
48
#include "StyleContext.h"
 
49
#include "KeyWords.h"
 
50
#include "Scintilla.h"
 
51
#include "SciLexer.h"
 
52
 
 
53
static const int T3_SINGLE_QUOTE = 1;
 
54
static const int T3_INT_EXPRESSION = 2;
 
55
 
 
56
static inline bool IsEOL(const int ch, const int chNext) {
 
57
        return (ch == '\r' && chNext != '\n') || (ch == '\n');
 
58
}
 
59
 
 
60
static inline bool IsASpaceOrTab(const int ch) {
 
61
        return ch == ' ' || ch == '\t';
 
62
}
 
63
 
 
64
static inline bool IsATADS3Operator(const int ch) {
 
65
        return ch == '=' || ch == '{' || ch == '}' || ch == '(' || ch == ')'
 
66
                || ch == '[' || ch == ']' || ch == ',' || ch == ':' || ch == ';'
 
67
                || ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%'
 
68
                || ch == '?' || ch == '!' || ch == '<' || ch == '>' || ch == '|'
 
69
                || ch == '@' || ch == '&' || ch == '~';
 
70
}
 
71
 
 
72
static inline bool IsAWordChar(const int ch) {
 
73
        return isalnum(ch) || ch == '_' || ch == '.';
 
74
}
 
75
 
 
76
static inline bool IsAWordStart(const int ch) {
 
77
        return isalpha(ch) || ch == '_';
 
78
}
 
79
 
 
80
static inline bool IsAHexDigit(const int ch) {
 
81
        int lch = tolower(ch);
 
82
        return isdigit(lch) || lch == 'a' || lch == 'b' || lch == 'c'
 
83
                || lch == 'd' || lch == 'e' || lch == 'f';
 
84
}
 
85
 
 
86
static inline bool IsAnHTMLChar(int ch) {
 
87
        return isalnum(ch) || ch == '-' || ch == '_' || ch == '.';
 
88
}
 
89
 
 
90
static inline bool IsADirectiveChar(int ch) {
 
91
        return isalnum(ch) || isspace(ch) || ch == '-' || ch == '/';
 
92
}
 
93
 
 
94
static inline bool IsANumberStart(StyleContext &sc) {
 
95
        return isdigit(sc.ch)
 
96
                || (!isdigit(sc.chPrev) && sc.ch == '.' && isdigit(sc.chNext));
 
97
}
 
98
 
 
99
inline static void ColouriseTADS3Operator(StyleContext &sc) {
 
100
        int initState = sc.state;
 
101
        sc.SetState(SCE_T3_OPERATOR);
 
102
        sc.ForwardSetState(initState);
 
103
}
 
104
 
 
105
static void ColouriseTADSHTMLString(StyleContext &sc, int &lineState) {
 
106
        int endState = sc.state;
 
107
        int chQuote = sc.ch;
 
108
        if (endState == SCE_T3_HTML_STRING) {
 
109
                if (lineState&T3_SINGLE_QUOTE) {
 
110
                        endState = SCE_T3_S_STRING;
 
111
                        chQuote = '"';
 
112
                } else if (lineState&T3_INT_EXPRESSION) {
 
113
                        endState = SCE_T3_X_STRING;
 
114
                        chQuote = '\'';
 
115
                } else {
 
116
                        endState = SCE_T3_D_STRING;
 
117
                        chQuote = '\'';
 
118
                }
 
119
        } else {
 
120
                sc.SetState(SCE_T3_HTML_STRING);
 
121
                sc.Forward();
 
122
        }
 
123
        int chString = chQuote == '"'? '\'': '"';
 
124
 
 
125
        while (sc.More()) {
 
126
                if (IsEOL(sc.ch, sc.chNext)) {
 
127
                        return;
 
128
                }
 
129
                if (sc.ch == chQuote) {
 
130
                        sc.ForwardSetState(endState);
 
131
                        return;
 
132
                }
 
133
                if (sc.ch == chString) {
 
134
                        sc.SetState(endState);
 
135
                        return;
 
136
                }
 
137
                if (sc.Match('\\', static_cast<char>(chQuote))
 
138
                        || sc.Match('\\', static_cast<char>(chString))) {
 
139
                        sc.Forward(2);
 
140
                } else {
 
141
                        sc.Forward();
 
142
                }
 
143
        }
 
144
}
 
145
 
 
146
static void ColouriseTADS3HTMLTagStart(StyleContext &sc) {
 
147
        sc.SetState(SCE_T3_HTML_TAG);
 
148
        sc.Forward();
 
149
        if (sc.ch == '/') {
 
150
                sc.Forward();
 
151
        }
 
152
        while (IsAnHTMLChar(sc.ch)) {
 
153
                sc.Forward();
 
154
        }
 
155
}
 
156
 
 
157
static void ColouriseTADS3HTMLTag(StyleContext &sc, int &lineState) {
 
158
        int endState = sc.state;
 
159
        int chQuote = '"';
 
160
        int chString = '\'';
 
161
        switch (endState) {
 
162
                case SCE_T3_S_STRING:
 
163
                        ColouriseTADS3HTMLTagStart(sc);
 
164
                        sc.SetState(SCE_T3_HTML_DEFAULT);
 
165
                        chQuote = '\'';
 
166
                        chString = '"';
 
167
                        break;
 
168
                case SCE_T3_D_STRING:
 
169
                case SCE_T3_X_STRING:
 
170
                        ColouriseTADS3HTMLTagStart(sc);
 
171
                        sc.SetState(SCE_T3_HTML_DEFAULT);
 
172
                        break;
 
173
                case SCE_T3_HTML_DEFAULT:
 
174
                        if (lineState&T3_SINGLE_QUOTE) {
 
175
                                endState = SCE_T3_S_STRING;
 
176
                                chQuote = '\'';
 
177
                                chString = '"';
 
178
                        } else if (lineState&T3_INT_EXPRESSION) {
 
179
                                endState = SCE_T3_X_STRING;
 
180
                        } else {
 
181
                                endState = SCE_T3_D_STRING;
 
182
                        }
 
183
                        break;
 
184
        }
 
185
 
 
186
        while (sc.More()) {
 
187
                if (IsEOL(sc.ch, sc.chNext)) {
 
188
                        return;
 
189
                }
 
190
                if (sc.Match('/', '>')) {
 
191
                        sc.SetState(SCE_T3_HTML_TAG);
 
192
                        sc.Forward(2);
 
193
                        sc.SetState(endState);
 
194
                        return;
 
195
                }
 
196
                if (sc.ch == '>') {
 
197
                        sc.SetState(SCE_T3_HTML_TAG);
 
198
                        sc.ForwardSetState(endState);
 
199
                        return;
 
200
                }
 
201
                if (sc.ch == chQuote) {
 
202
                        sc.SetState(endState);
 
203
                        return;
 
204
                }
 
205
                if (sc.ch == chString) {
 
206
                        ColouriseTADSHTMLString(sc, lineState);
 
207
                } else if (sc.ch == '=') {
 
208
                        ColouriseTADS3Operator(sc);
 
209
                } else {
 
210
                        sc.Forward();
 
211
                }
 
212
        }
 
213
}
 
214
 
 
215
static void ColouriseTADS3Keyword(StyleContext &sc,
 
216
                                                        WordList *keywordlists[],       unsigned int endPos) {
 
217
        char s[250];
 
218
        WordList &keywords = *keywordlists[0];
 
219
        WordList &userwords1 = *keywordlists[1];
 
220
        WordList &userwords2 = *keywordlists[2];
 
221
        WordList &userwords3 = *keywordlists[3];
 
222
        int initState = sc.state;
 
223
        sc.SetState(SCE_T3_IDENTIFIER);
 
224
        while (sc.More() && (IsAWordChar(sc.ch))) {
 
225
                sc.Forward();
 
226
        }
 
227
        sc.GetCurrent(s, sizeof(s));
 
228
        if ( strcmp(s, "is") == 0 || strcmp(s, "not") == 0) {
 
229
                // have to find if "in" is next
 
230
                int n = 1;
 
231
                while (n + sc.currentPos < endPos && IsASpaceOrTab(sc.GetRelative(n)))
 
232
                        n++;
 
233
                if (sc.GetRelative(n) == 'i' && sc.GetRelative(n+1) == 'n') {
 
234
                        sc.Forward(n+2);
 
235
                        sc.ChangeState(SCE_T3_KEYWORD);
 
236
                }
 
237
        } else if (keywords.InList(s)) {
 
238
                sc.ChangeState(SCE_T3_KEYWORD);
 
239
        } else if (userwords3.InList(s)) {
 
240
                sc.ChangeState(SCE_T3_USER3);
 
241
        } else if (userwords2.InList(s)) {
 
242
                sc.ChangeState(SCE_T3_USER2);
 
243
        } else if (userwords1.InList(s)) {
 
244
                sc.ChangeState(SCE_T3_USER1);
 
245
        }
 
246
        sc.SetState(initState);
 
247
}
 
248
 
 
249
static void ColouriseTADS3MsgParam(StyleContext &sc, int &lineState) {
 
250
        int endState = sc.state;
 
251
        int chQuote = '"';
 
252
        switch (endState) {
 
253
                case SCE_T3_S_STRING:
 
254
                        sc.SetState(SCE_T3_MSG_PARAM);
 
255
                        sc.Forward();
 
256
                        chQuote = '\'';
 
257
                        break;
 
258
                case SCE_T3_D_STRING:
 
259
                case SCE_T3_X_STRING:
 
260
                        sc.SetState(SCE_T3_MSG_PARAM);
 
261
                        sc.Forward();
 
262
                        break;
 
263
                case SCE_T3_MSG_PARAM:
 
264
                        if (lineState&T3_SINGLE_QUOTE) {
 
265
                                endState = SCE_T3_S_STRING;
 
266
                                chQuote = '\'';
 
267
                        } else if (lineState&T3_INT_EXPRESSION) {
 
268
                                endState = SCE_T3_X_STRING;
 
269
                        } else {
 
270
                                endState = SCE_T3_D_STRING;
 
271
                        }
 
272
                        break;
 
273
        }
 
274
        while (sc.More() && sc.ch != '}' && sc.ch != chQuote) {
 
275
                if (IsEOL(sc.ch, sc.chNext)) {
 
276
                        return;
 
277
                }
 
278
                if (sc.ch == '\\') {
 
279
                        sc.Forward();
 
280
                }
 
281
                sc.Forward();
 
282
        }
 
283
        if (sc.ch == chQuote) {
 
284
                sc.SetState(endState);
 
285
        } else {
 
286
                sc.ForwardSetState(endState);
 
287
        }
 
288
}
 
289
 
 
290
static void ColouriseTADS3LibDirective(StyleContext &sc, int &lineState) {
 
291
        int initState = sc.state;
 
292
        int chQuote = '"';
 
293
        switch (initState) {
 
294
                case SCE_T3_S_STRING:
 
295
                        sc.SetState(SCE_T3_LIB_DIRECTIVE);
 
296
                        sc.Forward(2);
 
297
                        chQuote = '\'';
 
298
                        break;
 
299
                case SCE_T3_D_STRING:
 
300
                        sc.SetState(SCE_T3_LIB_DIRECTIVE);
 
301
                        sc.Forward(2);
 
302
                        break;
 
303
                case SCE_T3_LIB_DIRECTIVE:
 
304
                        if (lineState&T3_SINGLE_QUOTE) {
 
305
                                initState = SCE_T3_S_STRING;
 
306
                                chQuote = '\'';
 
307
                        } else {
 
308
                                initState = SCE_T3_D_STRING;
 
309
                        }
 
310
                        break;
 
311
        }
 
312
        while (sc.More() && IsADirectiveChar(sc.ch)) {
 
313
                if (IsEOL(sc.ch, sc.chNext)) {
 
314
                        return;
 
315
                }
 
316
                sc.Forward();
 
317
        };
 
318
        if (sc.ch == '>' || !sc.More()) {
 
319
                sc.ForwardSetState(initState);
 
320
        } else if (sc.ch == chQuote) {
 
321
                sc.SetState(initState);
 
322
        } else {
 
323
                sc.ChangeState(initState);
 
324
                sc.Forward();
 
325
        }
 
326
}
 
327
 
 
328
static void ColouriseTADS3String(StyleContext &sc, int &lineState) {
 
329
        int chQuote = sc.ch;
 
330
        int endState = sc.state;
 
331
        switch (sc.state) {
 
332
                case SCE_T3_DEFAULT:
 
333
                case SCE_T3_X_DEFAULT:
 
334
                        if (chQuote == '"') {
 
335
                                if (sc.state == SCE_T3_DEFAULT) {
 
336
                                        sc.SetState(SCE_T3_D_STRING);
 
337
                                } else {
 
338
                                        sc.SetState(SCE_T3_X_STRING);
 
339
                                }
 
340
                                lineState &= ~T3_SINGLE_QUOTE;
 
341
                        } else {
 
342
                                sc.SetState(SCE_T3_S_STRING);
 
343
                                lineState |= T3_SINGLE_QUOTE;
 
344
                        }
 
345
                        sc.Forward();
 
346
                        break;
 
347
                case SCE_T3_S_STRING:
 
348
                        chQuote = '\'';
 
349
                        endState = lineState&T3_INT_EXPRESSION ?
 
350
                                SCE_T3_X_DEFAULT : SCE_T3_DEFAULT;
 
351
                        break;
 
352
                case SCE_T3_D_STRING:
 
353
                        chQuote = '"';
 
354
                        endState = SCE_T3_DEFAULT;
 
355
                        break;
 
356
                case SCE_T3_X_STRING:
 
357
                        chQuote = '"';
 
358
                        endState = SCE_T3_X_DEFAULT;
 
359
                        break;
 
360
        }
 
361
        while (sc.More()) {
 
362
                if (IsEOL(sc.ch, sc.chNext)) {
 
363
                        return;
 
364
                }
 
365
                if (sc.ch == chQuote) {
 
366
                        sc.ForwardSetState(endState);
 
367
                        return;
 
368
                }
 
369
                if (sc.state == SCE_T3_D_STRING && sc.Match('<', '<')) {
 
370
                        lineState |= T3_INT_EXPRESSION;
 
371
                        sc.SetState(SCE_T3_X_DEFAULT);
 
372
                        sc.Forward(2);
 
373
                        return;
 
374
                }
 
375
                if (sc.Match('\\', static_cast<char>(chQuote))) {
 
376
                        sc.Forward(2);
 
377
                } else if (sc.ch == '{') {
 
378
                        ColouriseTADS3MsgParam(sc, lineState);
 
379
                } else if (sc.Match('<', '.')) {
 
380
                        ColouriseTADS3LibDirective(sc, lineState);
 
381
                } else if (sc.ch == '<') {
 
382
                        ColouriseTADS3HTMLTag(sc, lineState);
 
383
                } else {
 
384
                        sc.Forward();
 
385
                }
 
386
        }
 
387
}
 
388
 
 
389
static void ColouriseTADS3Comment(StyleContext &sc, int endState) {
 
390
        sc.SetState(SCE_T3_BLOCK_COMMENT);
 
391
        while (sc.More()) {
 
392
                if (IsEOL(sc.ch, sc.chNext)) {
 
393
                        return;
 
394
                }
 
395
                if (sc.Match('*', '/')) {
 
396
                        sc.Forward(2);
 
397
                        sc.SetState(endState);
 
398
                        return;
 
399
                }
 
400
                sc.Forward();
 
401
        }
 
402
}
 
403
 
 
404
static void ColouriseToEndOfLine(StyleContext &sc, int initState, int endState) {
 
405
        sc.SetState(initState);
 
406
        while (sc.More()) {
 
407
                if (sc.ch == '\\') {
 
408
                        sc.Forward();
 
409
                        if (IsEOL(sc.ch, sc.chNext)) {
 
410
                                        return;
 
411
                        }
 
412
                }
 
413
                if (IsEOL(sc.ch, sc.chNext)) {
 
414
                        sc.SetState(endState);
 
415
                        return;
 
416
                }
 
417
                sc.Forward();
 
418
        }
 
419
}
 
420
 
 
421
static void ColouriseTADS3Number(StyleContext &sc) {
 
422
        int endState = sc.state;
 
423
        bool inHexNumber = false;
 
424
        bool seenE = false;
 
425
        bool seenDot = sc.ch == '.';
 
426
        sc.SetState(SCE_T3_NUMBER);
 
427
        if (sc.More()) {
 
428
                sc.Forward();
 
429
        }
 
430
        if (sc.chPrev == '0' && tolower(sc.ch) == 'x') {
 
431
                inHexNumber = true;
 
432
                sc.Forward();
 
433
        }
 
434
        while (sc.More()) {
 
435
                if (inHexNumber) {
 
436
                        if (!IsAHexDigit(sc.ch)) {
 
437
                                break;
 
438
                        }
 
439
                } else if (!isdigit(sc.ch)) {
 
440
                        if (!seenE && tolower(sc.ch) == 'e') {
 
441
                                seenE = true;
 
442
                                seenDot = true;
 
443
                                if (sc.chNext == '+' || sc.chNext == '-') {
 
444
                                        sc.Forward();
 
445
                                }
 
446
                        } else if (!seenDot && sc.ch == '.') {
 
447
                                seenDot = true;
 
448
                        } else {
 
449
                                break;
 
450
                        }
 
451
                }
 
452
                sc.Forward();
 
453
        }
 
454
        sc.SetState(endState);
 
455
}
 
456
 
 
457
static void ColouriseTADS3Doc(unsigned int startPos, int length, int initStyle,
 
458
                                                           WordList *keywordlists[], Accessor &styler) {
 
459
        int visibleChars = 0;
 
460
        int bracketLevel = 0;
 
461
        int lineState = 0;
 
462
        unsigned int endPos = startPos + length;
 
463
        int lineCurrent = styler.GetLine(startPos);
 
464
        if (lineCurrent > 0) {
 
465
                lineState = styler.GetLineState(lineCurrent-1);
 
466
        }
 
467
        StyleContext sc(startPos, length, initStyle, styler);
 
468
 
 
469
        while (sc.More()) {
 
470
 
 
471
                if (IsEOL(sc.ch, sc.chNext)) {
 
472
                        styler.SetLineState(lineCurrent, lineState);
 
473
                        lineCurrent++;
 
474
                        visibleChars = 0;
 
475
                        sc.Forward();
 
476
                        if (sc.ch == '\n') {
 
477
                                sc.Forward();
 
478
                        }
 
479
                }
 
480
 
 
481
                switch(sc.state) {
 
482
                        case SCE_T3_PREPROCESSOR:
 
483
                        case SCE_T3_LINE_COMMENT:
 
484
                                ColouriseToEndOfLine(sc, sc.state, lineState&T3_INT_EXPRESSION ?
 
485
                                        SCE_T3_X_DEFAULT : SCE_T3_DEFAULT);
 
486
                                break;
 
487
                        case SCE_T3_S_STRING:
 
488
                        case SCE_T3_D_STRING:
 
489
                        case SCE_T3_X_STRING:
 
490
                                ColouriseTADS3String(sc, lineState);
 
491
                                visibleChars++;
 
492
                                break;
 
493
                        case SCE_T3_MSG_PARAM:
 
494
                                ColouriseTADS3MsgParam(sc, lineState);
 
495
                                break;
 
496
                        case SCE_T3_LIB_DIRECTIVE:
 
497
                                ColouriseTADS3LibDirective(sc, lineState);
 
498
                                break;
 
499
                        case SCE_T3_HTML_DEFAULT:
 
500
                                ColouriseTADS3HTMLTag(sc, lineState);
 
501
                                break;
 
502
                        case SCE_T3_HTML_STRING:
 
503
                                ColouriseTADSHTMLString(sc, lineState);
 
504
                                break;
 
505
                        case SCE_T3_BLOCK_COMMENT:
 
506
                                ColouriseTADS3Comment(sc, lineState&T3_INT_EXPRESSION ?
 
507
                                        SCE_T3_X_DEFAULT : SCE_T3_DEFAULT);
 
508
                                break;
 
509
                        case SCE_T3_DEFAULT:
 
510
                        case SCE_T3_X_DEFAULT:
 
511
                                if (IsASpaceOrTab(sc.ch)) {
 
512
                                        sc.Forward();
 
513
                                } else if (sc.ch == '#' && visibleChars == 0) {
 
514
                                        ColouriseToEndOfLine(sc, SCE_T3_PREPROCESSOR, sc.state);
 
515
                                } else if (sc.Match('/', '*')) {
 
516
                                        ColouriseTADS3Comment(sc, sc.state);
 
517
                                        visibleChars++;
 
518
                                } else if (sc.Match('/', '/')) {
 
519
                                        ColouriseToEndOfLine(sc, SCE_T3_LINE_COMMENT, sc.state);
 
520
                                } else if (sc.ch == '"') {
 
521
                                        bracketLevel = 0;
 
522
                                        ColouriseTADS3String(sc, lineState);
 
523
                                        visibleChars++;
 
524
                                } else if (sc.ch == '\'') {
 
525
                                        ColouriseTADS3String(sc, lineState);
 
526
                                        visibleChars++;
 
527
                                } else if (sc.state == SCE_T3_X_DEFAULT && bracketLevel == 0
 
528
                                                   && sc.Match('>', '>')) {
 
529
                                        sc.Forward(2);
 
530
                                        sc.SetState(SCE_T3_D_STRING);
 
531
                                        lineState &= ~(T3_SINGLE_QUOTE|T3_INT_EXPRESSION);
 
532
                                } else if (IsATADS3Operator(sc.ch)) {
 
533
                                        if (sc.state == SCE_T3_X_DEFAULT) {
 
534
                                                if (sc.ch == '(') {
 
535
                                                        bracketLevel++;
 
536
                                                } else if (sc.ch == ')') {
 
537
                                                        bracketLevel--;
 
538
                                                }
 
539
                                        }
 
540
                                        ColouriseTADS3Operator(sc);
 
541
                                        visibleChars++;
 
542
                                } else if (IsANumberStart(sc)) {
 
543
                                        ColouriseTADS3Number(sc);
 
544
                                        visibleChars++;
 
545
                                } else if (IsAWordStart(sc.ch)) {
 
546
                                        ColouriseTADS3Keyword(sc, keywordlists, endPos);
 
547
                                        visibleChars++;
 
548
                                } else if (sc.Match("...")) {
 
549
                                        sc.SetState(SCE_T3_IDENTIFIER);
 
550
                                        sc.Forward(3);
 
551
                                        sc.SetState(SCE_T3_DEFAULT);
 
552
                                } else {
 
553
                                        sc.Forward();
 
554
                                        visibleChars++;
 
555
                                }
 
556
                                break;
 
557
                        default:
 
558
                                sc.SetState(SCE_T3_DEFAULT);
 
559
                                sc.Forward();
 
560
                }
 
561
        }
 
562
        sc.Complete();
 
563
}
 
564
 
 
565
/*
 
566
 TADS3 has two styles of top level block (TLB). Eg
 
567
 
 
568
 // default style
 
569
 silverKey : Key 'small silver key' 'small silver key'
 
570
        "A small key glints in the sunlight. "
 
571
 ;
 
572
 
 
573
 and
 
574
 
 
575
 silverKey : Key {
 
576
        'small silver key'
 
577
        'small silver key'
 
578
        "A small key glints in the sunlight. "
 
579
 }
 
580
 
 
581
 Some constructs mandate one or the other, but usually the author has may choose
 
582
 either.
 
583
 
 
584
 T3_SEENSTART is used to indicate that a braceless TLB has been (potentially)
 
585
 seen and is also used to match the closing ';' of the default style.
 
586
 
 
587
 T3_EXPECTINGIDENTIFIER and T3_EXPECTINGPUNCTUATION are used to keep track of
 
588
 what characters may be seen without incrementing the block level.  The general
 
589
 pattern is identifier <punc> identifier, acceptable punctuation characters
 
590
 are ':', ',', '(' and ')'.  No attempt is made to ensure that punctuation
 
591
 characters are syntactically correct, eg parentheses match. A ')' always
 
592
 signifies the start of a block.  We just need to check if it is followed by a
 
593
 '{', in which case we let the brace handling code handle the folding level.
 
594
 
 
595
 expectingIdentifier == false && expectingIdentifier == false
 
596
 Before the start of a TLB.
 
597
 
 
598
 expectingIdentifier == true && expectingIdentifier == true
 
599
 Currently in an identifier.  Will accept identifier or punctuation.
 
600
 
 
601
 expectingIdentifier == true && expectingIdentifier == false
 
602
 Just seen a punctuation character & now waiting for an identifier to start.
 
603
 
 
604
 expectingIdentifier == false && expectingIdentifier == truee
 
605
 We were in an identifier and have seen space.  Now waiting to see a punctuation
 
606
 character
 
607
 
 
608
 Space, comments & preprocessor directives are always acceptable and are
 
609
 equivalent.
 
610
*/
 
611
 
 
612
static const int T3_SEENSTART = 1 << 12;
 
613
static const int T3_EXPECTINGIDENTIFIER = 1 << 13;
 
614
static const int T3_EXPECTINGPUNCTUATION = 1 << 14;
 
615
 
 
616
static inline bool IsStringTransition(int s1, int s2) {
 
617
        return s1 != s2
 
618
                && (s1 == SCE_T3_S_STRING || s1 == SCE_T3_X_STRING
 
619
                        || s1 == SCE_T3_D_STRING && s2 != SCE_T3_X_DEFAULT)
 
620
                && s2 != SCE_T3_LIB_DIRECTIVE
 
621
                && s2 != SCE_T3_MSG_PARAM
 
622
                && s2 != SCE_T3_HTML_TAG
 
623
                && s2 != SCE_T3_HTML_STRING;
 
624
}
 
625
 
 
626
static inline bool IsATADS3Punctuation(const int ch) {
 
627
        return ch == ':' || ch == ',' || ch == '(' || ch == ')';
 
628
}
 
629
 
 
630
static inline bool IsAnIdentifier(const int style) {
 
631
        return style == SCE_T3_IDENTIFIER
 
632
                || style == SCE_T3_USER1
 
633
                || style == SCE_T3_USER2
 
634
                || style == SCE_T3_USER3;
 
635
}
 
636
 
 
637
static inline bool IsSpaceEquivalent(const int ch, const int style) {
 
638
        return isspace(ch)
 
639
                || style == SCE_T3_BLOCK_COMMENT
 
640
                || style == SCE_T3_LINE_COMMENT
 
641
                || style == SCE_T3_PREPROCESSOR;
 
642
}
 
643
 
 
644
static char peekAhead(unsigned int startPos, unsigned int endPos,
 
645
                                          Accessor &styler) {
 
646
        for (unsigned int i = startPos; i < endPos; i++) {
 
647
                int style = styler.StyleAt(i);
 
648
                char ch = styler[i];
 
649
                if (!IsSpaceEquivalent(ch, style)) {
 
650
                        if (IsAnIdentifier(style)) {
 
651
                                return 'a';
 
652
                        }
 
653
                        if (IsATADS3Punctuation(ch)) {
 
654
                                return ':';
 
655
                        }
 
656
                        if (ch == '{') {
 
657
                                return '{';
 
658
                        }
 
659
                        return '*';
 
660
                }
 
661
        }
 
662
        return ' ';
 
663
}
 
664
 
 
665
static void FoldTADS3Doc(unsigned int startPos, int length, int initStyle,
 
666
                            WordList *[], Accessor &styler) {
 
667
        unsigned int endPos = startPos + length;
 
668
        int lineCurrent = styler.GetLine(startPos);
 
669
        int levelCurrent = SC_FOLDLEVELBASE;
 
670
        if (lineCurrent > 0)
 
671
                levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
 
672
        int seenStart = levelCurrent & T3_SEENSTART;
 
673
        int expectingIdentifier = levelCurrent & T3_EXPECTINGIDENTIFIER;
 
674
        int expectingPunctuation = levelCurrent & T3_EXPECTINGPUNCTUATION;
 
675
        levelCurrent &= SC_FOLDLEVELNUMBERMASK;
 
676
        int levelMinCurrent = levelCurrent;
 
677
        int levelNext = levelCurrent;
 
678
        char chNext = styler[startPos];
 
679
        int styleNext = styler.StyleAt(startPos);
 
680
        int style = initStyle;
 
681
        char ch = chNext;
 
682
        int stylePrev = style;
 
683
        bool redo = false;
 
684
        for (unsigned int i = startPos; i < endPos; i++) {
 
685
                if (redo) {
 
686
                        redo = false;
 
687
                        i--;
 
688
                } else {
 
689
                        ch = chNext;
 
690
                        chNext = styler.SafeGetCharAt(i + 1);
 
691
                        stylePrev = style;
 
692
                        style = styleNext;
 
693
                        styleNext = styler.StyleAt(i + 1);
 
694
                }
 
695
                bool atEOL = IsEOL(ch, chNext);
 
696
 
 
697
                if (levelNext == SC_FOLDLEVELBASE) {
 
698
                        if (IsSpaceEquivalent(ch, style)) {
 
699
                                if (expectingPunctuation) {
 
700
                                        expectingIdentifier = 0;
 
701
                                }
 
702
                                if (style == SCE_T3_BLOCK_COMMENT) {
 
703
                                        levelNext++;
 
704
                                }
 
705
                        } else if (ch == '{') {
 
706
                                levelNext++;
 
707
                                seenStart = 0;
 
708
                        } else if (ch == '\'' || ch == '"' || ch == '[') {
 
709
                                levelNext++;
 
710
                                if (seenStart) {
 
711
                                        redo = true;
 
712
                                }
 
713
                        } else if (ch == ';') {
 
714
                                seenStart = 0;
 
715
                                expectingIdentifier = 0;
 
716
                                expectingPunctuation = 0;
 
717
                        } else if (expectingIdentifier && expectingPunctuation) {
 
718
                                if (IsATADS3Punctuation(ch)) {
 
719
                                        if (ch == ')' && peekAhead(i+1, endPos, styler) != '{') {
 
720
                                                levelNext++;
 
721
                                        } else {
 
722
                                                expectingPunctuation = 0;
 
723
                                        }
 
724
                                } else if (!IsAnIdentifier(style)) {
 
725
                                        levelNext++;
 
726
                                }
 
727
                        } else if (expectingIdentifier && !expectingPunctuation) {
 
728
                                if (!IsAnIdentifier(style)) {
 
729
                                        levelNext++;
 
730
                                } else {
 
731
                                        expectingPunctuation = T3_EXPECTINGPUNCTUATION;
 
732
                                }
 
733
                        } else if (!expectingIdentifier && expectingPunctuation) {
 
734
                                if (!IsATADS3Punctuation(ch)) {
 
735
                                        levelNext++;
 
736
                                } else {
 
737
                                        if (ch == ')' && peekAhead(i+1, endPos, styler) != '{') {
 
738
                                                levelNext++;
 
739
                                        } else {
 
740
                                                expectingIdentifier = T3_EXPECTINGIDENTIFIER;
 
741
                                                expectingPunctuation = 0;
 
742
                                        }
 
743
                                }
 
744
                        } else if (!expectingIdentifier && !expectingPunctuation) {
 
745
                                if (IsAnIdentifier(style)) {
 
746
                                        seenStart = T3_SEENSTART;
 
747
                                        expectingIdentifier = T3_EXPECTINGIDENTIFIER;
 
748
                                        expectingPunctuation = T3_EXPECTINGPUNCTUATION;
 
749
                                }
 
750
                        }
 
751
 
 
752
                        if (levelNext != SC_FOLDLEVELBASE && style != SCE_T3_BLOCK_COMMENT) {
 
753
                                expectingIdentifier = 0;
 
754
                                expectingPunctuation = 0;
 
755
                        }
 
756
 
 
757
                } else if (levelNext == SC_FOLDLEVELBASE+1 && seenStart
 
758
                                   && ch == ';' && style == SCE_T3_OPERATOR ) {
 
759
                        levelNext--;
 
760
                        seenStart = 0;
 
761
                } else if (style == SCE_T3_BLOCK_COMMENT) {
 
762
                        if (stylePrev != SCE_T3_BLOCK_COMMENT) {
 
763
                                levelNext++;
 
764
                        } else if (styleNext != SCE_T3_BLOCK_COMMENT && !atEOL) {
 
765
                                // Comments don't end at end of line and the next character may be unstyled.
 
766
                                levelNext--;
 
767
                        }
 
768
                } else if (ch == '\'' || ch == '"') {
 
769
                        if (IsStringTransition(style, stylePrev)) {
 
770
                                if (levelMinCurrent > levelNext) {
 
771
                                        levelMinCurrent = levelNext;
 
772
                                }
 
773
                                levelNext++;
 
774
                        } else if (IsStringTransition(style, styleNext)) {
 
775
                                levelNext--;
 
776
                        }
 
777
                } else if (style == SCE_T3_OPERATOR) {
 
778
                        if (ch == '{' || ch == '[') {
 
779
                                // Measure the minimum before a '{' to allow
 
780
                                // folding on "} else {"
 
781
                                if (levelMinCurrent > levelNext) {
 
782
                                        levelMinCurrent = levelNext;
 
783
                                }
 
784
                                levelNext++;
 
785
                        } else if (ch == '}' || ch == ']') {
 
786
                                levelNext--;
 
787
                        }
 
788
                }
 
789
 
 
790
                if (atEOL) {
 
791
                        if (seenStart && levelNext == SC_FOLDLEVELBASE) {
 
792
                                switch (peekAhead(i+1, endPos, styler)) {
 
793
                                        case ' ':
 
794
                                        case '{':
 
795
                                                break;
 
796
                                        case '*':
 
797
                                                levelNext++;
 
798
                                                break;
 
799
                                        case 'a':
 
800
                                                if (expectingPunctuation) {
 
801
                                                        levelNext++;
 
802
                                                }
 
803
                                                break;
 
804
                                        case ':':
 
805
                                                if (expectingIdentifier) {
 
806
                                                        levelNext++;
 
807
                                                }
 
808
                                                break;
 
809
                                }
 
810
                                if (levelNext != SC_FOLDLEVELBASE) {
 
811
                                        expectingIdentifier = 0;
 
812
                                        expectingPunctuation = 0;
 
813
                                }
 
814
                        }
 
815
                        int lev = levelMinCurrent | (levelNext | expectingIdentifier
 
816
                                | expectingPunctuation | seenStart) << 16;
 
817
                        if (levelMinCurrent < levelNext)
 
818
                                lev |= SC_FOLDLEVELHEADERFLAG;
 
819
                        if (lev != styler.LevelAt(lineCurrent)) {
 
820
                                styler.SetLevel(lineCurrent, lev);
 
821
                        }
 
822
                        lineCurrent++;
 
823
                        levelCurrent = levelNext;
 
824
                        levelMinCurrent = levelCurrent;
 
825
                }
 
826
        }
 
827
}
 
828
 
 
829
static const char * const tads3WordList[] = {
 
830
        "TADS3 Keywords",
 
831
        "User defined 1",
 
832
        "User defined 2",
 
833
        "User defined 3",
 
834
        0
 
835
};
 
836
 
 
837
LexerModule lmTADS3(SCLEX_TADS3, ColouriseTADS3Doc, "tads3", FoldTADS3Doc, tads3WordList);