]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/stc/scintilla/src/LexTADS3.cxx
Updated to Scintilla 1.67
[wxWidgets.git] / contrib / src / stc / scintilla / src / LexTADS3.cxx
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);