]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/stc/scintilla/src/LexLua.cxx
fc9607e25d24300256ea201cd1bf598f47151378
[wxWidgets.git] / contrib / src / stc / scintilla / src / LexLua.cxx
1 // Scintilla source code edit control
2 /** @file LexLua.cxx
3 ** Lexer for Lua language.
4 **
5 ** Written by Paul Winwood.
6 ** Folder by Alexey Yutkin.
7 ** Modified by Marcos E. Wurzius & Philippe Lhoste
8 **/
9
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <stdarg.h>
14 #include <stdio.h>
15 #include <fcntl.h>
16
17 #include "Platform.h"
18
19 #include "PropSet.h"
20 #include "Accessor.h"
21 #include "StyleContext.h"
22 #include "KeyWords.h"
23 #include "Scintilla.h"
24 #include "SciLexer.h"
25
26 #define SCE_LUA_LAST_STYLE SCE_LUA_WORD6
27
28 static inline bool IsAWordChar(const int ch) {
29 return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
30 }
31
32 inline bool IsAWordStart(const int ch) {
33 return (ch < 0x80) && (isalnum(ch) || ch == '_');
34 }
35
36 inline bool isLuaOperator(char ch) {
37 if (isalnum(ch))
38 return false;
39 // '.' left out as it is used to make up numbers
40 if (ch == '*' || ch == '/' || ch == '-' || ch == '+' ||
41 ch == '(' || ch == ')' || ch == '=' ||
42 ch == '{' || ch == '}' || ch == '~' ||
43 ch == '[' || ch == ']' || ch == ';' ||
44 ch == '<' || ch == '>' || ch == ',' ||
45 ch == '.' || ch == '^' || ch == '%' || ch == ':')
46 return true;
47 return false;
48 }
49
50 static void ColouriseLuaDoc(
51 unsigned int startPos,
52 int length,
53 int initStyle,
54 WordList *keywordlists[],
55 Accessor &styler) {
56
57 WordList &keywords = *keywordlists[0];
58 WordList &keywords2 = *keywordlists[1];
59 WordList &keywords3 = *keywordlists[2];
60 WordList &keywords4 = *keywordlists[3];
61 WordList &keywords5 = *keywordlists[4];
62 WordList &keywords6 = *keywordlists[5];
63
64 // Must initialize the literal string nesting level, if we are inside such a string.
65 int literalStringLevel = 0;
66 if (initStyle == SCE_LUA_LITERALSTRING) {
67 literalStringLevel = 1;
68 }
69 // We use states above the last one to indicate nesting level of literal strings
70 if (initStyle > SCE_LUA_LAST_STYLE) {
71 literalStringLevel = initStyle - SCE_LUA_LAST_STYLE + 1;
72 }
73
74 // Do not leak onto next line
75 if (initStyle == SCE_LUA_STRINGEOL) {
76 initStyle = SCE_LUA_DEFAULT;
77 }
78
79 StyleContext sc(startPos, length, initStyle, styler);
80 if (startPos == 0 && sc.ch == '#') {
81 sc.SetState(SCE_LUA_COMMENTLINE);
82 }
83 for (; sc.More(); sc.Forward()) {
84 if (sc.atLineStart && (sc.state == SCE_LUA_STRING)) {
85 // Prevent SCE_LUA_STRINGEOL from leaking back to previous line
86 sc.SetState(SCE_LUA_STRING);
87 }
88
89 // Handle string line continuation
90 if ((sc.state == SCE_LUA_STRING || sc.state == SCE_LUA_CHARACTER) &&
91 sc.ch == '\\') {
92 if (sc.chNext == '\n' || sc.chNext == '\r') {
93 sc.Forward();
94 if (sc.ch == '\r' && sc.chNext == '\n') {
95 sc.Forward();
96 }
97 continue;
98 }
99 }
100
101 // Determine if the current state should terminate.
102 if (sc.state == SCE_LUA_OPERATOR) {
103 sc.SetState(SCE_LUA_DEFAULT);
104 } else if (sc.state == SCE_LUA_NUMBER) {
105 if (!IsAWordChar(sc.ch)) {
106 sc.SetState(SCE_LUA_DEFAULT);
107 }
108 } else if (sc.state == SCE_LUA_IDENTIFIER) {
109 if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
110 char s[100];
111 sc.GetCurrent(s, sizeof(s));
112 if (keywords.InList(s)) {
113 sc.ChangeState(SCE_LUA_WORD);
114 } else if (keywords2.InList(s)) {
115 sc.ChangeState(SCE_LUA_WORD2);
116 } else if (keywords3.InList(s)) {
117 sc.ChangeState(SCE_LUA_WORD3);
118 } else if (keywords4.InList(s)) {
119 sc.ChangeState(SCE_LUA_WORD4);
120 } else if (keywords5.InList(s)) {
121 sc.ChangeState(SCE_LUA_WORD5);
122 } else if (keywords6.InList(s)) {
123 sc.ChangeState(SCE_LUA_WORD6);
124 }
125 sc.SetState(SCE_LUA_DEFAULT);
126 }
127 } else if (sc.state == SCE_LUA_COMMENTLINE ) {
128 if (sc.atLineEnd) {
129 sc.SetState(SCE_LUA_DEFAULT);
130 }
131 } else if (sc.state == SCE_LUA_PREPROCESSOR ) {
132 if (sc.atLineEnd) {
133 sc.SetState(SCE_LUA_DEFAULT);
134 }
135 } else if (sc.state == SCE_LUA_STRING) {
136 if (sc.ch == '\\') {
137 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
138 sc.Forward();
139 }
140 } else if (sc.ch == '\"') {
141 sc.ForwardSetState(SCE_LUA_DEFAULT);
142 } else if (sc.atLineEnd) {
143 sc.ChangeState(SCE_LUA_STRINGEOL);
144 sc.ForwardSetState(SCE_LUA_DEFAULT);
145 }
146 } else if (sc.state == SCE_LUA_CHARACTER) {
147 if (sc.ch == '\\') {
148 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
149 sc.Forward();
150 }
151 } else if (sc.ch == '\'') {
152 sc.ForwardSetState(SCE_LUA_DEFAULT);
153 } else if (sc.atLineEnd) {
154 sc.ChangeState(SCE_LUA_STRINGEOL);
155 sc.ForwardSetState(SCE_LUA_DEFAULT);
156 }
157 } else if (sc.state == SCE_LUA_LITERALSTRING || sc.state > SCE_LUA_LAST_STYLE) {
158 if (sc.Match('[', '[')) {
159 literalStringLevel++;
160 sc.SetState(SCE_LUA_LAST_STYLE + literalStringLevel - 1);
161 } else if (sc.Match(']', ']') && literalStringLevel > 0) {
162 literalStringLevel--;
163 sc.Forward();
164 if (literalStringLevel == 0) {
165 sc.ForwardSetState(SCE_LUA_DEFAULT);
166 } else if (literalStringLevel == 1) {
167 sc.ForwardSetState(SCE_LUA_LITERALSTRING);
168 } else {
169 sc.ForwardSetState(SCE_LUA_LAST_STYLE + literalStringLevel - 1);
170 }
171 }
172 }
173 // Determine if a new state should be entered.
174 if (sc.state == SCE_LUA_DEFAULT) {
175 if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
176 sc.SetState(SCE_LUA_NUMBER);
177 } else if (IsAWordStart(sc.ch)) {
178 sc.SetState(SCE_LUA_IDENTIFIER);
179 } else if (sc.Match('\"')) {
180 sc.SetState(SCE_LUA_STRING);
181 } else if (sc.Match('\'')) {
182 sc.SetState(SCE_LUA_CHARACTER);
183 } else if (sc.Match('[', '[')) {
184 literalStringLevel = 1;
185 sc.SetState(SCE_LUA_LITERALSTRING);
186 sc.Forward();
187 } else if (sc.Match('-', '-')) {
188 sc.SetState(SCE_LUA_COMMENTLINE);
189 sc.Forward();
190 } else if (sc.Match('$') && sc.atLineStart) {
191 sc.SetState(SCE_LUA_PREPROCESSOR); // Obsolete since Lua 4.0, but still in old code
192 } else if (isLuaOperator(static_cast<char>(sc.ch))) {
193 sc.SetState(SCE_LUA_OPERATOR);
194 }
195 }
196 }
197 sc.Complete();
198 }
199
200
201 static void FoldLuaDoc(unsigned int startPos, int length, int /* initStyle */, WordList *[],
202 Accessor &styler) {
203 unsigned int lengthDoc = startPos + length;
204 int visibleChars = 0;
205 int lineCurrent = styler.GetLine(startPos);
206 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
207 int levelCurrent = levelPrev;
208 char chNext = styler[startPos];
209 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
210 int styleNext = styler.StyleAt(startPos);
211 char s[10];
212
213 for (unsigned int i = startPos; i < lengthDoc; i++) {
214 char ch = chNext;
215 chNext = styler.SafeGetCharAt(i + 1);
216 int style = styleNext;
217 styleNext = styler.StyleAt(i + 1);
218 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
219 if (style == SCE_LUA_WORD) {
220 if (ch == 'i' || ch == 'd' || ch == 'f' || ch == 'e') {
221 for (unsigned int j = 0; j < 8; j++) {
222 if (!iswordchar(styler[i + j])) {
223 break;
224 }
225 s[j] = styler[i + j];
226 s[j + 1] = '\0';
227 }
228
229 if ((strcmp(s, "if") == 0) || (strcmp(s, "do") == 0) || (strcmp(s, "function") == 0)) {
230 levelCurrent++;
231 }
232 if ((strcmp(s, "end") == 0) || (strcmp(s, "elseif") == 0)) {
233 levelCurrent--;
234 }
235 }
236 } else if (style == SCE_LUA_OPERATOR) {
237 if (ch == '{' || ch == '(') {
238 levelCurrent++;
239 } else if (ch == '}' || ch == ')') {
240 levelCurrent--;
241 }
242 }
243
244 if (atEOL) {
245 int lev = levelPrev;
246 if (visibleChars == 0 && foldCompact) {
247 lev |= SC_FOLDLEVELWHITEFLAG;
248 }
249 if ((levelCurrent > levelPrev) && (visibleChars > 0)) {
250 lev |= SC_FOLDLEVELHEADERFLAG;
251 }
252 if (lev != styler.LevelAt(lineCurrent)) {
253 styler.SetLevel(lineCurrent, lev);
254 }
255 lineCurrent++;
256 levelPrev = levelCurrent;
257 visibleChars = 0;
258 }
259 if (!isspacechar(ch)) {
260 visibleChars++;
261 }
262 }
263 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
264
265 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
266 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
267 }
268
269 LexerModule lmLua(SCLEX_LUA, ColouriseLuaDoc, "lua", FoldLuaDoc);