]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/lexers/LexTCL.cxx
1 // Scintilla source code edit control
3 ** Lexer for TCL language.
5 // Copyright 1998-2001 by Andre Arpin <arpin@kingston.net>
6 // The License.txt file describes the conditions under which this software may be distributed.
16 #include "Scintilla.h"
20 #include "LexAccessor.h"
22 #include "StyleContext.h"
23 #include "CharacterSet.h"
24 #include "LexerModule.h"
27 using namespace Scintilla
;
30 // Extended to accept accented characters
31 static inline bool IsAWordChar(int ch
) {
33 (isalnum(ch
) || ch
== '_' || ch
==':' || ch
=='.'); // : name space separator
36 static inline bool IsAWordStart(int ch
) {
37 return ch
>= 0x80 || (ch
==':' || isalpha(ch
) || ch
== '_');
40 static inline bool IsANumberChar(int ch
) {
41 // Not exactly following number definition (several dots are seen as OK, etc.)
42 // but probably enough in most cases.
44 (IsADigit(ch
, 0x10) || toupper(ch
) == 'E' ||
45 ch
== '.' || ch
== '-' || ch
== '+');
48 static void ColouriseTCLDoc(unsigned int startPos
, int length
, int , WordList
*keywordlists
[], Accessor
&styler
) {
49 #define isComment(s) (s==SCE_TCL_COMMENT || s==SCE_TCL_COMMENTLINE || s==SCE_TCL_COMMENT_BOX || s==SCE_TCL_BLOCK_COMMENT)
50 bool foldComment
= styler
.GetPropertyInt("fold.comment") != 0;
51 bool commentLevel
= false;
52 bool subBrace
= false; // substitution begin with a brace ${.....}
53 enum tLineState
{LS_DEFAULT
, LS_OPEN_COMMENT
, LS_OPEN_DOUBLE_QUOTE
, LS_COMMENT_BOX
, LS_MASK_STATE
= 0xf,
54 LS_COMMAND_EXPECTED
= 16, LS_BRACE_ONLY
= 32 } lineState
= LS_DEFAULT
;
55 bool prevSlash
= false;
60 int currentLine
= styler
.GetLine(startPos
);
63 length
+= startPos
- styler
.LineStart(currentLine
);
64 // make sure lines overlap
65 startPos
= styler
.LineStart(currentLine
);
67 WordList
&keywords
= *keywordlists
[0];
68 WordList
&keywords2
= *keywordlists
[1];
69 WordList
&keywords3
= *keywordlists
[2];
70 WordList
&keywords4
= *keywordlists
[3];
71 WordList
&keywords5
= *keywordlists
[4];
72 WordList
&keywords6
= *keywordlists
[5];
73 WordList
&keywords7
= *keywordlists
[6];
74 WordList
&keywords8
= *keywordlists
[7];
75 WordList
&keywords9
= *keywordlists
[8];
77 if (currentLine
> 0) {
78 int ls
= styler
.GetLineState(currentLine
- 1);
79 lineState
= tLineState(ls
& LS_MASK_STATE
);
80 expected
= LS_COMMAND_EXPECTED
== tLineState(ls
& LS_COMMAND_EXPECTED
);
81 subBrace
= LS_BRACE_ONLY
== tLineState(ls
& LS_BRACE_ONLY
);
82 currentLevel
= styler
.LevelAt(currentLine
- 1) >> 17;
83 commentLevel
= (styler
.LevelAt(currentLine
- 1) >> 16) & 1;
85 styler
.SetLevel(0, SC_FOLDLEVELBASE
| SC_FOLDLEVELHEADERFLAG
);
86 bool visibleChars
= false;
88 int previousLevel
= currentLevel
;
89 StyleContext
sc(startPos
, length
, SCE_TCL_DEFAULT
, styler
);
90 for (; ; sc
.Forward()) {
92 if (sc
.ch
=='\r' && sc
.chNext
== '\n') // only ignore \r on PC process on the mac
94 bool atEnd
= !sc
.More(); // make sure we coloured the last word
95 if (lineState
!= LS_DEFAULT
) {
96 sc
.SetState(SCE_TCL_DEFAULT
);
97 if (lineState
== LS_OPEN_COMMENT
)
98 sc
.SetState(SCE_TCL_COMMENTLINE
);
99 else if (lineState
== LS_OPEN_DOUBLE_QUOTE
)
100 sc
.SetState(SCE_TCL_IN_QUOTE
);
101 else if (lineState
== LS_COMMENT_BOX
&& (sc
.ch
== '#' || (sc
.ch
== ' ' && sc
.chNext
=='#')))
102 sc
.SetState(SCE_TCL_COMMENT_BOX
);
103 lineState
= LS_DEFAULT
;
105 if (subBrace
) { // ${ overrides every thing even \ except }
108 sc
.SetState(SCE_TCL_OPERATOR
);
109 sc
.ForwardSetState(SCE_TCL_DEFAULT
);
113 sc
.SetState(SCE_TCL_SUB_BRACE
);
116 } else if (sc
.state
== SCE_TCL_DEFAULT
|| sc
.state
==SCE_TCL_OPERATOR
) {
117 expected
&= isspacechar(static_cast<unsigned char>(sc
.ch
)) || IsAWordStart(sc
.ch
) || sc
.ch
=='#';
118 } else if (sc
.state
== SCE_TCL_SUBSTITUTION
) {
122 sc
.SetState(SCE_TCL_OPERATOR
);
123 sc
.ForwardSetState(SCE_TCL_SUBSTITUTION
);
126 sc
.SetState(SCE_TCL_OPERATOR
);
132 sc
.SetState(SCE_TCL_OPERATOR
);
134 sc
.ForwardSetState(SCE_TCL_SUBSTITUTION
);
137 // maybe spaces should be allowed ???
138 if (!IsAWordChar(sc
.ch
)) { // probably the code is wrong
139 sc
.SetState(SCE_TCL_DEFAULT
);
144 } else if (isComment(sc
.state
)) {
145 } else if (!IsAWordChar(sc
.ch
)) {
146 if ((sc
.state
== SCE_TCL_IDENTIFIER
&& expected
) || sc
.state
== SCE_TCL_MODIFIER
) {
149 sc
.GetCurrent(w
, sizeof(w
));
150 if (w
[strlen(w
)-1]=='\r')
152 while(*s
== ':') // ignore leading : like in ::set a 10
154 bool quote
= sc
.state
== SCE_TCL_IN_QUOTE
;
155 if (commentLevel
|| expected
) {
156 if (keywords
.InList(s
)) {
157 sc
.ChangeState(quote
? SCE_TCL_WORD_IN_QUOTE
: SCE_TCL_WORD
);
158 } else if (keywords2
.InList(s
)) {
159 sc
.ChangeState(quote
? SCE_TCL_WORD_IN_QUOTE
: SCE_TCL_WORD2
);
160 } else if (keywords3
.InList(s
)) {
161 sc
.ChangeState(quote
? SCE_TCL_WORD_IN_QUOTE
: SCE_TCL_WORD3
);
162 } else if (keywords4
.InList(s
)) {
163 sc
.ChangeState(quote
? SCE_TCL_WORD_IN_QUOTE
: SCE_TCL_WORD4
);
164 } else if (sc
.GetRelative(-static_cast<int>(strlen(s
))-1) == '{' &&
165 keywords5
.InList(s
) && sc
.ch
== '}') { // {keyword} exactly no spaces
166 sc
.ChangeState(SCE_TCL_EXPAND
);
168 if (keywords6
.InList(s
)) {
169 sc
.ChangeState(SCE_TCL_WORD5
);
170 } else if (keywords7
.InList(s
)) {
171 sc
.ChangeState(SCE_TCL_WORD6
);
172 } else if (keywords8
.InList(s
)) {
173 sc
.ChangeState(SCE_TCL_WORD7
);
174 } else if (keywords9
.InList(s
)) {
175 sc
.ChangeState(SCE_TCL_WORD8
);
179 sc
.SetState(quote
? SCE_TCL_IN_QUOTE
: SCE_TCL_DEFAULT
);
180 } else if (sc
.state
== SCE_TCL_MODIFIER
|| sc
.state
== SCE_TCL_IDENTIFIER
) {
181 sc
.SetState(SCE_TCL_DEFAULT
);
187 lineState
= LS_DEFAULT
;
188 currentLine
= styler
.GetLine(sc
.currentPos
);
189 if (foldComment
&& sc
.state
!=SCE_TCL_COMMENT
&& isComment(sc
.state
)) {
190 if (currentLevel
== 0) {
195 if (visibleChars
&& commentLevel
) {
198 commentLevel
= false;
203 flag
= SC_FOLDLEVELWHITEFLAG
;
204 if (currentLevel
> previousLevel
)
205 flag
= SC_FOLDLEVELHEADERFLAG
;
206 styler
.SetLevel(currentLine
, flag
+ previousLevel
+ SC_FOLDLEVELBASE
+ (currentLevel
<< 17) + (commentLevel
<< 16));
208 // Update the line state, so it can be seen by next line
209 if (sc
.state
== SCE_TCL_IN_QUOTE
)
210 lineState
= LS_OPEN_DOUBLE_QUOTE
;
213 if (isComment(sc
.state
))
214 lineState
= LS_OPEN_COMMENT
;
215 } else if (sc
.state
== SCE_TCL_COMMENT_BOX
)
216 lineState
= LS_COMMENT_BOX
;
218 styler
.SetLineState(currentLine
,
219 (subBrace
? LS_BRACE_ONLY
: 0) |
220 (expected
? LS_COMMAND_EXPECTED
: 0) | lineState
);
221 if (lineState
== LS_COMMENT_BOX
)
222 sc
.ForwardSetState(SCE_TCL_COMMENT_BOX
);
223 else if (lineState
== LS_OPEN_DOUBLE_QUOTE
)
224 sc
.ForwardSetState(SCE_TCL_IN_QUOTE
);
226 sc
.ForwardSetState(SCE_TCL_DEFAULT
);
228 previousLevel
= currentLevel
;
234 if (sc
.ch
== '#' && IsANumberChar(sc
.chNext
))
235 sc
.ForwardSetState(SCE_TCL_NUMBER
);
238 prevSlash
= sc
.ch
== '\\';
239 if (isComment(sc
.state
))
241 if (sc
.atLineStart
) {
242 visibleChars
= false;
243 if (sc
.state
!=SCE_TCL_IN_QUOTE
&& !isComment(sc
.state
))
245 sc
.SetState(SCE_TCL_DEFAULT
);
246 expected
= IsAWordStart(sc
.ch
)|| isspacechar(static_cast<unsigned char>(sc
.ch
));
252 if (!IsANumberChar(sc
.ch
))
253 sc
.SetState(SCE_TCL_DEFAULT
);
255 case SCE_TCL_IN_QUOTE
:
257 sc
.ForwardSetState(SCE_TCL_DEFAULT
);
258 visibleChars
= true; // necessary if a " is the first and only character on a line
260 } else if (sc
.ch
== '[' || sc
.ch
== ']' || sc
.ch
== '$') {
261 sc
.SetState(SCE_TCL_OPERATOR
);
262 expected
= sc
.ch
== '[';
263 sc
.ForwardSetState(SCE_TCL_IN_QUOTE
);
267 case SCE_TCL_OPERATOR
:
268 sc
.SetState(SCE_TCL_DEFAULT
);
274 if (sc
.state
!= SCE_TCL_IN_QUOTE
&& expected
)
275 sc
.SetState(SCE_TCL_COMMENT
);
277 sc
.SetState(SCE_TCL_COMMENTLINE
);
278 if (sc
.chNext
== '~')
279 sc
.SetState(SCE_TCL_BLOCK_COMMENT
);
280 if (sc
.atLineStart
&& (sc
.chNext
== '#' || sc
.chNext
== '-'))
281 sc
.SetState(SCE_TCL_COMMENT_BOX
);
285 if (!isspacechar(static_cast<unsigned char>(sc
.ch
))) {
294 // Determine if a new state should be entered.
295 if (sc
.state
== SCE_TCL_DEFAULT
) {
296 if (IsAWordStart(sc
.ch
)) {
297 sc
.SetState(SCE_TCL_IDENTIFIER
);
298 } else if (IsADigit(sc
.ch
) && !IsAWordChar(sc
.chPrev
)) {
299 sc
.SetState(SCE_TCL_NUMBER
);
303 sc
.SetState(SCE_TCL_IN_QUOTE
);
306 sc
.SetState(SCE_TCL_OPERATOR
);
311 sc
.SetState(SCE_TCL_OPERATOR
);
320 sc
.SetState(SCE_TCL_OPERATOR
);
327 if (sc
.chNext
!= '{') {
328 sc
.SetState(SCE_TCL_SUBSTITUTION
);
331 sc
.SetState(SCE_TCL_OPERATOR
); // $
333 sc
.ForwardSetState(SCE_TCL_SUB_BRACE
);
338 if ((isspacechar(static_cast<unsigned char>(sc
.chPrev
))||
339 isoperator(static_cast<char>(sc
.chPrev
))) && IsADigit(sc
.chNext
,0x10))
340 sc
.SetState(SCE_TCL_NUMBER
);
343 sc
.SetState(IsADigit(sc
.chNext
)? SCE_TCL_NUMBER
: SCE_TCL_MODIFIER
);
346 if (isoperator(static_cast<char>(sc
.ch
))) {
347 sc
.SetState(SCE_TCL_OPERATOR
);
356 static const char * const tclWordListDesc
[] = {
369 // this code supports folding in the colourizer
370 LexerModule
lmTCL(SCLEX_TCL
, ColouriseTCLDoc
, "tcl", 0, tclWordListDesc
);