]> git.saurik.com Git - wxWidgets.git/blob - src/stc/scintilla/lexers/LexLisp.cxx
simplify code so it always returns the same object
[wxWidgets.git] / src / stc / scintilla / lexers / LexLisp.cxx
1 // Scintilla source code edit control
2 /** @file LexLisp.cxx
3 ** Lexer for Lisp.
4 ** Written by Alexey Yutkin.
5 **/
6 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
8
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <assert.h>
14 #include <ctype.h>
15
16 #include "ILexer.h"
17 #include "Scintilla.h"
18 #include "SciLexer.h"
19
20 #include "WordList.h"
21 #include "LexAccessor.h"
22 #include "Accessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
26
27 #ifdef SCI_NAMESPACE
28 using namespace Scintilla;
29 #endif
30
31 #define SCE_LISP_CHARACTER 29
32 #define SCE_LISP_MACRO 30
33 #define SCE_LISP_MACRO_DISPATCH 31
34
35 static inline bool isLispoperator(char ch) {
36 if (isascii(ch) && isalnum(ch))
37 return false;
38 if (ch == '\'' || ch == '`' || ch == '(' || ch == ')' || ch == '[' || ch == ']' || ch == '{' || ch == '}')
39 return true;
40 return false;
41 }
42
43 static inline bool isLispwordstart(char ch) {
44 return isascii(ch) && ch != ';' && !isspacechar(ch) && !isLispoperator(ch) &&
45 ch != '\n' && ch != '\r' && ch != '\"';
46 }
47
48
49 static void classifyWordLisp(unsigned int start, unsigned int end, WordList &keywords, WordList &keywords_kw, Accessor &styler) {
50 assert(end >= start);
51 char s[100];
52 unsigned int i;
53 bool digit_flag = true;
54 for (i = 0; (i < end - start + 1) && (i < 99); i++) {
55 s[i] = styler[start + i];
56 s[i + 1] = '\0';
57 if (!isdigit(s[i]) && (s[i] != '.')) digit_flag = false;
58 }
59 char chAttr = SCE_LISP_IDENTIFIER;
60
61 if(digit_flag) chAttr = SCE_LISP_NUMBER;
62 else {
63 if (keywords.InList(s)) {
64 chAttr = SCE_LISP_KEYWORD;
65 } else if (keywords_kw.InList(s)) {
66 chAttr = SCE_LISP_KEYWORD_KW;
67 } else if ((s[0] == '*' && s[i-1] == '*') ||
68 (s[0] == '+' && s[i-1] == '+')) {
69 chAttr = SCE_LISP_SPECIAL;
70 }
71 }
72 styler.ColourTo(end, chAttr);
73 return;
74 }
75
76
77 static void ColouriseLispDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
78 Accessor &styler) {
79
80 WordList &keywords = *keywordlists[0];
81 WordList &keywords_kw = *keywordlists[1];
82
83 styler.StartAt(startPos);
84
85 int state = initStyle, radix = -1;
86 char chNext = styler[startPos];
87 unsigned int lengthDoc = startPos + length;
88 styler.StartSegment(startPos);
89 for (unsigned int i = startPos; i < lengthDoc; i++) {
90 char ch = chNext;
91 chNext = styler.SafeGetCharAt(i + 1);
92
93 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
94
95 if (styler.IsLeadByte(ch)) {
96 chNext = styler.SafeGetCharAt(i + 2);
97 i += 1;
98 continue;
99 }
100
101 if (state == SCE_LISP_DEFAULT) {
102 if (ch == '#') {
103 styler.ColourTo(i - 1, state);
104 radix = -1;
105 state = SCE_LISP_MACRO_DISPATCH;
106 } else if (ch == ':' && isLispwordstart(chNext)) {
107 styler.ColourTo(i - 1, state);
108 state = SCE_LISP_SYMBOL;
109 } else if (isLispwordstart(ch)) {
110 styler.ColourTo(i - 1, state);
111 state = SCE_LISP_IDENTIFIER;
112 }
113 else if (ch == ';') {
114 styler.ColourTo(i - 1, state);
115 state = SCE_LISP_COMMENT;
116 }
117 else if (isLispoperator(ch) || ch=='\'') {
118 styler.ColourTo(i - 1, state);
119 styler.ColourTo(i, SCE_LISP_OPERATOR);
120 if (ch=='\'' && isLispwordstart(chNext)) {
121 state = SCE_LISP_SYMBOL;
122 }
123 }
124 else if (ch == '\"') {
125 styler.ColourTo(i - 1, state);
126 state = SCE_LISP_STRING;
127 }
128 } else if (state == SCE_LISP_IDENTIFIER || state == SCE_LISP_SYMBOL) {
129 if (!isLispwordstart(ch)) {
130 if (state == SCE_LISP_IDENTIFIER) {
131 classifyWordLisp(styler.GetStartSegment(), i - 1, keywords, keywords_kw, styler);
132 } else {
133 styler.ColourTo(i - 1, state);
134 }
135 state = SCE_LISP_DEFAULT;
136 } /*else*/
137 if (isLispoperator(ch) || ch=='\'') {
138 styler.ColourTo(i - 1, state);
139 styler.ColourTo(i, SCE_LISP_OPERATOR);
140 if (ch=='\'' && isLispwordstart(chNext)) {
141 state = SCE_LISP_SYMBOL;
142 }
143 }
144 } else if (state == SCE_LISP_MACRO_DISPATCH) {
145 if (!(isascii(ch) && isdigit(ch))) {
146 if (ch != 'r' && ch != 'R' && (i - styler.GetStartSegment()) > 1) {
147 state = SCE_LISP_DEFAULT;
148 } else {
149 switch (ch) {
150 case '|': state = SCE_LISP_MULTI_COMMENT; break;
151 case 'o':
152 case 'O': radix = 8; state = SCE_LISP_MACRO; break;
153 case 'x':
154 case 'X': radix = 16; state = SCE_LISP_MACRO; break;
155 case 'b':
156 case 'B': radix = 2; state = SCE_LISP_MACRO; break;
157 case '\\': state = SCE_LISP_CHARACTER; break;
158 case ':':
159 case '-':
160 case '+': state = SCE_LISP_MACRO; break;
161 case '\'': if (isLispwordstart(chNext)) {
162 state = SCE_LISP_SPECIAL;
163 } else {
164 styler.ColourTo(i - 1, SCE_LISP_DEFAULT);
165 styler.ColourTo(i, SCE_LISP_OPERATOR);
166 state = SCE_LISP_DEFAULT;
167 }
168 break;
169 default: if (isLispoperator(ch)) {
170 styler.ColourTo(i - 1, SCE_LISP_DEFAULT);
171 styler.ColourTo(i, SCE_LISP_OPERATOR);
172 }
173 state = SCE_LISP_DEFAULT;
174 break;
175 }
176 }
177 }
178 } else if (state == SCE_LISP_MACRO) {
179 if (isLispwordstart(ch) && (radix == -1 || IsADigit(ch, radix))) {
180 state = SCE_LISP_SPECIAL;
181 } else {
182 state = SCE_LISP_DEFAULT;
183 }
184 } else if (state == SCE_LISP_CHARACTER) {
185 if (isLispoperator(ch)) {
186 styler.ColourTo(i, SCE_LISP_SPECIAL);
187 state = SCE_LISP_DEFAULT;
188 } else if (isLispwordstart(ch)) {
189 styler.ColourTo(i, SCE_LISP_SPECIAL);
190 state = SCE_LISP_SPECIAL;
191 } else {
192 state = SCE_LISP_DEFAULT;
193 }
194 } else if (state == SCE_LISP_SPECIAL) {
195 if (!isLispwordstart(ch) || (radix != -1 && !IsADigit(ch, radix))) {
196 styler.ColourTo(i - 1, state);
197 state = SCE_LISP_DEFAULT;
198 }
199 if (isLispoperator(ch) || ch=='\'') {
200 styler.ColourTo(i - 1, state);
201 styler.ColourTo(i, SCE_LISP_OPERATOR);
202 if (ch=='\'' && isLispwordstart(chNext)) {
203 state = SCE_LISP_SYMBOL;
204 }
205 }
206 } else {
207 if (state == SCE_LISP_COMMENT) {
208 if (atEOL) {
209 styler.ColourTo(i - 1, state);
210 state = SCE_LISP_DEFAULT;
211 }
212 } else if (state == SCE_LISP_MULTI_COMMENT) {
213 if (ch == '|' && chNext == '#') {
214 i++;
215 chNext = styler.SafeGetCharAt(i + 1);
216 styler.ColourTo(i, state);
217 state = SCE_LISP_DEFAULT;
218 }
219 } else if (state == SCE_LISP_STRING) {
220 if (ch == '\\') {
221 if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
222 i++;
223 chNext = styler.SafeGetCharAt(i + 1);
224 }
225 } else if (ch == '\"') {
226 styler.ColourTo(i, state);
227 state = SCE_LISP_DEFAULT;
228 }
229 }
230 }
231
232 }
233 styler.ColourTo(lengthDoc - 1, state);
234 }
235
236 static void FoldLispDoc(unsigned int startPos, int length, int /* initStyle */, WordList *[],
237 Accessor &styler) {
238 unsigned int lengthDoc = startPos + length;
239 int visibleChars = 0;
240 int lineCurrent = styler.GetLine(startPos);
241 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
242 int levelCurrent = levelPrev;
243 char chNext = styler[startPos];
244 int styleNext = styler.StyleAt(startPos);
245 for (unsigned int i = startPos; i < lengthDoc; i++) {
246 char ch = chNext;
247 chNext = styler.SafeGetCharAt(i + 1);
248 int style = styleNext;
249 styleNext = styler.StyleAt(i + 1);
250 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
251 if (style == SCE_LISP_OPERATOR) {
252 if (ch == '(' || ch == '[' || ch == '{') {
253 levelCurrent++;
254 } else if (ch == ')' || ch == ']' || ch == '}') {
255 levelCurrent--;
256 }
257 }
258 if (atEOL) {
259 int lev = levelPrev;
260 if (visibleChars == 0)
261 lev |= SC_FOLDLEVELWHITEFLAG;
262 if ((levelCurrent > levelPrev) && (visibleChars > 0))
263 lev |= SC_FOLDLEVELHEADERFLAG;
264 if (lev != styler.LevelAt(lineCurrent)) {
265 styler.SetLevel(lineCurrent, lev);
266 }
267 lineCurrent++;
268 levelPrev = levelCurrent;
269 visibleChars = 0;
270 }
271 if (!isspacechar(ch))
272 visibleChars++;
273 }
274 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
275 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
276 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
277 }
278
279 static const char * const lispWordListDesc[] = {
280 "Functions and special operators",
281 "Keywords",
282 0
283 };
284
285 LexerModule lmLISP(SCLEX_LISP, ColouriseLispDoc, "lisp", FoldLispDoc, lispWordListDesc);