]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/lexers/LexLua.cxx
1 // Scintilla source code edit control
3 ** Lexer for Lua language.
5 ** Written by Paul Winwood.
6 ** Folder by Alexey Yutkin.
7 ** Modified by Marcos E. Wurzius & Philippe Lhoste
18 #include "Scintilla.h"
22 #include "LexAccessor.h"
24 #include "StyleContext.h"
25 #include "CharacterSet.h"
26 #include "LexerModule.h"
29 using namespace Scintilla
;
32 // Test for [=[ ... ]=] delimiters, returns 0 if it's only a [ or ],
33 // return 1 for [[ or ]], returns >=2 for [=[ or ]=] and so on.
34 // The maximum number of '=' characters allowed is 254.
35 static int LongDelimCheck(StyleContext
&sc
) {
37 while (sc
.GetRelative(sep
) == '=' && sep
< 0xFF)
39 if (sc
.GetRelative(sep
) == sc
.ch
)
44 static void ColouriseLuaDoc(
45 unsigned int startPos
,
48 WordList
*keywordlists
[],
51 WordList
&keywords
= *keywordlists
[0];
52 WordList
&keywords2
= *keywordlists
[1];
53 WordList
&keywords3
= *keywordlists
[2];
54 WordList
&keywords4
= *keywordlists
[3];
55 WordList
&keywords5
= *keywordlists
[4];
56 WordList
&keywords6
= *keywordlists
[5];
57 WordList
&keywords7
= *keywordlists
[6];
58 WordList
&keywords8
= *keywordlists
[7];
60 // Accepts accented characters
61 CharacterSet
setWordStart(CharacterSet::setAlpha
, "_", 0x80, true);
62 CharacterSet
setWord(CharacterSet::setAlphaNum
, "_", 0x80, true);
63 // Not exactly following number definition (several dots are seen as OK, etc.)
64 // but probably enough in most cases. [pP] is for hex floats.
65 CharacterSet
setNumber(CharacterSet::setDigits
, ".-+abcdefpABCDEFP");
66 CharacterSet
setExponent(CharacterSet::setNone
, "eEpP");
67 CharacterSet
setLuaOperator(CharacterSet::setNone
, "*/-+()={}~[];<>,.^%:#");
68 CharacterSet
setEscapeSkip(CharacterSet::setNone
, "\"'\\");
70 int currentLine
= styler
.GetLine(startPos
);
71 // Initialize long string [[ ... ]] or block comment --[[ ... ]] nesting level,
72 // if we are inside such a string. Block comment was introduced in Lua 5.0,
73 // blocks with separators [=[ ... ]=] in Lua 5.1.
74 // Continuation of a string (\z whitespace escaping) is controlled by stringWs.
78 if (initStyle
== SCE_LUA_LITERALSTRING
|| initStyle
== SCE_LUA_COMMENT
||
79 initStyle
== SCE_LUA_STRING
|| initStyle
== SCE_LUA_CHARACTER
) {
80 int lineState
= styler
.GetLineState(currentLine
- 1);
81 nestLevel
= lineState
>> 9;
82 sepCount
= lineState
& 0xFF;
83 stringWs
= lineState
& 0x100;
86 // Do not leak onto next line
87 if (initStyle
== SCE_LUA_STRINGEOL
|| initStyle
== SCE_LUA_COMMENTLINE
|| initStyle
== SCE_LUA_PREPROCESSOR
) {
88 initStyle
= SCE_LUA_DEFAULT
;
91 StyleContext
sc(startPos
, length
, initStyle
, styler
);
92 if (startPos
== 0 && sc
.ch
== '#') {
93 // shbang line: # is a comment only if first char of the script
94 sc
.SetState(SCE_LUA_COMMENTLINE
);
96 for (; sc
.More(); sc
.Forward()) {
98 // Update the line state, so it can be seen by next line
99 currentLine
= styler
.GetLine(sc
.currentPos
);
101 case SCE_LUA_LITERALSTRING
:
102 case SCE_LUA_COMMENT
:
104 case SCE_LUA_CHARACTER
:
105 // Inside a literal string, block comment or string, we set the line state
106 styler
.SetLineState(currentLine
, (nestLevel
<< 9) | stringWs
| sepCount
);
109 // Reset the line state
110 styler
.SetLineState(currentLine
, 0);
114 if (sc
.atLineStart
&& (sc
.state
== SCE_LUA_STRING
)) {
115 // Prevent SCE_LUA_STRINGEOL from leaking back to previous line
116 sc
.SetState(SCE_LUA_STRING
);
119 // Handle string line continuation
120 if ((sc
.state
== SCE_LUA_STRING
|| sc
.state
== SCE_LUA_CHARACTER
) &&
122 if (sc
.chNext
== '\n' || sc
.chNext
== '\r') {
124 if (sc
.ch
== '\r' && sc
.chNext
== '\n') {
131 // Determine if the current state should terminate.
132 if (sc
.state
== SCE_LUA_OPERATOR
) {
133 if (sc
.ch
== ':' && sc
.chPrev
== ':') { // :: <label> :: forward scan
135 int ln
= 0, maxln
= startPos
+ length
- sc
.currentPos
;
137 while (ln
< maxln
) { // determine line extent
138 c
= sc
.GetRelative(ln
);
139 if (c
== '\r' || c
== '\n')
144 while (ln
< maxln
) { // skip over spaces/tabs
145 if (!IsASpaceOrTab(sc
.GetRelative(ln
)))
150 if (setWordStart
.Contains(sc
.GetRelative(ln
))) {
153 while (ln
< maxln
) { // get potential label
154 c
= sc
.GetRelative(ln
);
155 if (!setWord
.Contains(c
))
161 s
[i
] = '\0'; int lbl
= ln
;
162 if (!keywords
.InList(s
)) {
163 while (ln
< maxln
) { // skip over spaces/tabs
164 if (!IsASpaceOrTab(sc
.GetRelative(ln
)))
169 if (sc
.GetRelative(ln
) == ':' && sc
.GetRelative(ln
+ 1) == ':') {
170 // final :: found, complete valid label construct
171 sc
.ChangeState(SCE_LUA_LABEL
);
173 sc
.SetState(SCE_LUA_DEFAULT
);
176 sc
.SetState(SCE_LUA_LABEL
);
177 sc
.Forward(lbl
- ws1
);
179 sc
.SetState(SCE_LUA_DEFAULT
);
182 sc
.SetState(SCE_LUA_LABEL
);
188 sc
.SetState(SCE_LUA_DEFAULT
);
189 } else if (sc
.state
== SCE_LUA_NUMBER
) {
190 // We stop the number definition on non-numerical non-dot non-eEpP non-sign non-hexdigit char
191 if (!setNumber
.Contains(sc
.ch
)) {
192 sc
.SetState(SCE_LUA_DEFAULT
);
193 } else if (sc
.ch
== '-' || sc
.ch
== '+') {
194 if (!setExponent
.Contains(sc
.chPrev
))
195 sc
.SetState(SCE_LUA_DEFAULT
);
197 } else if (sc
.state
== SCE_LUA_IDENTIFIER
) {
198 if (!(setWord
.Contains(sc
.ch
) || sc
.ch
== '.') || sc
.Match('.', '.')) {
200 sc
.GetCurrent(s
, sizeof(s
));
201 if (keywords
.InList(s
)) {
202 sc
.ChangeState(SCE_LUA_WORD
);
203 if (strcmp(s
, "goto") == 0) { // goto <label> forward scan
204 sc
.SetState(SCE_LUA_DEFAULT
);
205 while (IsASpaceOrTab(sc
.ch
) && !sc
.atLineEnd
)
207 if (setWordStart
.Contains(sc
.ch
)) {
208 sc
.SetState(SCE_LUA_LABEL
);
210 while (setWord
.Contains(sc
.ch
))
212 sc
.GetCurrent(s
, sizeof(s
));
213 if (keywords
.InList(s
))
214 sc
.ChangeState(SCE_LUA_WORD
);
216 sc
.SetState(SCE_LUA_DEFAULT
);
218 } else if (keywords2
.InList(s
)) {
219 sc
.ChangeState(SCE_LUA_WORD2
);
220 } else if (keywords3
.InList(s
)) {
221 sc
.ChangeState(SCE_LUA_WORD3
);
222 } else if (keywords4
.InList(s
)) {
223 sc
.ChangeState(SCE_LUA_WORD4
);
224 } else if (keywords5
.InList(s
)) {
225 sc
.ChangeState(SCE_LUA_WORD5
);
226 } else if (keywords6
.InList(s
)) {
227 sc
.ChangeState(SCE_LUA_WORD6
);
228 } else if (keywords7
.InList(s
)) {
229 sc
.ChangeState(SCE_LUA_WORD7
);
230 } else if (keywords8
.InList(s
)) {
231 sc
.ChangeState(SCE_LUA_WORD8
);
233 sc
.SetState(SCE_LUA_DEFAULT
);
235 } else if (sc
.state
== SCE_LUA_COMMENTLINE
|| sc
.state
== SCE_LUA_PREPROCESSOR
) {
237 sc
.ForwardSetState(SCE_LUA_DEFAULT
);
239 } else if (sc
.state
== SCE_LUA_STRING
) {
241 if (!IsASpace(sc
.ch
))
245 if (setEscapeSkip
.Contains(sc
.chNext
)) {
247 } else if (sc
.chNext
== 'z') {
251 } else if (sc
.ch
== '\"') {
252 sc
.ForwardSetState(SCE_LUA_DEFAULT
);
253 } else if (stringWs
== 0 && sc
.atLineEnd
) {
254 sc
.ChangeState(SCE_LUA_STRINGEOL
);
255 sc
.ForwardSetState(SCE_LUA_DEFAULT
);
257 } else if (sc
.state
== SCE_LUA_CHARACTER
) {
259 if (!IsASpace(sc
.ch
))
263 if (setEscapeSkip
.Contains(sc
.chNext
)) {
265 } else if (sc
.chNext
== 'z') {
269 } else if (sc
.ch
== '\'') {
270 sc
.ForwardSetState(SCE_LUA_DEFAULT
);
271 } else if (stringWs
== 0 && sc
.atLineEnd
) {
272 sc
.ChangeState(SCE_LUA_STRINGEOL
);
273 sc
.ForwardSetState(SCE_LUA_DEFAULT
);
275 } else if (sc
.state
== SCE_LUA_LITERALSTRING
|| sc
.state
== SCE_LUA_COMMENT
) {
277 int sep
= LongDelimCheck(sc
);
278 if (sep
== 1 && sepCount
== 1) { // [[-only allowed to nest
282 } else if (sc
.ch
== ']') {
283 int sep
= LongDelimCheck(sc
);
284 if (sep
== 1 && sepCount
== 1) { // un-nest with ]]-only
287 if (nestLevel
== 0) {
288 sc
.ForwardSetState(SCE_LUA_DEFAULT
);
290 } else if (sep
> 1 && sep
== sepCount
) { // ]=]-style delim
292 sc
.ForwardSetState(SCE_LUA_DEFAULT
);
297 // Determine if a new state should be entered.
298 if (sc
.state
== SCE_LUA_DEFAULT
) {
299 if (IsADigit(sc
.ch
) || (sc
.ch
== '.' && IsADigit(sc
.chNext
))) {
300 sc
.SetState(SCE_LUA_NUMBER
);
301 if (sc
.ch
== '0' && toupper(sc
.chNext
) == 'X') {
304 } else if (setWordStart
.Contains(sc
.ch
)) {
305 sc
.SetState(SCE_LUA_IDENTIFIER
);
306 } else if (sc
.ch
== '\"') {
307 sc
.SetState(SCE_LUA_STRING
);
309 } else if (sc
.ch
== '\'') {
310 sc
.SetState(SCE_LUA_CHARACTER
);
312 } else if (sc
.ch
== '[') {
313 sepCount
= LongDelimCheck(sc
);
315 sc
.SetState(SCE_LUA_OPERATOR
);
318 sc
.SetState(SCE_LUA_LITERALSTRING
);
319 sc
.Forward(sepCount
);
321 } else if (sc
.Match('-', '-')) {
322 sc
.SetState(SCE_LUA_COMMENTLINE
);
323 if (sc
.Match("--[")) {
325 sepCount
= LongDelimCheck(sc
);
328 sc
.ChangeState(SCE_LUA_COMMENT
);
329 sc
.Forward(sepCount
);
334 } else if (sc
.atLineStart
&& sc
.Match('$')) {
335 sc
.SetState(SCE_LUA_PREPROCESSOR
); // Obsolete since Lua 4.0, but still in old code
336 } else if (setLuaOperator
.Contains(sc
.ch
)) {
337 sc
.SetState(SCE_LUA_OPERATOR
);
342 if (setWord
.Contains(sc
.chPrev
) || sc
.chPrev
== '.') {
344 sc
.GetCurrent(s
, sizeof(s
));
345 if (keywords
.InList(s
)) {
346 sc
.ChangeState(SCE_LUA_WORD
);
347 } else if (keywords2
.InList(s
)) {
348 sc
.ChangeState(SCE_LUA_WORD2
);
349 } else if (keywords3
.InList(s
)) {
350 sc
.ChangeState(SCE_LUA_WORD3
);
351 } else if (keywords4
.InList(s
)) {
352 sc
.ChangeState(SCE_LUA_WORD4
);
353 } else if (keywords5
.InList(s
)) {
354 sc
.ChangeState(SCE_LUA_WORD5
);
355 } else if (keywords6
.InList(s
)) {
356 sc
.ChangeState(SCE_LUA_WORD6
);
357 } else if (keywords7
.InList(s
)) {
358 sc
.ChangeState(SCE_LUA_WORD7
);
359 } else if (keywords8
.InList(s
)) {
360 sc
.ChangeState(SCE_LUA_WORD8
);
367 static void FoldLuaDoc(unsigned int startPos
, int length
, int /* initStyle */, WordList
*[],
369 unsigned int lengthDoc
= startPos
+ length
;
370 int visibleChars
= 0;
371 int lineCurrent
= styler
.GetLine(startPos
);
372 int levelPrev
= styler
.LevelAt(lineCurrent
) & SC_FOLDLEVELNUMBERMASK
;
373 int levelCurrent
= levelPrev
;
374 char chNext
= styler
[startPos
];
375 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
376 int styleNext
= styler
.StyleAt(startPos
);
379 for (unsigned int i
= startPos
; i
< lengthDoc
; i
++) {
381 chNext
= styler
.SafeGetCharAt(i
+ 1);
382 int style
= styleNext
;
383 styleNext
= styler
.StyleAt(i
+ 1);
384 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
385 if (style
== SCE_LUA_WORD
) {
386 if (ch
== 'i' || ch
== 'd' || ch
== 'f' || ch
== 'e' || ch
== 'r' || ch
== 'u') {
387 for (unsigned int j
= 0; j
< 8; j
++) {
388 if (!iswordchar(styler
[i
+ j
])) {
391 s
[j
] = styler
[i
+ j
];
395 if ((strcmp(s
, "if") == 0) || (strcmp(s
, "do") == 0) || (strcmp(s
, "function") == 0) || (strcmp(s
, "repeat") == 0)) {
398 if ((strcmp(s
, "end") == 0) || (strcmp(s
, "elseif") == 0) || (strcmp(s
, "until") == 0)) {
402 } else if (style
== SCE_LUA_OPERATOR
) {
403 if (ch
== '{' || ch
== '(') {
405 } else if (ch
== '}' || ch
== ')') {
408 } else if (style
== SCE_LUA_LITERALSTRING
|| style
== SCE_LUA_COMMENT
) {
411 } else if (ch
== ']') {
418 if (visibleChars
== 0 && foldCompact
) {
419 lev
|= SC_FOLDLEVELWHITEFLAG
;
421 if ((levelCurrent
> levelPrev
) && (visibleChars
> 0)) {
422 lev
|= SC_FOLDLEVELHEADERFLAG
;
424 if (lev
!= styler
.LevelAt(lineCurrent
)) {
425 styler
.SetLevel(lineCurrent
, lev
);
428 levelPrev
= levelCurrent
;
431 if (!isspacechar(ch
)) {
435 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
437 int flagsNext
= styler
.LevelAt(lineCurrent
) & ~SC_FOLDLEVELNUMBERMASK
;
438 styler
.SetLevel(lineCurrent
, levelPrev
| flagsNext
);
441 static const char * const luaWordListDesc
[] = {
444 "String, (table) & math functions",
445 "(coroutines), I/O & system facilities",
453 LexerModule
lmLua(SCLEX_LUA
, ColouriseLuaDoc
, "lua", FoldLuaDoc
, luaWordListDesc
);