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