]>
git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/src/LexLua.cxx
63114a976dfaeb63a060b3b46579920e87e8d0ec
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
20 #include "StyleContext.h"
22 #include "Scintilla.h"
26 using namespace Scintilla
;
29 // Extended to accept accented characters
30 static inline bool IsAWordChar(int ch
) {
32 (isalnum(ch
) || ch
== '.' || ch
== '_');
35 static inline bool IsAWordStart(int ch
) {
37 (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 (isdigit(ch
) || toupper(ch
) == 'E' ||
45 ch
== '.' || ch
== '-' || ch
== '+' ||
46 (ch
>= 'a' && ch
<= 'f') || (ch
>= 'A' && ch
<= 'F'));
49 static inline bool IsLuaOperator(int ch
) {
50 if (ch
>= 0x80 || isalnum(ch
)) {
53 // '.' left out as it is used to make up numbers
54 if (ch
== '*' || ch
== '/' || ch
== '-' || ch
== '+' ||
55 ch
== '(' || ch
== ')' || ch
== '=' ||
56 ch
== '{' || ch
== '}' || ch
== '~' ||
57 ch
== '[' || ch
== ']' || ch
== ';' ||
58 ch
== '<' || ch
== '>' || ch
== ',' ||
59 ch
== '.' || ch
== '^' || ch
== '%' || ch
== ':' ||
66 // Test for [=[ ... ]=] delimiters, returns 0 if it's only a [ or ],
67 // return 1 for [[ or ]], returns >=2 for [=[ or ]=] and so on.
68 // The maximum number of '=' characters allowed is 254.
69 static int LongDelimCheck(StyleContext
&sc
) {
71 while (sc
.GetRelative(sep
) == '=' && sep
< 0xFF)
73 if (sc
.GetRelative(sep
) == sc
.ch
)
78 static void ColouriseLuaDoc(
79 unsigned int startPos
,
82 WordList
*keywordlists
[],
85 WordList
&keywords
= *keywordlists
[0];
86 WordList
&keywords2
= *keywordlists
[1];
87 WordList
&keywords3
= *keywordlists
[2];
88 WordList
&keywords4
= *keywordlists
[3];
89 WordList
&keywords5
= *keywordlists
[4];
90 WordList
&keywords6
= *keywordlists
[5];
91 WordList
&keywords7
= *keywordlists
[6];
92 WordList
&keywords8
= *keywordlists
[7];
94 int currentLine
= styler
.GetLine(startPos
);
95 // Initialize long string [[ ... ]] or block comment --[[ ... ]] nesting level,
96 // if we are inside such a string. Block comment was introduced in Lua 5.0,
97 // blocks with separators [=[ ... ]=] in Lua 5.1.
100 if (initStyle
== SCE_LUA_LITERALSTRING
|| initStyle
== SCE_LUA_COMMENT
) {
101 int lineState
= styler
.GetLineState(currentLine
- 1);
102 nestLevel
= lineState
>> 8;
103 sepCount
= lineState
& 0xFF;
106 // Do not leak onto next line
107 if (initStyle
== SCE_LUA_STRINGEOL
|| initStyle
== SCE_LUA_COMMENTLINE
|| initStyle
== SCE_LUA_PREPROCESSOR
) {
108 initStyle
= SCE_LUA_DEFAULT
;
111 StyleContext
sc(startPos
, length
, initStyle
, styler
);
112 if (startPos
== 0 && sc
.ch
== '#') {
113 // shbang line: # is a comment only if first char of the script
114 sc
.SetState(SCE_LUA_COMMENTLINE
);
116 for (; sc
.More(); sc
.Forward()) {
118 // Update the line state, so it can be seen by next line
119 currentLine
= styler
.GetLine(sc
.currentPos
);
121 case SCE_LUA_LITERALSTRING
:
122 case SCE_LUA_COMMENT
:
123 // Inside a literal string or block comment, we set the line state
124 styler
.SetLineState(currentLine
, (nestLevel
<< 8) | sepCount
);
127 // Reset the line state
128 styler
.SetLineState(currentLine
, 0);
132 if (sc
.atLineStart
&& (sc
.state
== SCE_LUA_STRING
)) {
133 // Prevent SCE_LUA_STRINGEOL from leaking back to previous line
134 sc
.SetState(SCE_LUA_STRING
);
137 // Handle string line continuation
138 if ((sc
.state
== SCE_LUA_STRING
|| sc
.state
== SCE_LUA_CHARACTER
) &&
140 if (sc
.chNext
== '\n' || sc
.chNext
== '\r') {
142 if (sc
.ch
== '\r' && sc
.chNext
== '\n') {
149 // Determine if the current state should terminate.
150 if (sc
.state
== SCE_LUA_OPERATOR
) {
151 sc
.SetState(SCE_LUA_DEFAULT
);
152 } else if (sc
.state
== SCE_LUA_NUMBER
) {
153 // We stop the number definition on non-numerical non-dot non-eE non-sign non-hexdigit char
154 if (!IsANumberChar(sc
.ch
)) {
155 sc
.SetState(SCE_LUA_DEFAULT
);
156 } else if (sc
.ch
== '-' || sc
.ch
== '+') {
157 if (sc
.chPrev
!= 'E' && sc
.chPrev
!= 'e')
158 sc
.SetState(SCE_LUA_DEFAULT
);
160 } else if (sc
.state
== SCE_LUA_IDENTIFIER
) {
161 if (!IsAWordChar(sc
.ch
) || sc
.Match('.', '.')) {
163 sc
.GetCurrent(s
, sizeof(s
));
164 if (keywords
.InList(s
)) {
165 sc
.ChangeState(SCE_LUA_WORD
);
166 } else if (keywords2
.InList(s
)) {
167 sc
.ChangeState(SCE_LUA_WORD2
);
168 } else if (keywords3
.InList(s
)) {
169 sc
.ChangeState(SCE_LUA_WORD3
);
170 } else if (keywords4
.InList(s
)) {
171 sc
.ChangeState(SCE_LUA_WORD4
);
172 } else if (keywords5
.InList(s
)) {
173 sc
.ChangeState(SCE_LUA_WORD5
);
174 } else if (keywords6
.InList(s
)) {
175 sc
.ChangeState(SCE_LUA_WORD6
);
176 } else if (keywords7
.InList(s
)) {
177 sc
.ChangeState(SCE_LUA_WORD7
);
178 } else if (keywords8
.InList(s
)) {
179 sc
.ChangeState(SCE_LUA_WORD8
);
181 sc
.SetState(SCE_LUA_DEFAULT
);
183 } else if (sc
.state
== SCE_LUA_COMMENTLINE
|| sc
.state
== SCE_LUA_PREPROCESSOR
) {
185 sc
.ForwardSetState(SCE_LUA_DEFAULT
);
187 } else if (sc
.state
== SCE_LUA_STRING
) {
189 if (sc
.chNext
== '\"' || sc
.chNext
== '\'' || sc
.chNext
== '\\') {
192 } else if (sc
.ch
== '\"') {
193 sc
.ForwardSetState(SCE_LUA_DEFAULT
);
194 } else if (sc
.atLineEnd
) {
195 sc
.ChangeState(SCE_LUA_STRINGEOL
);
196 sc
.ForwardSetState(SCE_LUA_DEFAULT
);
198 } else if (sc
.state
== SCE_LUA_CHARACTER
) {
200 if (sc
.chNext
== '\"' || sc
.chNext
== '\'' || sc
.chNext
== '\\') {
203 } else if (sc
.ch
== '\'') {
204 sc
.ForwardSetState(SCE_LUA_DEFAULT
);
205 } else if (sc
.atLineEnd
) {
206 sc
.ChangeState(SCE_LUA_STRINGEOL
);
207 sc
.ForwardSetState(SCE_LUA_DEFAULT
);
209 } else if (sc
.state
== SCE_LUA_LITERALSTRING
|| sc
.state
== SCE_LUA_COMMENT
) {
211 int sep
= LongDelimCheck(sc
);
212 if (sep
== 1 && sepCount
== 1) { // [[-only allowed to nest
216 } else if (sc
.ch
== ']') {
217 int sep
= LongDelimCheck(sc
);
218 if (sep
== 1 && sepCount
== 1) { // un-nest with ]]-only
221 if (nestLevel
== 0) {
222 sc
.ForwardSetState(SCE_LUA_DEFAULT
);
224 } else if (sep
> 1 && sep
== sepCount
) { // ]=]-style delim
226 sc
.ForwardSetState(SCE_LUA_DEFAULT
);
231 // Determine if a new state should be entered.
232 if (sc
.state
== SCE_LUA_DEFAULT
) {
233 if (IsADigit(sc
.ch
) || (sc
.ch
== '.' && IsADigit(sc
.chNext
))) {
234 sc
.SetState(SCE_LUA_NUMBER
);
235 if (sc
.ch
== '0' && toupper(sc
.chNext
) == 'X') {
238 } else if (IsAWordStart(sc
.ch
)) {
239 sc
.SetState(SCE_LUA_IDENTIFIER
);
240 } else if (sc
.ch
== '\"') {
241 sc
.SetState(SCE_LUA_STRING
);
242 } else if (sc
.ch
== '\'') {
243 sc
.SetState(SCE_LUA_CHARACTER
);
244 } else if (sc
.ch
== '[') {
245 sepCount
= LongDelimCheck(sc
);
247 sc
.SetState(SCE_LUA_OPERATOR
);
250 sc
.SetState(SCE_LUA_LITERALSTRING
);
251 sc
.Forward(sepCount
);
253 } else if (sc
.Match('-', '-')) {
254 sc
.SetState(SCE_LUA_COMMENTLINE
);
255 if (sc
.Match("--[")) {
257 sepCount
= LongDelimCheck(sc
);
260 sc
.ChangeState(SCE_LUA_COMMENT
);
261 sc
.Forward(sepCount
);
266 } else if (sc
.atLineStart
&& sc
.Match('$')) {
267 sc
.SetState(SCE_LUA_PREPROCESSOR
); // Obsolete since Lua 4.0, but still in old code
268 } else if (IsLuaOperator(static_cast<char>(sc
.ch
))) {
269 sc
.SetState(SCE_LUA_OPERATOR
);
276 static void FoldLuaDoc(unsigned int startPos
, int length
, int /* initStyle */, WordList
*[],
278 unsigned int lengthDoc
= startPos
+ length
;
279 int visibleChars
= 0;
280 int lineCurrent
= styler
.GetLine(startPos
);
281 int levelPrev
= styler
.LevelAt(lineCurrent
) & SC_FOLDLEVELNUMBERMASK
;
282 int levelCurrent
= levelPrev
;
283 char chNext
= styler
[startPos
];
284 bool foldCompact
= styler
.GetPropertyInt("fold.compact", 1) != 0;
285 int styleNext
= styler
.StyleAt(startPos
);
288 for (unsigned int i
= startPos
; i
< lengthDoc
; i
++) {
290 chNext
= styler
.SafeGetCharAt(i
+ 1);
291 int style
= styleNext
;
292 styleNext
= styler
.StyleAt(i
+ 1);
293 bool atEOL
= (ch
== '\r' && chNext
!= '\n') || (ch
== '\n');
294 if (style
== SCE_LUA_WORD
) {
295 if (ch
== 'i' || ch
== 'd' || ch
== 'f' || ch
== 'e' || ch
== 'r' || ch
== 'u') {
296 for (unsigned int j
= 0; j
< 8; j
++) {
297 if (!iswordchar(styler
[i
+ j
])) {
300 s
[j
] = styler
[i
+ j
];
304 if ((strcmp(s
, "if") == 0) || (strcmp(s
, "do") == 0) || (strcmp(s
, "function") == 0) || (strcmp(s
, "repeat") == 0)) {
307 if ((strcmp(s
, "end") == 0) || (strcmp(s
, "elseif") == 0) || (strcmp(s
, "until") == 0)) {
311 } else if (style
== SCE_LUA_OPERATOR
) {
312 if (ch
== '{' || ch
== '(') {
314 } else if (ch
== '}' || ch
== ')') {
317 } else if (style
== SCE_LUA_LITERALSTRING
|| style
== SCE_LUA_COMMENT
) {
320 } else if (ch
== ']') {
327 if (visibleChars
== 0 && foldCompact
) {
328 lev
|= SC_FOLDLEVELWHITEFLAG
;
330 if ((levelCurrent
> levelPrev
) && (visibleChars
> 0)) {
331 lev
|= SC_FOLDLEVELHEADERFLAG
;
333 if (lev
!= styler
.LevelAt(lineCurrent
)) {
334 styler
.SetLevel(lineCurrent
, lev
);
337 levelPrev
= levelCurrent
;
340 if (!isspacechar(ch
)) {
344 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
346 int flagsNext
= styler
.LevelAt(lineCurrent
) & ~SC_FOLDLEVELNUMBERMASK
;
347 styler
.SetLevel(lineCurrent
, levelPrev
| flagsNext
);
350 static const char * const luaWordListDesc
[] = {
353 "String, (table) & math functions",
354 "(coroutines), I/O & system facilities",
362 LexerModule
lmLua(SCLEX_LUA
, ColouriseLuaDoc
, "lua", FoldLuaDoc
, luaWordListDesc
);