1// Scintilla source code edit control
2/** @file LexScriptol.cxx
3 ** Lexer for Scriptol.
4 **/
5
6#include <stdlib.h>
7#include <string.h>
8#include <stdio.h>
9#include <stdarg.h>
10#include <assert.h>
11#include <ctype.h>
12
13#include <string>
14#include <string_view>
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
27using namespace Lexilla;
28
29static void ClassifyWordSol(Sci_PositionU start, Sci_PositionU end, WordList &keywords, Accessor &styler, char *prevWord)
30{
31 char s[100] = "";
32 bool wordIsNumber = isdigit(styler[start]) != 0;
33 for (Sci_PositionU i = 0; i < end - start + 1 && i < 30; i++)
34 {
35 s[i] = styler[start + i];
36 s[i + 1] = '\0';
37 }
38 char chAttr = SCE_SCRIPTOL_IDENTIFIER;
39 if (0 == strcmp(prevWord, "class")) chAttr = SCE_SCRIPTOL_CLASSNAME;
40 else if (wordIsNumber) chAttr = SCE_SCRIPTOL_NUMBER;
41 else if (keywords.InList(s)) chAttr = SCE_SCRIPTOL_KEYWORD;
42 else for (Sci_PositionU i = 0; i < end - start + 1; i++) // test dotted idents
43 {
44 if (styler[start + i] == '.')
45 {
46 styler.ColourTo(start + i - 1, chAttr);
47 styler.ColourTo(start + i, SCE_SCRIPTOL_OPERATOR);
48 }
49 }
50 styler.ColourTo(end, chAttr);
51 strcpy(prevWord, s);
52}
53
54static bool IsSolComment(Accessor &styler, Sci_Position pos, Sci_Position len)
55{
56 if(len > 0)
57 {
58 char c = styler[pos];
59 if(c == '`') return true;
60 if(len > 1)
61 {
62 if(c == '/')
63 {
64 c = styler[pos + 1];
65 if(c == '/') return true;
66 if(c == '*') return true;
67 }
68 }
69 }
70 return false;
71}
72
73static bool IsSolStringStart(char ch)
74{
75 if (ch == '\'' || ch == '"') return true;
76 return false;
77}
78
79static bool IsSolWordStart(char ch)
80{
81 return (iswordchar(ch) && !IsSolStringStart(ch));
82}
83
84
85static int GetSolStringState(Accessor &styler, Sci_Position i, Sci_Position *nextIndex)
86{
87 char ch = styler.SafeGetCharAt(i);
88 char chNext = styler.SafeGetCharAt(i + 1);
89
90 if (ch != '\"' && ch != '\'')
91 {
92 *nextIndex = i + 1;
93 return SCE_SCRIPTOL_DEFAULT;
94 }
95 // ch is either single or double quotes in string
96 // code below seem non-sense but is here for future extensions
97 if (ch == chNext && ch == styler.SafeGetCharAt(i + 2))
98 {
99 *nextIndex = i + 3;
100 if(ch == '\"') return SCE_SCRIPTOL_TRIPLE;
101 if(ch == '\'') return SCE_SCRIPTOL_TRIPLE;
102 return SCE_SCRIPTOL_STRING;
103 }
104 else
105 {
106 *nextIndex = i + 1;
107 if (ch == '"') return SCE_SCRIPTOL_STRING;
108 else return SCE_SCRIPTOL_STRING;
109 }
110}
111
112
113static void ColouriseSolDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
114 WordList *keywordlists[], Accessor &styler)
115 {
116
117 Sci_Position lengthDoc = startPos + length;
118 char stringType = '\"';
119
120 if (startPos > 0)
121 {
122 Sci_Position lineCurrent = styler.GetLine(startPos);
123 if (lineCurrent > 0)
124 {
125 startPos = styler.LineStart(lineCurrent-1);
126 if (startPos == 0) initStyle = SCE_SCRIPTOL_DEFAULT;
127 else initStyle = styler.StyleAt(startPos-1);
128 }
129 }
130
131 styler.StartAt(startPos);
132
133 WordList &keywords = *keywordlists[0];
134
135 char prevWord[200];
136 prevWord[0] = '\0';
137 if (length == 0) return;
138
139 int state = initStyle & 31;
140
141 Sci_Position nextIndex = 0;
142 char chPrev = ' ';
143 char chPrev2 = ' ';
144 char chNext = styler[startPos];
145 styler.StartSegment(startPos);
146 for (Sci_Position i = startPos; i < lengthDoc; i++)
147 {
148
149 char ch = chNext;
150 chNext = styler.SafeGetCharAt(i + 1);
151
152 if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == lengthDoc))
153 {
154 if ((state == SCE_SCRIPTOL_DEFAULT) ||
155 (state == SCE_SCRIPTOL_TRIPLE) ||
156 (state == SCE_SCRIPTOL_COMMENTBLOCK))
157 {
158 styler.ColourTo(i, state);
159 }
160 }
161
162 if (styler.IsLeadByte(ch))
163 {
164 chNext = styler.SafeGetCharAt(i + 2);
165 chPrev = ' ';
166 chPrev2 = ' ';
167 i += 1;
168 continue;
169 }
170
171 if (state == SCE_SCRIPTOL_STRINGEOL)
172 {
173 if (ch != '\r' && ch != '\n')
174 {
175 styler.ColourTo(i - 1, state);
176 state = SCE_SCRIPTOL_DEFAULT;
177 }
178 }
179
180 if (state == SCE_SCRIPTOL_DEFAULT)
181 {
182 if (IsSolWordStart(ch))
183 {
184 styler.ColourTo(i - 1, state);
185 state = SCE_SCRIPTOL_KEYWORD;
186 }
187 else if (ch == '`')
188 {
189 styler.ColourTo(i - 1, state);
190 state = SCE_SCRIPTOL_COMMENTLINE;
191 }
192 else if (ch == '/')
193 {
194 styler.ColourTo(i - 1, state);
195 if(chNext == '/') state = SCE_SCRIPTOL_CSTYLE;
196 if(chNext == '*') state = SCE_SCRIPTOL_COMMENTBLOCK;
197 }
198
199 else if (IsSolStringStart(ch))
200 {
201 styler.ColourTo(i - 1, state);
202 state = GetSolStringState(styler, i, &nextIndex);
203 if(state == SCE_SCRIPTOL_STRING)
204 {
205 stringType = ch;
206 }
207 if (nextIndex != i + 1)
208 {
209 i = nextIndex - 1;
210 ch = ' ';
211 chPrev = ' ';
212 chNext = styler.SafeGetCharAt(i + 1);
213 }
214 }
215 else if (isoperator(ch))
216 {
217 styler.ColourTo(i - 1, state);
218 styler.ColourTo(i, SCE_SCRIPTOL_OPERATOR);
219 }
220 }
221 else if (state == SCE_SCRIPTOL_KEYWORD)
222 {
223 if (!iswordchar(ch))
224 {
225 ClassifyWordSol(styler.GetStartSegment(), i - 1, keywords, styler, prevWord);
226 state = SCE_SCRIPTOL_DEFAULT;
227 if (ch == '`')
228 {
229 state = chNext == '`' ? SCE_SCRIPTOL_PERSISTENT : SCE_SCRIPTOL_COMMENTLINE;
230 }
231 else if (IsSolStringStart(ch))
232 {
233 styler.ColourTo(i - 1, state);
234 state = GetSolStringState(styler, i, &nextIndex);
235 if (nextIndex != i + 1)
236 {
237 i = nextIndex - 1;
238 ch = ' ';
239 chPrev = ' ';
240 chNext = styler.SafeGetCharAt(i + 1);
241 }
242 }
243 else if (isoperator(ch))
244 {
245 styler.ColourTo(i, SCE_SCRIPTOL_OPERATOR);
246 }
247 }
248 }
249 else
250 {
251 if (state == SCE_SCRIPTOL_COMMENTLINE ||
252 state == SCE_SCRIPTOL_PERSISTENT ||
253 state == SCE_SCRIPTOL_CSTYLE)
254 {
255 if (ch == '\r' || ch == '\n')
256 {
257 styler.ColourTo(i - 1, state);
258 state = SCE_SCRIPTOL_DEFAULT;
259 }
260 }
261 else if(state == SCE_SCRIPTOL_COMMENTBLOCK)
262 {
263 if(chPrev == '*' && ch == '/')
264 {
265 styler.ColourTo(i, state);
266 state = SCE_SCRIPTOL_DEFAULT;
267 }
268 }
269 else if ((state == SCE_SCRIPTOL_STRING) ||
270 (state == SCE_SCRIPTOL_CHARACTER))
271 {
272 if ((ch == '\r' || ch == '\n') && (chPrev != '\\'))
273 {
274 styler.ColourTo(i - 1, state);
275 state = SCE_SCRIPTOL_STRINGEOL;
276 }
277 else if (ch == '\\')
278 {
279 if (chNext == '\"' || chNext == '\'' || chNext == '\\')
280 {
281 i++;
282 ch = chNext;
283 chNext = styler.SafeGetCharAt(i + 1);
284 }
285 }
286 else if ((ch == '\"') || (ch == '\''))
287 {
288 // must match the entered quote type
289 if(ch == stringType)
290 {
291 styler.ColourTo(i, state);
292 state = SCE_SCRIPTOL_DEFAULT;
293 }
294 }
295 }
296 else if (state == SCE_SCRIPTOL_TRIPLE)
297 {
298 if ((ch == '\'' && chPrev == '\'' && chPrev2 == '\'') ||
299 (ch == '\"' && chPrev == '\"' && chPrev2 == '\"'))
300 {
301 styler.ColourTo(i, state);
302 state = SCE_SCRIPTOL_DEFAULT;
303 }
304 }
305
306 }
307 chPrev2 = chPrev;
308 chPrev = ch;
309 }
310 if (state == SCE_SCRIPTOL_KEYWORD)
311 {
312 ClassifyWordSol(styler.GetStartSegment(),
313 lengthDoc-1, keywords, styler, prevWord);
314 }
315 else
316 {
317 styler.ColourTo(lengthDoc-1, state);
318 }
319}
320
321static void FoldSolDoc(Sci_PositionU startPos, Sci_Position length, int initStyle,
322 WordList *[], Accessor &styler)
323 {
324 Sci_Position lengthDoc = startPos + length;
325
326 Sci_Position lineCurrent = styler.GetLine(startPos);
327 if (startPos > 0)
328 {
329 if (lineCurrent > 0)
330 {
331 lineCurrent--;
332 startPos = styler.LineStart(lineCurrent);
333 if (startPos == 0)
334 initStyle = SCE_SCRIPTOL_DEFAULT;
335 else
336 initStyle = styler.StyleAt(startPos-1);
337 }
338 }
339 int state = initStyle & 31;
340 int spaceFlags = 0;
341 int indentCurrent = styler.IndentAmount(lineCurrent, &spaceFlags, IsSolComment);
342 if (state == SCE_SCRIPTOL_TRIPLE)
343 indentCurrent |= SC_FOLDLEVELWHITEFLAG;
344 char chNext = styler[startPos];
345 for (Sci_Position i = startPos; i < lengthDoc; i++)
346 {
347 char ch = chNext;
348 chNext = styler.SafeGetCharAt(i + 1);
349 int style = styler.StyleAt(i) & 31;
350
351 if ((ch == '\r' && chNext != '\n') || (ch == '\n') || (i == lengthDoc))
352 {
353 int lev = indentCurrent;
354 int indentNext = styler.IndentAmount(lineCurrent + 1, &spaceFlags, IsSolComment);
355 if (style == SCE_SCRIPTOL_TRIPLE)
356 indentNext |= SC_FOLDLEVELWHITEFLAG;
357 if (!(indentCurrent & SC_FOLDLEVELWHITEFLAG))
358 {
359 // Only non whitespace lines can be headers
360 if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext & SC_FOLDLEVELNUMBERMASK))
361 {
362 lev |= SC_FOLDLEVELHEADERFLAG;
363 }
364 else if (indentNext & SC_FOLDLEVELWHITEFLAG)
365 {
366 // Line after is blank so check the next - maybe should continue further?
367 int spaceFlags2 = 0;
368 int indentNext2 = styler.IndentAmount(lineCurrent + 2, &spaceFlags2, IsSolComment);
369 if ((indentCurrent & SC_FOLDLEVELNUMBERMASK) < (indentNext2 & SC_FOLDLEVELNUMBERMASK))
370 {
371 lev |= SC_FOLDLEVELHEADERFLAG;
372 }
373 }
374 }
375 indentCurrent = indentNext;
376 styler.SetLevel(lineCurrent, lev);
377 lineCurrent++;
378 }
379 }
380}
381
382LexerModule lmScriptol(SCLEX_SCRIPTOL, ColouriseSolDoc, "scriptol", FoldSolDoc);
383