1// Scintilla source code edit control
2/** @file LexEScript.cxx
3 ** Lexer for ESCRIPT
4 **/
5// Copyright 2003 by Patrizio Bekerle (patrizio@bekerle.com)
6
7#include <stdlib.h>
8#include <string.h>
9#include <stdio.h>
10#include <stdarg.h>
11#include <assert.h>
12#include <ctype.h>
13
14#include <string>
15#include <string_view>
16
17#include "ILexer.h"
18#include "Scintilla.h"
19#include "SciLexer.h"
20
21#include "WordList.h"
22#include "LexAccessor.h"
23#include "Accessor.h"
24#include "StyleContext.h"
25#include "CharacterSet.h"
26#include "LexerModule.h"
27
28using namespace Lexilla;
29
30
31static inline bool IsAWordChar(const int ch) {
32 return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
33}
34
35static inline bool IsAWordStart(const int ch) {
36 return (ch < 0x80) && (isalnum(ch) || ch == '_');
37}
38
39
40
41static void ColouriseESCRIPTDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordlists[],
42 Accessor &styler) {
43
44 WordList &keywords = *keywordlists[0];
45 WordList &keywords2 = *keywordlists[1];
46 WordList &keywords3 = *keywordlists[2];
47
48 // Do not leak onto next line
49 /*if (initStyle == SCE_ESCRIPT_STRINGEOL)
50 initStyle = SCE_ESCRIPT_DEFAULT;*/
51
52 StyleContext sc(startPos, length, initStyle, styler);
53
54 bool caseSensitive = styler.GetPropertyInt("escript.case.sensitive", 0) != 0;
55
56 for (; sc.More(); sc.Forward()) {
57
58 /*if (sc.atLineStart && (sc.state == SCE_ESCRIPT_STRING)) {
59 // Prevent SCE_ESCRIPT_STRINGEOL from leaking back to previous line
60 sc.SetState(SCE_ESCRIPT_STRING);
61 }*/
62
63 // Handle line continuation generically.
64 if (sc.ch == '\\') {
65 if (sc.chNext == '\n' || sc.chNext == '\r') {
66 sc.Forward();
67 if (sc.ch == '\r' && sc.chNext == '\n') {
68 sc.Forward();
69 }
70 continue;
71 }
72 }
73
74 // Determine if the current state should terminate.
75 if (sc.state == SCE_ESCRIPT_OPERATOR || sc.state == SCE_ESCRIPT_BRACE) {
76 sc.SetState(SCE_ESCRIPT_DEFAULT);
77 } else if (sc.state == SCE_ESCRIPT_NUMBER) {
78 if (!IsADigit(sc.ch) || sc.ch != '.') {
79 sc.SetState(SCE_ESCRIPT_DEFAULT);
80 }
81 } else if (sc.state == SCE_ESCRIPT_IDENTIFIER) {
82 if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
83 char s[100];
84 if (caseSensitive) {
85 sc.GetCurrent(s, sizeof(s));
86 } else {
87 sc.GetCurrentLowered(s, sizeof(s));
88 }
89
90// sc.GetCurrentLowered(s, sizeof(s));
91
92 if (keywords.InList(s)) {
93 sc.ChangeState(SCE_ESCRIPT_WORD);
94 } else if (keywords2.InList(s)) {
95 sc.ChangeState(SCE_ESCRIPT_WORD2);
96 } else if (keywords3.InList(s)) {
97 sc.ChangeState(SCE_ESCRIPT_WORD3);
98 // sc.state = SCE_ESCRIPT_IDENTIFIER;
99 }
100 sc.SetState(SCE_ESCRIPT_DEFAULT);
101 }
102 } else if (sc.state == SCE_ESCRIPT_COMMENT) {
103 if (sc.Match('*', '/')) {
104 sc.Forward();
105 sc.ForwardSetState(SCE_ESCRIPT_DEFAULT);
106 }
107 } else if (sc.state == SCE_ESCRIPT_COMMENTDOC) {
108 if (sc.Match('*', '/')) {
109 sc.Forward();
110 sc.ForwardSetState(SCE_ESCRIPT_DEFAULT);
111 }
112 } else if (sc.state == SCE_ESCRIPT_COMMENTLINE) {
113 if (sc.atLineEnd) {
114 sc.SetState(SCE_ESCRIPT_DEFAULT);
115 }
116 } else if (sc.state == SCE_ESCRIPT_STRING) {
117 if (sc.ch == '\\') {
118 if (sc.chNext == '\"' || sc.chNext == '\\') {
119 sc.Forward();
120 }
121 } else if (sc.ch == '\"') {
122 sc.ForwardSetState(SCE_ESCRIPT_DEFAULT);
123 }
124 }
125
126 // Determine if a new state should be entered.
127 if (sc.state == SCE_ESCRIPT_DEFAULT) {
128 if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
129 sc.SetState(SCE_ESCRIPT_NUMBER);
130 } else if (IsAWordStart(sc.ch) || (sc.ch == '#')) {
131 sc.SetState(SCE_ESCRIPT_IDENTIFIER);
132 } else if (sc.Match('/', '*')) {
133 sc.SetState(SCE_ESCRIPT_COMMENT);
134 sc.Forward(); // Eat the * so it isn't used for the end of the comment
135 } else if (sc.Match('/', '/')) {
136 sc.SetState(SCE_ESCRIPT_COMMENTLINE);
137 } else if (sc.ch == '\"') {
138 sc.SetState(SCE_ESCRIPT_STRING);
139 //} else if (isoperator(static_cast<char>(sc.ch))) {
140 } else if (sc.ch == '+' || sc.ch == '-' || sc.ch == '*' || sc.ch == '/' || sc.ch == '=' || sc.ch == '<' || sc.ch == '>' || sc.ch == '&' || sc.ch == '|' || sc.ch == '!' || sc.ch == '?' || sc.ch == ':') {
141 sc.SetState(SCE_ESCRIPT_OPERATOR);
142 } else if (sc.ch == '{' || sc.ch == '}') {
143 sc.SetState(SCE_ESCRIPT_BRACE);
144 }
145 }
146
147 }
148 sc.Complete();
149}
150
151
152static int classifyFoldPointESCRIPT(const char* s, const char* prevWord) {
153 int lev = 0;
154 if (strcmp(prevWord, "end") == 0) return lev;
155 if ((strcmp(prevWord, "else") == 0 && strcmp(s, "if") == 0) || strcmp(s, "elseif") == 0)
156 return -1;
157
158 if (strcmp(s, "for") == 0 || strcmp(s, "foreach") == 0
159 || strcmp(s, "program") == 0 || strcmp(s, "function") == 0
160 || strcmp(s, "while") == 0 || strcmp(s, "case") == 0
161 || strcmp(s, "if") == 0 ) {
162 lev = 1;
163 } else if ( strcmp(s, "endfor") == 0 || strcmp(s, "endforeach") == 0
164 || strcmp(s, "endprogram") == 0 || strcmp(s, "endfunction") == 0
165 || strcmp(s, "endwhile") == 0 || strcmp(s, "endcase") == 0
166 || strcmp(s, "endif") == 0 ) {
167 lev = -1;
168 }
169
170 return lev;
171}
172
173
174static bool IsStreamCommentStyle(int style) {
175 return style == SCE_ESCRIPT_COMMENT ||
176 style == SCE_ESCRIPT_COMMENTDOC ||
177 style == SCE_ESCRIPT_COMMENTLINE;
178}
179
180static void FoldESCRIPTDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *[], Accessor &styler) {
181 //~ bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
182 // Do not know how to fold the comment at the moment.
183 bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
184 bool foldComment = true;
185 Sci_PositionU endPos = startPos + length;
186 int visibleChars = 0;
187 Sci_Position lineCurrent = styler.GetLine(startPos);
188 int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
189 int levelCurrent = levelPrev;
190 char chNext = styler[startPos];
191 int styleNext = styler.StyleAt(startPos);
192 int style = initStyle;
193
194 Sci_Position lastStart = 0;
195 char prevWord[32] = "";
196
197 for (Sci_PositionU i = startPos; i < endPos; i++) {
198 char ch = chNext;
199 chNext = styler.SafeGetCharAt(i + 1);
200 int stylePrev = style;
201 style = styleNext;
202 styleNext = styler.StyleAt(i + 1);
203 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
204
205
206 if (foldComment && IsStreamCommentStyle(style)) {
207 if (!IsStreamCommentStyle(stylePrev)) {
208 levelCurrent++;
209 } else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
210 // Comments don't end at end of line and the next character may be unstyled.
211 levelCurrent--;
212 }
213 }
214
215 if (foldComment && (style == SCE_ESCRIPT_COMMENTLINE)) {
216 if ((ch == '/') && (chNext == '/')) {
217 char chNext2 = styler.SafeGetCharAt(i + 2);
218 if (chNext2 == '{') {
219 levelCurrent++;
220 } else if (chNext2 == '}') {
221 levelCurrent--;
222 }
223 }
224 }
225
226 if (stylePrev == SCE_ESCRIPT_DEFAULT && style == SCE_ESCRIPT_WORD3)
227 {
228 // Store last word start point.
229 lastStart = i;
230 }
231
232 if (style == SCE_ESCRIPT_WORD3) {
233 if(iswordchar(ch) && !iswordchar(chNext)) {
234 char s[32];
235 Sci_PositionU j;
236 for(j = 0; ( j < 31 ) && ( j < i-lastStart+1 ); j++) {
237 s[j] = static_cast<char>(tolower(styler[lastStart + j]));
238 }
239 s[j] = '\0';
240 levelCurrent += classifyFoldPointESCRIPT(s, prevWord);
241 strcpy(prevWord, s);
242 }
243 }
244 if (atEOL) {
245 int lev = levelPrev;
246 if (visibleChars == 0 && foldCompact)
247 lev |= SC_FOLDLEVELWHITEFLAG;
248 if ((levelCurrent > levelPrev) && (visibleChars > 0))
249 lev |= SC_FOLDLEVELHEADERFLAG;
250 if (lev != styler.LevelAt(lineCurrent)) {
251 styler.SetLevel(lineCurrent, lev);
252 }
253 lineCurrent++;
254 levelPrev = levelCurrent;
255 visibleChars = 0;
256 strcpy(prevWord, "");
257 }
258
259 if (!isspacechar(ch))
260 visibleChars++;
261 }
262
263 // Fill in the real level of the next line, keeping the current flags as they will be filled in later
264 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
265 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
266}
267
268
269
270static const char * const ESCRIPTWordLists[] = {
271 "Primary keywords and identifiers",
272 "Intrinsic functions",
273 "Extended and user defined functions",
274 0,
275};
276
277LexerModule lmESCRIPT(SCLEX_ESCRIPT, ColouriseESCRIPTDoc, "escript", FoldESCRIPTDoc, ESCRIPTWordLists);
278