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