*** empty log message ***
[anjuta-git-plugin.git] / scintilla / LexLua.cxx
blobd3f80ada2f69bc231f57ac89ed09df08abb2b63f
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 **/
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <stdarg.h>
14 #include <stdio.h>
16 #include "Platform.h"
18 #include "PropSet.h"
19 #include "Accessor.h"
20 #include "StyleContext.h"
21 #include "KeyWords.h"
22 #include "Scintilla.h"
23 #include "SciLexer.h"
25 static inline bool IsAWordChar(const int ch) {
26 return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '.');
29 static inline bool IsAWordStart(const int ch) {
30 return (ch < 0x80) && (isalnum(ch) || ch == '_');
33 static inline bool IsANumberChar(const int ch) {
34 // Not exactly following number definition (several dots are seen as OK, etc.)
35 // but probably enough in most cases.
36 return (ch < 0x80) &&
37 (isdigit(ch) || toupper(ch) == 'E' ||
38 ch == '.' || ch == '-' || ch == '+');
41 static inline bool IsLuaOperator(int ch) {
42 if (ch >= 0x80 || isalnum(ch)) {
43 return false;
45 // '.' left out as it is used to make up numbers
46 if (ch == '*' || ch == '/' || ch == '-' || ch == '+' ||
47 ch == '(' || ch == ')' || ch == '=' ||
48 ch == '{' || ch == '}' || ch == '~' ||
49 ch == '[' || ch == ']' || ch == ';' ||
50 ch == '<' || ch == '>' || ch == ',' ||
51 ch == '.' || ch == '^' || ch == '%' || ch == ':') {
52 return true;
54 return false;
57 static void ColouriseLuaDoc(
58 unsigned int startPos,
59 int length,
60 int initStyle,
61 WordList *keywordlists[],
62 Accessor &styler) {
64 WordList &keywords = *keywordlists[0];
65 WordList &keywords2 = *keywordlists[1];
66 WordList &keywords3 = *keywordlists[2];
67 WordList &keywords4 = *keywordlists[3];
68 WordList &keywords5 = *keywordlists[4];
69 WordList &keywords6 = *keywordlists[5];
70 WordList &keywords7 = *keywordlists[6];
71 WordList &keywords8 = *keywordlists[7];
73 int currentLine = styler.GetLine(startPos);
74 // Initialize the literal string [[ ... ]] nesting level, if we are inside such a string.
75 int literalStringLevel = 0;
76 if (initStyle == SCE_LUA_LITERALSTRING) {
77 literalStringLevel = styler.GetLineState(currentLine - 1);
79 // Initialize the block comment --[[ ... ]] nesting level, if we are inside such a comment
80 int blockCommentLevel = 0;
81 if (initStyle == SCE_LUA_COMMENT) {
82 blockCommentLevel = styler.GetLineState(currentLine - 1);
85 // Do not leak onto next line
86 if (initStyle == SCE_LUA_STRINGEOL) {
87 initStyle = SCE_LUA_DEFAULT;
90 StyleContext sc(startPos, length, initStyle, styler);
91 if (startPos == 0 && sc.ch == '#') {
92 // shbang line: # is a comment only if first char of the script
93 sc.SetState(SCE_LUA_COMMENTLINE);
95 for (; sc.More(); sc.Forward()) {
96 if (sc.atLineEnd) {
97 // Update the line state, so it can be seen by next line
98 currentLine = styler.GetLine(sc.currentPos);
99 switch (sc.state) {
100 case SCE_LUA_LITERALSTRING:
101 // Inside a literal string, we set the line state
102 styler.SetLineState(currentLine, literalStringLevel);
103 break;
104 case SCE_LUA_COMMENT: // Block comment
105 // Inside a block comment, we set the line state
106 styler.SetLineState(currentLine, blockCommentLevel);
107 break;
108 default:
109 // Reset the line state
110 styler.SetLineState(currentLine, 0);
111 break;
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) &&
121 sc.ch == '\\') {
122 if (sc.chNext == '\n' || sc.chNext == '\r') {
123 sc.Forward();
124 if (sc.ch == '\r' && sc.chNext == '\n') {
125 sc.Forward();
127 continue;
131 // Determine if the current state should terminate.
132 if (sc.state == SCE_LUA_OPERATOR) {
133 sc.SetState(SCE_LUA_DEFAULT);
134 } else if (sc.state == SCE_LUA_NUMBER) {
135 // We stop the number definition on non-numerical non-dot non-eE non-sign char
136 if (!IsANumberChar(sc.ch)) {
137 sc.SetState(SCE_LUA_DEFAULT);
139 } else if (sc.state == SCE_LUA_IDENTIFIER) {
140 if (!IsAWordChar(sc.ch) || sc.Match('.', '.')) {
141 char s[100];
142 sc.GetCurrent(s, sizeof(s));
143 if (keywords.InList(s)) {
144 sc.ChangeState(SCE_LUA_WORD);
145 } else if (keywords2.InList(s)) {
146 sc.ChangeState(SCE_LUA_WORD2);
147 } else if (keywords3.InList(s)) {
148 sc.ChangeState(SCE_LUA_WORD3);
149 } else if (keywords4.InList(s)) {
150 sc.ChangeState(SCE_LUA_WORD4);
151 } else if (keywords5.InList(s)) {
152 sc.ChangeState(SCE_LUA_WORD5);
153 } else if (keywords6.InList(s)) {
154 sc.ChangeState(SCE_LUA_WORD6);
155 } else if (keywords6.InList(s)) {
156 sc.ChangeState(SCE_LUA_WORD6);
157 } else if (keywords7.InList(s)) {
158 sc.ChangeState(SCE_LUA_WORD7);
159 } else if (keywords8.InList(s)) {
160 sc.ChangeState(SCE_LUA_WORD8);
162 sc.SetState(SCE_LUA_DEFAULT);
164 } else if (sc.state == SCE_LUA_COMMENTLINE ) {
165 if (sc.atLineEnd) {
166 sc.SetState(SCE_LUA_DEFAULT);
168 } else if (sc.state == SCE_LUA_PREPROCESSOR ) {
169 if (sc.atLineEnd) {
170 sc.SetState(SCE_LUA_DEFAULT);
172 } else if (sc.state == SCE_LUA_STRING) {
173 if (sc.ch == '\\') {
174 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
175 sc.Forward();
177 } else if (sc.ch == '\"') {
178 sc.ForwardSetState(SCE_LUA_DEFAULT);
179 } else if (sc.atLineEnd) {
180 sc.ChangeState(SCE_LUA_STRINGEOL);
181 sc.ForwardSetState(SCE_LUA_DEFAULT);
183 } else if (sc.state == SCE_LUA_CHARACTER) {
184 if (sc.ch == '\\') {
185 if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
186 sc.Forward();
188 } else if (sc.ch == '\'') {
189 sc.ForwardSetState(SCE_LUA_DEFAULT);
190 } else if (sc.atLineEnd) {
191 sc.ChangeState(SCE_LUA_STRINGEOL);
192 sc.ForwardSetState(SCE_LUA_DEFAULT);
194 } else if (sc.state == SCE_LUA_LITERALSTRING) {
195 if (sc.Match('[', '[')) {
196 literalStringLevel++;
197 sc.Forward();
198 sc.SetState(SCE_LUA_LITERALSTRING);
199 } else if (sc.Match(']', ']') && literalStringLevel > 0) {
200 literalStringLevel--;
201 sc.Forward();
202 if (literalStringLevel == 0) {
203 sc.ForwardSetState(SCE_LUA_DEFAULT);
206 } else if (sc.state == SCE_LUA_COMMENT) { // Lua 5.0's block comment
207 if (sc.Match('[', '[')) {
208 blockCommentLevel++;
209 sc.Forward();
210 } else if (sc.Match(']', ']') && blockCommentLevel > 0) {
211 blockCommentLevel--;
212 sc.Forward();
213 if (blockCommentLevel == 0) {
214 sc.ForwardSetState(SCE_LUA_DEFAULT);
219 // Determine if a new state should be entered.
220 if (sc.state == SCE_LUA_DEFAULT) {
221 if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
222 sc.SetState(SCE_LUA_NUMBER);
223 } else if (IsAWordStart(sc.ch)) {
224 sc.SetState(SCE_LUA_IDENTIFIER);
225 } else if (sc.Match('\"')) {
226 sc.SetState(SCE_LUA_STRING);
227 } else if (sc.Match('\'')) {
228 sc.SetState(SCE_LUA_CHARACTER);
229 } else if (sc.Match('[', '[')) {
230 literalStringLevel = 1;
231 sc.SetState(SCE_LUA_LITERALSTRING);
232 sc.Forward();
233 } else if (sc.Match("--[[")) { // Lua 5.0's block comment
234 blockCommentLevel = 1;
235 sc.SetState(SCE_LUA_COMMENT);
236 sc.Forward(3);
237 } else if (sc.Match('-', '-')) {
238 sc.SetState(SCE_LUA_COMMENTLINE);
239 sc.Forward();
240 } else if (sc.atLineStart && sc.Match('$')) {
241 sc.SetState(SCE_LUA_PREPROCESSOR); // Obsolete since Lua 4.0, but still in old code
242 } else if (IsLuaOperator(static_cast<char>(sc.ch))) {
243 sc.SetState(SCE_LUA_OPERATOR);
247 sc.Complete();
250 static void FoldLuaDoc(unsigned int startPos, int length, int /* initStyle */, WordList *[],
251 Accessor &styler) {
252 unsigned int lengthDoc = startPos + length;
253 int visibleChars = 0;
254 int lineCurrent = styler.GetLine(startPos);
255 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
256 int levelCurrent = levelPrev;
257 char chNext = styler[startPos];
258 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
259 int styleNext = styler.StyleAt(startPos);
260 char s[10];
262 for (unsigned int i = startPos; i < lengthDoc; i++) {
263 char ch = chNext;
264 chNext = styler.SafeGetCharAt(i + 1);
265 int style = styleNext;
266 styleNext = styler.StyleAt(i + 1);
267 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
268 if (style == SCE_LUA_WORD) {
269 if (ch == 'i' || ch == 'd' || ch == 'f' || ch == 'e') {
270 for (unsigned int j = 0; j < 8; j++) {
271 if (!iswordchar(styler[i + j])) {
272 break;
274 s[j] = styler[i + j];
275 s[j + 1] = '\0';
278 if ((strcmp(s, "if") == 0) || (strcmp(s, "do") == 0) || (strcmp(s, "function") == 0)) {
279 levelCurrent++;
281 if ((strcmp(s, "end") == 0) || (strcmp(s, "elseif") == 0)) {
282 levelCurrent--;
285 } else if (style == SCE_LUA_OPERATOR) {
286 if (ch == '{' || ch == '(') {
287 levelCurrent++;
288 } else if (ch == '}' || ch == ')') {
289 levelCurrent--;
293 if (atEOL) {
294 int lev = levelPrev;
295 if (visibleChars == 0 && foldCompact) {
296 lev |= SC_FOLDLEVELWHITEFLAG;
298 if ((levelCurrent > levelPrev) && (visibleChars > 0)) {
299 lev |= SC_FOLDLEVELHEADERFLAG;
301 if (lev != styler.LevelAt(lineCurrent)) {
302 styler.SetLevel(lineCurrent, lev);
304 lineCurrent++;
305 levelPrev = levelCurrent;
306 visibleChars = 0;
308 if (!isspacechar(ch)) {
309 visibleChars++;
312 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
314 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
315 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
318 static const char * const luaWordListDesc[] = {
319 "Keywords",
320 "Basic functions",
321 "String, (table) & math functions",
322 "(coroutines), I/O & system facilities",
323 "XXX",
324 "XXX",
328 LexerModule lmLua(SCLEX_LUA, ColouriseLuaDoc, "lua", FoldLuaDoc, luaWordListDesc);