]>
Commit | Line | Data |
---|---|---|
1e9bafca RD |
1 | // Scintilla source code edit control |
2 | /** @file LexSmalltalk.cxx | |
3 | ** Lexer for Smalltalk language. | |
4 | ** Written by Sergey Philippov, sphilippov-at-gmail-dot-com | |
5 | **/ | |
6 | // Copyright 1998-2002 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> | |
1dcf666d RD |
11 | #include <stdio.h> |
12 | #include <stdarg.h> | |
13 | #include <assert.h> | |
1e9bafca RD |
14 | #include <ctype.h> |
15 | ||
1dcf666d RD |
16 | #include "ILexer.h" |
17 | #include "Scintilla.h" | |
18 | #include "SciLexer.h" | |
1e9bafca | 19 | |
1dcf666d RD |
20 | #include "WordList.h" |
21 | #include "LexAccessor.h" | |
1e9bafca RD |
22 | #include "Accessor.h" |
23 | #include "StyleContext.h" | |
1dcf666d RD |
24 | #include "CharacterSet.h" |
25 | #include "LexerModule.h" | |
1e9bafca | 26 | |
7e0c58e9 RD |
27 | #ifdef SCI_NAMESPACE |
28 | using namespace Scintilla; | |
29 | #endif | |
30 | ||
1e9bafca RD |
31 | /* |
32 | | lexTable classificationBlock charClasses | | |
33 | charClasses := #(#DecDigit #Letter #Special #Upper #BinSel). | |
34 | lexTable := ByteArray new: 128. | |
35 | classificationBlock := [ :charClass :chars | | |
36 | | flag | | |
37 | flag := 1 bitShift: (charClasses indexOf: charClass) - 1. | |
38 | chars do: [ :char | lexTable at: char codePoint + 1 put: ((lexTable at: char codePoint + 1) bitOr: flag)]]. | |
39 | ||
40 | classificationBlock | |
41 | value: #DecDigit value: '0123456789'; | |
42 | value: #Letter value: '_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; | |
43 | value: #Special value: '()[]{};.^:'; | |
44 | value: #BinSel value: '~@%&*-+=|\/,<>?!'; | |
45 | value: #Upper value: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. | |
46 | ||
1dcf666d | 47 | ((String new: 500) streamContents: [ :stream | |
1e9bafca RD |
48 | stream crLf; nextPutAll: 'static int ClassificationTable[256] = {'. |
49 | lexTable keysAndValuesDo: [ :index :value | | |
50 | ((index - 1) rem: 16) == 0 ifTrue: [ | |
51 | stream crLf; tab] | |
52 | ifFalse: [ | |
53 | stream space]. | |
54 | stream print: value. | |
55 | index ~= 256 ifTrue: [ | |
56 | stream nextPut: $,]]. | |
57 | stream crLf; nextPutAll: '};'; crLf. | |
1dcf666d | 58 | |
1e9bafca RD |
59 | charClasses keysAndValuesDo: [ :index :name | |
60 | stream | |
61 | crLf; | |
62 | nextPutAll: ( | |
63 | ('static inline bool is<1s>(int ch) {return (ch > 0) && (ch %< 0x80) && ((ClassificationTable[ch] & <2p>) != 0);}') | |
64 | expandMacrosWith: name with: (1 bitShift: (index - 1))) | |
65 | ]]) edit | |
66 | */ | |
67 | ||
68 | // autogenerated {{{{ | |
69 | ||
70 | static int ClassificationTable[256] = { | |
71 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
72 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
73 | 0, 16, 0, 0, 0, 16, 16, 0, 4, 4, 16, 16, 16, 16, 4, 16, | |
74 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 16, 16, 16, 16, | |
75 | 16, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, | |
76 | 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 4, 16, 4, 4, 2, | |
77 | 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |
78 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 16, 4, 16, 0, | |
79 | }; | |
80 | ||
81 | static inline bool isDecDigit(int ch) {return (ch > 0) && (ch < 0x80) && ((ClassificationTable[ch] & 1) != 0);} | |
82 | static inline bool isLetter(int ch) {return (ch > 0) && (ch < 0x80) && ((ClassificationTable[ch] & 2) != 0);} | |
83 | static inline bool isSpecial(int ch) {return (ch > 0) && (ch < 0x80) && ((ClassificationTable[ch] & 4) != 0);} | |
84 | static inline bool isUpper(int ch) {return (ch > 0) && (ch < 0x80) && ((ClassificationTable[ch] & 8) != 0);} | |
85 | static inline bool isBinSel(int ch) {return (ch > 0) && (ch < 0x80) && ((ClassificationTable[ch] & 16) != 0);} | |
86 | // autogenerated }}}} | |
87 | ||
88 | static inline bool isAlphaNumeric(int ch) { | |
89 | return isDecDigit(ch) || isLetter(ch); | |
90 | } | |
91 | ||
92 | static inline bool isDigitOfRadix(int ch, int radix) | |
93 | { | |
94 | if (isDecDigit(ch)) | |
95 | return (ch - '0') < radix; | |
96 | else if (!isUpper(ch)) | |
97 | return false; | |
98 | else | |
99 | return (ch - 'A' + 10) < radix; | |
100 | } | |
101 | ||
102 | static inline void skipComment(StyleContext& sc) | |
1dcf666d | 103 | { |
1e9bafca RD |
104 | while (sc.More() && sc.ch != '\"') |
105 | sc.Forward(); | |
106 | } | |
107 | ||
108 | static inline void skipString(StyleContext& sc) | |
109 | { | |
110 | while (sc.More()) { | |
111 | if (sc.ch == '\'') { | |
112 | if (sc.chNext != '\'') | |
113 | return; | |
114 | sc.Forward(); | |
115 | } | |
116 | sc.Forward(); | |
117 | } | |
118 | } | |
119 | ||
120 | static void handleHash(StyleContext& sc) | |
121 | { | |
122 | if (isSpecial(sc.chNext)) { | |
123 | sc.SetState(SCE_ST_SPECIAL); | |
124 | return; | |
125 | } | |
1dcf666d | 126 | |
1e9bafca RD |
127 | sc.SetState(SCE_ST_SYMBOL); |
128 | sc.Forward(); | |
129 | if (sc.ch == '\'') { | |
130 | sc.Forward(); | |
131 | skipString(sc); | |
132 | } | |
133 | else { | |
134 | if (isLetter(sc.ch)) { | |
135 | while (isAlphaNumeric(sc.chNext) || sc.chNext == ':') | |
136 | sc.Forward(); | |
137 | } | |
138 | else if (isBinSel(sc.ch)) { | |
139 | while (isBinSel(sc.chNext)) | |
140 | sc.Forward(); | |
141 | } | |
142 | } | |
143 | } | |
144 | ||
145 | static inline void handleSpecial(StyleContext& sc) | |
146 | { | |
147 | if (sc.ch == ':' && sc.chNext == '=') { | |
148 | sc.SetState(SCE_ST_ASSIGN); | |
149 | sc.Forward(); | |
150 | } | |
151 | else { | |
152 | if (sc.ch == '^') | |
153 | sc.SetState(SCE_ST_RETURN); | |
154 | else | |
155 | sc.SetState(SCE_ST_SPECIAL); | |
156 | } | |
157 | } | |
158 | ||
159 | static inline void skipInt(StyleContext& sc, int radix) | |
160 | { | |
161 | while (isDigitOfRadix(sc.chNext, radix)) | |
162 | sc.Forward(); | |
163 | } | |
164 | ||
165 | static void handleNumeric(StyleContext& sc) | |
166 | { | |
167 | char num[256]; | |
168 | int nl; | |
169 | int radix; | |
1dcf666d | 170 | |
1e9bafca RD |
171 | sc.SetState(SCE_ST_NUMBER); |
172 | num[0] = static_cast<char>(sc.ch); | |
173 | nl = 1; | |
174 | while (isDecDigit(sc.chNext)) { | |
175 | num[nl++] = static_cast<char>(sc.chNext); | |
176 | sc.Forward(); | |
177 | if (nl+1 == sizeof(num)/sizeof(num[0])) // overrun check | |
178 | break; | |
179 | } | |
180 | if (sc.chNext == 'r') { | |
181 | num[nl] = 0; | |
182 | if (num[0] == '-') | |
183 | radix = atoi(num + 1); | |
184 | else | |
185 | radix = atoi(num); | |
186 | sc.Forward(); | |
187 | if (sc.chNext == '-') | |
188 | sc.Forward(); | |
189 | skipInt(sc, radix); | |
190 | } | |
191 | else | |
192 | radix = 10; | |
193 | if (sc.chNext != '.' || !isDigitOfRadix(sc.GetRelative(2), radix)) | |
194 | return; | |
195 | sc.Forward(); | |
196 | skipInt(sc, radix); | |
197 | if (sc.chNext == 's') { | |
198 | // ScaledDecimal | |
199 | sc.Forward(); | |
200 | while (isDecDigit(sc.chNext)) | |
201 | sc.Forward(); | |
202 | return; | |
203 | } | |
204 | else if (sc.chNext != 'e' && sc.chNext != 'd' && sc.chNext != 'q') | |
205 | return; | |
206 | sc.Forward(); | |
207 | if (sc.chNext == '+' || sc.chNext == '-') | |
208 | sc.Forward(); | |
209 | skipInt(sc, radix); | |
210 | } | |
211 | ||
212 | static inline void handleBinSel(StyleContext& sc) | |
213 | { | |
214 | sc.SetState(SCE_ST_BINARY); | |
215 | while (isBinSel(sc.chNext)) | |
216 | sc.Forward(); | |
217 | } | |
218 | ||
219 | static void handleLetter(StyleContext& sc, WordList* specialSelectorList) | |
220 | { | |
221 | char ident[256]; | |
222 | int il; | |
223 | int state; | |
224 | bool doubleColonPresent; | |
1dcf666d | 225 | |
1e9bafca RD |
226 | sc.SetState(SCE_ST_DEFAULT); |
227 | ||
228 | ident[0] = static_cast<char>(sc.ch); | |
229 | il = 1; | |
230 | while (isAlphaNumeric(sc.chNext)) { | |
231 | ident[il++] = static_cast<char>(sc.chNext); | |
232 | sc.Forward(); | |
233 | if (il+2 == sizeof(ident)/sizeof(ident[0])) // overrun check | |
234 | break; | |
235 | } | |
236 | ||
237 | if (sc.chNext == ':') { | |
238 | doubleColonPresent = true; | |
239 | ident[il++] = ':'; | |
240 | sc.Forward(); | |
241 | } | |
242 | else | |
243 | doubleColonPresent = false; | |
244 | ident[il] = 0; | |
1dcf666d | 245 | |
1e9bafca RD |
246 | if (specialSelectorList->InList(ident)) |
247 | state = SCE_ST_SPEC_SEL; | |
248 | else if (doubleColonPresent) | |
249 | state = SCE_ST_KWSEND; | |
250 | else if (isUpper(ident[0])) | |
251 | state = SCE_ST_GLOBAL; | |
252 | else { | |
253 | if (!strcmp(ident, "self")) | |
254 | state = SCE_ST_SELF; | |
255 | else if (!strcmp(ident, "super")) | |
256 | state = SCE_ST_SUPER; | |
257 | else if (!strcmp(ident, "nil")) | |
258 | state = SCE_ST_NIL; | |
259 | else if (!strcmp(ident, "true") || !strcmp(ident, "false")) | |
260 | state = SCE_ST_BOOL; | |
261 | else | |
262 | state = SCE_ST_DEFAULT; | |
263 | } | |
1dcf666d | 264 | |
1e9bafca RD |
265 | sc.ChangeState(state); |
266 | } | |
267 | ||
268 | static void colorizeSmalltalkDoc(unsigned int startPos, int length, int initStyle, WordList *wordLists[], Accessor &styler) | |
269 | { | |
270 | StyleContext sc(startPos, length, initStyle, styler); | |
271 | ||
272 | if (initStyle == SCE_ST_COMMENT) { | |
273 | skipComment(sc); | |
274 | if (sc.More()) | |
275 | sc.Forward(); | |
276 | } | |
277 | else if (initStyle == SCE_ST_STRING) { | |
278 | skipString(sc); | |
279 | if (sc.More()) | |
280 | sc.Forward(); | |
281 | } | |
282 | ||
283 | for (; sc.More(); sc.Forward()) { | |
284 | int ch; | |
1dcf666d | 285 | |
1e9bafca RD |
286 | ch = sc.ch; |
287 | if (ch == '\"') { | |
288 | sc.SetState(SCE_ST_COMMENT); | |
289 | sc.Forward(); | |
290 | skipComment(sc); | |
291 | } | |
292 | else if (ch == '\'') { | |
293 | sc.SetState(SCE_ST_STRING); | |
294 | sc.Forward(); | |
295 | skipString(sc); | |
296 | } | |
297 | else if (ch == '#') | |
298 | handleHash(sc); | |
299 | else if (ch == '$') { | |
300 | sc.SetState(SCE_ST_CHARACTER); | |
301 | sc.Forward(); | |
302 | } | |
303 | else if (isSpecial(ch)) | |
304 | handleSpecial(sc); | |
305 | else if (isDecDigit(ch)) | |
306 | handleNumeric(sc); | |
307 | else if (isLetter(ch)) | |
308 | handleLetter(sc, wordLists[0]); | |
309 | else if (isBinSel(ch)) { | |
310 | if (ch == '-' && isDecDigit(sc.chNext)) | |
311 | handleNumeric(sc); | |
312 | else | |
313 | handleBinSel(sc); | |
314 | } | |
315 | else | |
316 | sc.SetState(SCE_ST_DEFAULT); | |
317 | } | |
318 | sc.Complete(); | |
319 | } | |
320 | ||
321 | static const char* const smalltalkWordListDesc[] = { | |
322 | "Special selectors", | |
323 | 0 | |
324 | }; | |
325 | ||
326 | LexerModule lmSmalltalk(SCLEX_SMALLTALK, colorizeSmalltalkDoc, "smalltalk", NULL, smalltalkWordListDesc); |