1// Scintilla source code edit control
2/** @file LexBaan.cxx
3** Lexer for Baan.
4** Based heavily on LexCPP.cxx
5**/
6// Copyright 2001- by Vamsi Potluru <vamsi@who.net> & Praveen Ambekar <ambekarpraveen@yahoo.com>
7// Maintainer Email: oirfeodent@yahoo.co.in
8// The License.txt file describes the conditions under which this software may be distributed.
9
10// C standard library
11#include <stdlib.h>
12#include <string.h>
13
14// C++ wrappers of C standard library
15#include <cassert>
16
17// C++ standard library
18#include <string>
19#include <string_view>
20#include <map>
21#include <functional>
22
23// Scintilla headers
24
25// Non-platform-specific headers
26
27// include
28#include "ILexer.h"
29#include "Scintilla.h"
30#include "SciLexer.h"
31
32// lexlib
33#include "WordList.h"
34#include "LexAccessor.h"
35#include "StyleContext.h"
36#include "CharacterSet.h"
37#include "LexerModule.h"
38#include "OptionSet.h"
39#include "DefaultLexer.h"
40
41using namespace Scintilla;
42using namespace Lexilla;
43
44namespace {
45// Use an unnamed namespace to protect the functions and classes from name conflicts
46
47// Options used for LexerBaan
48struct OptionsBaan {
49 bool fold;
50 bool foldComment;
51 bool foldPreprocessor;
52 bool foldCompact;
53 bool baanFoldSyntaxBased;
54 bool baanFoldKeywordsBased;
55 bool baanFoldSections;
56 bool baanFoldInnerLevel;
57 bool baanStylingWithinPreprocessor;
58 OptionsBaan() {
59 fold = false;
60 foldComment = false;
61 foldPreprocessor = false;
62 foldCompact = false;
63 baanFoldSyntaxBased = false;
64 baanFoldKeywordsBased = false;
65 baanFoldSections = false;
66 baanFoldInnerLevel = false;
67 baanStylingWithinPreprocessor = false;
68 }
69};
70
71const char *const baanWordLists[] = {
72 "Baan & BaanSQL Reserved Keywords ",
73 "Baan Standard functions",
74 "Baan Functions Abridged",
75 "Baan Main Sections ",
76 "Baan Sub Sections",
77 "PreDefined Variables",
78 "PreDefined Attributes",
79 "Enumerates",
80 0,
81};
82
83struct OptionSetBaan : public OptionSet<OptionsBaan> {
84 OptionSetBaan() {
85 DefineProperty("fold", &OptionsBaan::fold);
86
87 DefineProperty("fold.comment", &OptionsBaan::foldComment);
88
89 DefineProperty("fold.preprocessor", &OptionsBaan::foldPreprocessor);
90
91 DefineProperty("fold.compact", &OptionsBaan::foldCompact);
92
93 DefineProperty("fold.baan.syntax.based", &OptionsBaan::baanFoldSyntaxBased,
94 "Set this property to 0 to disable syntax based folding, which is folding based on '{' & '('.");
95
96 DefineProperty("fold.baan.keywords.based", &OptionsBaan::baanFoldKeywordsBased,
97 "Set this property to 0 to disable keywords based folding, which is folding based on "
98 " for, if, on (case), repeat, select, while and fold ends based on endfor, endif, endcase, until, endselect, endwhile respectively."
99 "Also folds declarations which are grouped together.");
100
101 DefineProperty("fold.baan.sections", &OptionsBaan::baanFoldSections,
102 "Set this property to 0 to disable folding of Main Sections as well as Sub Sections.");
103
104 DefineProperty("fold.baan.inner.level", &OptionsBaan::baanFoldInnerLevel,
105 "Set this property to 1 to enable folding of inner levels of select statements."
106 "Disabled by default. case and if statements are also eligible" );
107
108 DefineProperty("lexer.baan.styling.within.preprocessor", &OptionsBaan::baanStylingWithinPreprocessor,
109 "For Baan code, determines whether all preprocessor code is styled in the "
110 "preprocessor style (0, the default) or only from the initial # to the end "
111 "of the command word(1).");
112
113 DefineWordListSets(baanWordLists);
114 }
115};
116
117static inline bool IsAWordChar(const int ch) {
118 return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_' || ch == '$');
119}
120
121static inline bool IsAnOperator(int ch) {
122 if (IsAlphaNumeric(ch))
123 return false;
124 if (ch == '#' || ch == '^' || ch == '&' || ch == '*' ||
125 ch == '(' || ch == ')' || ch == '-' || ch == '+' ||
126 ch == '=' || ch == '|' || ch == '{' || ch == '}' ||
127 ch == '[' || ch == ']' || ch == ':' || ch == ';' ||
128 ch == '<' || ch == '>' || ch == ',' || ch == '/' ||
129 ch == '?' || ch == '!' || ch == '"' || ch == '~' ||
130 ch == '\\')
131 return true;
132 return false;
133}
134
135static inline int IsAnyOtherIdentifier(char *s, Sci_Position sLength) {
136
137 /* IsAnyOtherIdentifier uses standard templates used in baan.
138 The matching template is shown as comments just above the return condition.
139 ^ - refers to any character [a-z].
140 # - refers to any number [0-9].
141 Other characters shown are compared as is.
142 Tried implementing with Regex... it was too complicated for me.
143 Any other implementation suggestion welcome.
144 */
145 switch (sLength) {
146 case 8:
147 if (isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
148 //^^^^^###
149 return(SCE_BAAN_TABLEDEF);
150 }
151 break;
152 case 9:
153 if (s[0] == 't' && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && isalpha(s[5]) && IsADigit(s[6]) && IsADigit(s[7]) && IsADigit(s[8])) {
154 //t^^^^^###
155 return(SCE_BAAN_TABLEDEF);
156 }
157 else if (s[8] == '.' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
158 //^^^^^###.
159 return(SCE_BAAN_TABLESQL);
160 }
161 break;
162 case 13:
163 if (s[8] == '.' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
164 //^^^^^###.****
165 return(SCE_BAAN_TABLESQL);
166 }
167 else if (s[0] == 'r' && s[1] == 'c' && s[2] == 'd' && s[3] == '.' && s[4] == 't' && isalpha(s[5]) && isalpha(s[6]) && isalpha(s[7]) && isalpha(s[8]) && isalpha(s[9]) && IsADigit(s[10]) && IsADigit(s[11]) && IsADigit(s[12])) {
168 //rcd.t^^^^^###
169 return(SCE_BAAN_TABLEDEF);
170 }
171 break;
172 case 14:
173 case 15:
174 if (s[8] == '.' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
175 if (s[13] != ':') {
176 //^^^^^###.******
177 return(SCE_BAAN_TABLESQL);
178 }
179 }
180 break;
181 case 16:
182 case 17:
183 if (s[8] == '.' && s[9] == '_' && s[10] == 'i' && s[11] == 'n' && s[12] == 'd' && s[13] == 'e' && s[14] == 'x' && IsADigit(s[15]) && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
184 //^^^^^###._index##
185 return(SCE_BAAN_TABLEDEF);
186 }
187 else if (s[8] == '.' && s[9] == '_' && s[10] == 'c' && s[11] == 'o' && s[12] == 'm' && s[13] == 'p' && s[14] == 'n' && s[15] == 'r' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[5]) && IsADigit(s[6]) && IsADigit(s[7])) {
188 //^^^^^###._compnr
189 return(SCE_BAAN_TABLEDEF);
190 }
191 break;
192 default:
193 break;
194 }
195 if (sLength > 14 && s[5] == '.' && s[6] == 'd' && s[7] == 'l' && s[8] == 'l' && s[13] == '.' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && IsADigit(s[9]) && IsADigit(s[10]) && IsADigit(s[11]) && IsADigit(s[12])) {
196 //^^^^^.dll####.
197 return(SCE_BAAN_FUNCTION);
198 }
199 else if (sLength > 15 && s[2] == 'i' && s[3] == 'n' && s[4] == 't' && s[5] == '.' && s[6] == 'd' && s[7] == 'l' && s[8] == 'l' && isalpha(s[0]) && isalpha(s[1]) && isalpha(s[9]) && isalpha(s[10]) && isalpha(s[11]) && isalpha(s[12]) && isalpha(s[13])) {
200 //^^int.dll^^^^^.
201 return(SCE_BAAN_FUNCTION);
202 }
203 else if (sLength > 11 && s[0] == 'i' && s[10] == '.' && isalpha(s[1]) && isalpha(s[2]) && isalpha(s[3]) && isalpha(s[4]) && isalpha(s[5]) && IsADigit(s[6]) && IsADigit(s[7]) && IsADigit(s[8]) && IsADigit(s[9])) {
204 //i^^^^^####.
205 return(SCE_BAAN_FUNCTION);
206 }
207
208 return(SCE_BAAN_DEFAULT);
209}
210
211static bool IsCommentLine(Sci_Position line, LexAccessor &styler) {
212 Sci_Position pos = styler.LineStart(line);
213 Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
214 for (Sci_Position i = pos; i < eol_pos; i++) {
215 char ch = styler[i];
216 int style = styler.StyleAt(i);
217 if (ch == '|' && style == SCE_BAAN_COMMENT)
218 return true;
219 else if (!IsASpaceOrTab(ch))
220 return false;
221 }
222 return false;
223}
224
225static bool IsPreProcLine(Sci_Position line, LexAccessor &styler) {
226 Sci_Position pos = styler.LineStart(line);
227 Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
228 for (Sci_Position i = pos; i < eol_pos; i++) {
229 char ch = styler[i];
230 int style = styler.StyleAt(i);
231 if (ch == '#' && style == SCE_BAAN_PREPROCESSOR) {
232 if (styler.Match(i, "#elif") || styler.Match(i, "#else") || styler.Match(i, "#endif")
233 || styler.Match(i, "#if") || styler.Match(i, "#ifdef") || styler.Match(i, "#ifndef"))
234 // Above PreProcessors has a seperate fold mechanism.
235 return false;
236 else
237 return true;
238 }
239 else if (ch == '^')
240 return true;
241 else if (!IsASpaceOrTab(ch))
242 return false;
243 }
244 return false;
245}
246
247static int mainOrSubSectionLine(Sci_Position line, LexAccessor &styler) {
248 Sci_Position pos = styler.LineStart(line);
249 Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
250 for (Sci_Position i = pos; i < eol_pos; i++) {
251 char ch = styler[i];
252 int style = styler.StyleAt(i);
253 if (style == SCE_BAAN_WORD5 || style == SCE_BAAN_WORD4)
254 return style;
255 else if (IsASpaceOrTab(ch))
256 continue;
257 else
258 break;
259 }
260 return 0;
261}
262
263static bool priorSectionIsSubSection(Sci_Position line, LexAccessor &styler){
264 while (line > 0) {
265 Sci_Position pos = styler.LineStart(line);
266 Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
267 for (Sci_Position i = pos; i < eol_pos; i++) {
268 char ch = styler[i];
269 int style = styler.StyleAt(i);
270 if (style == SCE_BAAN_WORD4)
271 return true;
272 else if (style == SCE_BAAN_WORD5)
273 return false;
274 else if (IsASpaceOrTab(ch))
275 continue;
276 else
277 break;
278 }
279 line--;
280 }
281 return false;
282}
283
284static bool nextSectionIsSubSection(Sci_Position line, LexAccessor &styler) {
285 while (line > 0) {
286 Sci_Position pos = styler.LineStart(line);
287 Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
288 for (Sci_Position i = pos; i < eol_pos; i++) {
289 char ch = styler[i];
290 int style = styler.StyleAt(i);
291 if (style == SCE_BAAN_WORD4)
292 return true;
293 else if (style == SCE_BAAN_WORD5)
294 return false;
295 else if (IsASpaceOrTab(ch))
296 continue;
297 else
298 break;
299 }
300 line++;
301 }
302 return false;
303}
304
305static bool IsDeclarationLine(Sci_Position line, LexAccessor &styler) {
306 Sci_Position pos = styler.LineStart(line);
307 Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
308 for (Sci_Position i = pos; i < eol_pos; i++) {
309 char ch = styler[i];
310 int style = styler.StyleAt(i);
311 if (style == SCE_BAAN_WORD) {
312 if (styler.Match(i, "table") || styler.Match(i, "extern") || styler.Match(i, "long")
313 || styler.Match(i, "double") || styler.Match(i, "boolean") || styler.Match(i, "string")
314 || styler.Match(i, "domain")) {
315 for (Sci_Position j = eol_pos; j > pos; j--) {
316 int styleFromEnd = styler.StyleAt(j);
317 if (styleFromEnd == SCE_BAAN_COMMENT)
318 continue;
319 else if (IsASpace(styler[j]))
320 continue;
321 else if (styler[j] != ',')
322 //Above conditions ensures, Declaration is not part of any function parameters.
323 return true;
324 else
325 return false;
326 }
327 }
328 else
329 return false;
330 }
331 else if (!IsASpaceOrTab(ch))
332 return false;
333 }
334 return false;
335}
336
337static bool IsInnerLevelFold(Sci_Position line, LexAccessor &styler) {
338 Sci_Position pos = styler.LineStart(line);
339 Sci_Position eol_pos = styler.LineStart(line + 1) - 1;
340 for (Sci_Position i = pos; i < eol_pos; i++) {
341 char ch = styler[i];
342 int style = styler.StyleAt(i);
343 if (style == SCE_BAAN_WORD && (styler.Match(i, "else" ) || styler.Match(i, "case")
344 || styler.Match(i, "default") || styler.Match(i, "selectdo") || styler.Match(i, "selecteos")
345 || styler.Match(i, "selectempty") || styler.Match(i, "selecterror")))
346 return true;
347 else if (IsASpaceOrTab(ch))
348 continue;
349 else
350 return false;
351 }
352 return false;
353}
354
355static inline bool wordInArray(const std::string& value, std::string *array, int length)
356{
357 for (int i = 0; i < length; i++)
358 {
359 if (value == array[i])
360 {
361 return true;
362 }
363 }
364
365 return false;
366}
367
368class WordListAbridged : public WordList {
369public:
370 WordListAbridged() {
371 kwAbridged = false;
372 kwHasSection = false;
373 };
374 ~WordListAbridged() {
375 Clear();
376 };
377 bool kwAbridged;
378 bool kwHasSection;
379 bool Contains(const char *s) {
380 return kwAbridged ? InListAbridged(s, '~') : InList(s);
381 };
382};
383
384}
385
386class LexerBaan : public DefaultLexer {
387 WordListAbridged keywords;
388 WordListAbridged keywords2;
389 WordListAbridged keywords3;
390 WordListAbridged keywords4;
391 WordListAbridged keywords5;
392 WordListAbridged keywords6;
393 WordListAbridged keywords7;
394 WordListAbridged keywords8;
395 WordListAbridged keywords9;
396 OptionsBaan options;
397 OptionSetBaan osBaan;
398public:
399 LexerBaan() : DefaultLexer("baan", SCLEX_BAAN) {
400 }
401
402 virtual ~LexerBaan() {
403 }
404
405 int SCI_METHOD Version() const override {
406 return lvRelease5;
407 }
408
409 void SCI_METHOD Release() override {
410 delete this;
411 }
412
413 const char * SCI_METHOD PropertyNames() override {
414 return osBaan.PropertyNames();
415 }
416
417 int SCI_METHOD PropertyType(const char * name) override {
418 return osBaan.PropertyType(name);
419 }
420
421 const char * SCI_METHOD DescribeProperty(const char * name) override {
422 return osBaan.DescribeProperty(name);
423 }
424
425 Sci_Position SCI_METHOD PropertySet(const char *key, const char *val) override;
426
427 const char * SCI_METHOD PropertyGet(const char *key) override {
428 return osBaan.PropertyGet(key);
429 }
430
431 const char * SCI_METHOD DescribeWordListSets() override {
432 return osBaan.DescribeWordListSets();
433 }
434
435 Sci_Position SCI_METHOD WordListSet(int n, const char *wl) override;
436
437 void SCI_METHOD Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
438
439 void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) override;
440
441 void * SCI_METHOD PrivateCall(int, void *) override {
442 return NULL;
443 }
444
445 static ILexer5 * LexerFactoryBaan() {
446 return new LexerBaan();
447 }
448};
449
450Sci_Position SCI_METHOD LexerBaan::PropertySet(const char *key, const char *val) {
451 if (osBaan.PropertySet(&options, key, val)) {
452 return 0;
453 }
454 return -1;
455}
456
457Sci_Position SCI_METHOD LexerBaan::WordListSet(int n, const char *wl) {
458 WordListAbridged *WordListAbridgedN = 0;
459 switch (n) {
460 case 0:
461 WordListAbridgedN = &keywords;
462 break;
463 case 1:
464 WordListAbridgedN = &keywords2;
465 break;
466 case 2:
467 WordListAbridgedN = &keywords3;
468 break;
469 case 3:
470 WordListAbridgedN = &keywords4;
471 break;
472 case 4:
473 WordListAbridgedN = &keywords5;
474 break;
475 case 5:
476 WordListAbridgedN = &keywords6;
477 break;
478 case 6:
479 WordListAbridgedN = &keywords7;
480 break;
481 case 7:
482 WordListAbridgedN = &keywords8;
483 break;
484 case 8:
485 WordListAbridgedN = &keywords9;
486 break;
487 }
488 Sci_Position firstModification = -1;
489 if (WordListAbridgedN) {
490 WordListAbridged wlNew;
491 wlNew.Set(wl);
492 if (*WordListAbridgedN != wlNew) {
493 WordListAbridgedN->Set(wl);
494 WordListAbridgedN->kwAbridged = strchr(wl, '~') != NULL;
495 WordListAbridgedN->kwHasSection = strchr(wl, ':') != NULL;
496
497 firstModification = 0;
498 }
499 }
500 return firstModification;
501}
502
503void SCI_METHOD LexerBaan::Lex(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
504
505 if (initStyle == SCE_BAAN_STRINGEOL) // Does not leak onto next line
506 initStyle = SCE_BAAN_DEFAULT;
507
508 int visibleChars = 0;
509 bool lineHasDomain = false;
510 bool lineHasFunction = false;
511 bool lineHasPreProc = false;
512 bool lineIgnoreString = false;
513 bool lineHasDefines = false;
514 bool numberIsHex = false;
515 char word[1000];
516 int wordlen = 0;
517
518 std::string preProcessorTags[13] = { "#context_off", "#context_on",
519 "#define", "#elif", "#else", "#endif",
520 "#ident", "#if", "#ifdef", "#ifndef",
521 "#include", "#pragma", "#undef" };
522 LexAccessor styler(pAccess);
523 StyleContext sc(startPos, length, initStyle, styler);
524
525 for (; sc.More(); sc.Forward()) {
526
527 // Determine if the current state should terminate.
528 switch (sc.state) {
529 case SCE_BAAN_OPERATOR:
530 sc.SetState(SCE_BAAN_DEFAULT);
531 break;
532 case SCE_BAAN_NUMBER:
533 if (IsASpaceOrTab(sc.ch) || sc.ch == '\r' || sc.ch == '\n' || IsAnOperator(sc.ch)) {
534 sc.SetState(SCE_BAAN_DEFAULT);
535 }
536 else if ((numberIsHex && !(MakeLowerCase(sc.ch) == 'x' || MakeLowerCase(sc.ch) == 'e' ||
537 IsADigit(sc.ch, 16) || sc.ch == '.' || sc.ch == '-' || sc.ch == '+')) ||
538 (!numberIsHex && !(MakeLowerCase(sc.ch) == 'e' || IsADigit(sc.ch)
539 || sc.ch == '.' || sc.ch == '-' || sc.ch == '+'))) {
540 // check '-' for possible -10e-5. Add '+' as well.
541 numberIsHex = false;
542 sc.ChangeState(SCE_BAAN_IDENTIFIER);
543 sc.SetState(SCE_BAAN_DEFAULT);
544 }
545 break;
546 case SCE_BAAN_IDENTIFIER:
547 if (!IsAWordChar(sc.ch)) {
548 char s[1000];
549 char s1[1000];
550 sc.GetCurrentLowered(s, sizeof(s));
551 if (sc.ch == ':') {
552 memcpy(s1, s, sizeof(s));
553 s1[sc.LengthCurrent()] = sc.ch;
554 s1[sc.LengthCurrent() + 1] = '\0';
555 }
556 if ((keywords.kwHasSection && (sc.ch == ':')) ? keywords.Contains(s1) : keywords.Contains(s)) {
557 sc.ChangeState(SCE_BAAN_WORD);
558 if (0 == strcmp(s, "domain")) {
559 lineHasDomain = true;
560 }
561 else if (0 == strcmp(s, "function")) {
562 lineHasFunction = true;
563 }
564 }
565 else if (lineHasDomain) {
566 sc.ChangeState(SCE_BAAN_DOMDEF);
567 lineHasDomain = false;
568 }
569 else if (lineHasFunction) {
570 sc.ChangeState(SCE_BAAN_FUNCDEF);
571 lineHasFunction = false;
572 }
573 else if ((keywords2.kwHasSection && (sc.ch == ':')) ? keywords2.Contains(s1) : keywords2.Contains(s)) {
574 sc.ChangeState(SCE_BAAN_WORD2);
575 }
576 else if ((keywords3.kwHasSection && (sc.ch == ':')) ? keywords3.Contains(s1) : keywords3.Contains(s)) {
577 if (sc.ch == '(')
578 sc.ChangeState(SCE_BAAN_WORD3);
579 else
580 sc.ChangeState(SCE_BAAN_IDENTIFIER);
581 }
582 else if ((keywords4.kwHasSection && (sc.ch == ':')) ? keywords4.Contains(s1) : keywords4.Contains(s)) {
583 sc.ChangeState(SCE_BAAN_WORD4);
584 }
585 else if ((keywords5.kwHasSection && (sc.ch == ':')) ? keywords5.Contains(s1) : keywords5.Contains(s)) {
586 sc.ChangeState(SCE_BAAN_WORD5);
587 }
588 else if ((keywords6.kwHasSection && (sc.ch == ':')) ? keywords6.Contains(s1) : keywords6.Contains(s)) {
589 sc.ChangeState(SCE_BAAN_WORD6);
590 }
591 else if ((keywords7.kwHasSection && (sc.ch == ':')) ? keywords7.Contains(s1) : keywords7.Contains(s)) {
592 sc.ChangeState(SCE_BAAN_WORD7);
593 }
594 else if ((keywords8.kwHasSection && (sc.ch == ':')) ? keywords8.Contains(s1) : keywords8.Contains(s)) {
595 sc.ChangeState(SCE_BAAN_WORD8);
596 }
597 else if ((keywords9.kwHasSection && (sc.ch == ':')) ? keywords9.Contains(s1) : keywords9.Contains(s)) {
598 sc.ChangeState(SCE_BAAN_WORD9);
599 }
600 else if (lineHasPreProc) {
601 sc.ChangeState(SCE_BAAN_OBJECTDEF);
602 lineHasPreProc = false;
603 }
604 else if (lineHasDefines) {
605 sc.ChangeState(SCE_BAAN_DEFINEDEF);
606 lineHasDefines = false;
607 }
608 else {
609 int state = IsAnyOtherIdentifier(s, sc.LengthCurrent());
610 if (state > 0) {
611 sc.ChangeState(state);
612 }
613 }
614 sc.SetState(SCE_BAAN_DEFAULT);
615 }
616 break;
617 case SCE_BAAN_PREPROCESSOR:
618 if (options.baanStylingWithinPreprocessor) {
619 if (IsASpace(sc.ch) || IsAnOperator(sc.ch)) {
620 sc.SetState(SCE_BAAN_DEFAULT);
621 }
622 }
623 else {
624 if (sc.atLineEnd && (sc.chNext != '^')) {
625 sc.SetState(SCE_BAAN_DEFAULT);
626 }
627 }
628 break;
629 case SCE_BAAN_COMMENT:
630 if (sc.ch == '\r' || sc.ch == '\n') {
631 sc.SetState(SCE_BAAN_DEFAULT);
632 }
633 break;
634 case SCE_BAAN_COMMENTDOC:
635 if (sc.MatchIgnoreCase("enddllusage")) {
636 for (unsigned int i = 0; i < 10; i++) {
637 sc.Forward();
638 }
639 sc.ForwardSetState(SCE_BAAN_DEFAULT);
640 }
641 else if (sc.MatchIgnoreCase("endfunctionusage")) {
642 for (unsigned int i = 0; i < 15; i++) {
643 sc.Forward();
644 }
645 sc.ForwardSetState(SCE_BAAN_DEFAULT);
646 }
647 break;
648 case SCE_BAAN_STRING:
649 if (sc.ch == '\"') {
650 sc.ForwardSetState(SCE_BAAN_DEFAULT);
651 }
652 else if ((sc.atLineEnd) && (sc.chNext != '^')) {
653 sc.ChangeState(SCE_BAAN_STRINGEOL);
654 sc.ForwardSetState(SCE_BAAN_DEFAULT);
655 visibleChars = 0;
656 }
657 break;
658 }
659
660 // Determine if a new state should be entered.
661 if (sc.state == SCE_BAAN_DEFAULT) {
662 if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))
663 || ((sc.ch == '-' || sc.ch == '+') && (IsADigit(sc.chNext) || sc.chNext == '.'))
664 || (MakeLowerCase(sc.ch) == 'e' && (IsADigit(sc.chNext) || sc.chNext == '+' || sc.chNext == '-'))) {
665 if ((sc.ch == '0' && MakeLowerCase(sc.chNext) == 'x') ||
666 ((sc.ch == '-' || sc.ch == '+') && sc.chNext == '0' && MakeLowerCase(sc.GetRelativeCharacter(2)) == 'x')){
667 numberIsHex = true;
668 }
669 sc.SetState(SCE_BAAN_NUMBER);
670 }
671 else if (sc.MatchIgnoreCase("dllusage") || sc.MatchIgnoreCase("functionusage")) {
672 sc.SetState(SCE_BAAN_COMMENTDOC);
673 do {
674 sc.Forward();
675 } while ((!sc.atLineEnd) && sc.More());
676 }
677 else if (iswordstart(sc.ch)) {
678 sc.SetState(SCE_BAAN_IDENTIFIER);
679 }
680 else if (sc.Match('|')) {
681 sc.SetState(SCE_BAAN_COMMENT);
682 }
683 else if (sc.ch == '\"' && !(lineIgnoreString)) {
684 sc.SetState(SCE_BAAN_STRING);
685 }
686 else if (sc.ch == '#' && visibleChars == 0) {
687 // Preprocessor commands are alone on their line
688 sc.SetState(SCE_BAAN_PREPROCESSOR);
689 word[0] = '\0';
690 wordlen = 0;
691 while (sc.More() && !(IsASpace(sc.chNext) || IsAnOperator(sc.chNext))) {
692 sc.Forward();
693 wordlen++;
694 }
695 sc.GetCurrentLowered(word, sizeof(word));
696 if (!sc.atLineEnd) {
697 word[wordlen++] = sc.ch;
698 word[wordlen++] = '\0';
699 }
700 if (!wordInArray(word, preProcessorTags, 13))
701 // Colorise only preprocessor built in Baan.
702 sc.ChangeState(SCE_BAAN_IDENTIFIER);
703 if (strcmp(word, "#pragma") == 0 || strcmp(word, "#include") == 0) {
704 lineHasPreProc = true;
705 lineIgnoreString = true;
706 }
707 else if (strcmp(word, "#define") == 0 || strcmp(word, "#undef") == 0 ||
708 strcmp(word, "#ifdef") == 0 || strcmp(word, "#if") == 0 || strcmp(word, "#ifndef") == 0) {
709 lineHasDefines = true;
710 lineIgnoreString = false;
711 }
712 }
713 else if (IsAnOperator(static_cast<char>(sc.ch))) {
714 sc.SetState(SCE_BAAN_OPERATOR);
715 }
716 }
717
718 if (sc.atLineEnd) {
719 // Reset states to begining of colourise so no surprises
720 // if different sets of lines lexed.
721 visibleChars = 0;
722 lineHasDomain = false;
723 lineHasFunction = false;
724 lineHasPreProc = false;
725 lineIgnoreString = false;
726 lineHasDefines = false;
727 numberIsHex = false;
728 }
729 if (!IsASpace(sc.ch)) {
730 visibleChars++;
731 }
732 }
733 sc.Complete();
734}
735
736void SCI_METHOD LexerBaan::Fold(Sci_PositionU startPos, Sci_Position length, int initStyle, IDocument *pAccess) {
737 if (!options.fold)
738 return;
739
740 char word[100];
741 int wordlen = 0;
742 bool foldStart = true;
743 bool foldNextSelect = true;
744 bool afterFunctionSection = false;
745 bool beforeDeclarationSection = false;
746 int currLineStyle = 0;
747 int nextLineStyle = 0;
748
749 std::string startTags[6] = { "for", "if", "on", "repeat", "select", "while" };
750 std::string endTags[6] = { "endcase", "endfor", "endif", "endselect", "endwhile", "until" };
751 std::string selectCloseTags[5] = { "selectdo", "selecteos", "selectempty", "selecterror", "endselect" };
752
753 LexAccessor styler(pAccess);
754 Sci_PositionU endPos = startPos + length;
755 int visibleChars = 0;
756 Sci_Position lineCurrent = styler.GetLine(startPos);
757
758 // Backtrack to previous line in case need to fix its fold status
759 if (startPos > 0) {
760 if (lineCurrent > 0) {
761 lineCurrent--;
762 startPos = styler.LineStart(lineCurrent);
763 }
764 }
765
766 int levelPrev = SC_FOLDLEVELBASE;
767 if (lineCurrent > 0)
768 levelPrev = styler.LevelAt(lineCurrent - 1) >> 16;
769 int levelCurrent = levelPrev;
770 char chNext = styler[startPos];
771 int style = initStyle;
772 int styleNext = styler.StyleAt(startPos);
773
774 for (Sci_PositionU i = startPos; i < endPos; i++) {
775 char ch = chNext;
776 chNext = styler.SafeGetCharAt(i + 1);
777 style = styleNext;
778 styleNext = styler.StyleAt(i + 1);
779 int stylePrev = (i) ? styler.StyleAt(i - 1) : SCE_BAAN_DEFAULT;
780 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
781
782 // Comment folding
783 if (options.foldComment && style == SCE_BAAN_COMMENTDOC) {
784 if (style != stylePrev) {
785 levelCurrent++;
786 }
787 else if (style != styleNext) {
788 levelCurrent--;
789 }
790 }
791 if (options.foldComment && atEOL && IsCommentLine(lineCurrent, styler)) {
792 if (!IsCommentLine(lineCurrent - 1, styler)
793 && IsCommentLine(lineCurrent + 1, styler))
794 levelCurrent++;
795 else if (IsCommentLine(lineCurrent - 1, styler)
796 && !IsCommentLine(lineCurrent + 1, styler))
797 levelCurrent--;
798 }
799 // PreProcessor Folding
800 if (options.foldPreprocessor) {
801 if (atEOL && IsPreProcLine(lineCurrent, styler)) {
802 if (!IsPreProcLine(lineCurrent - 1, styler)
803 && IsPreProcLine(lineCurrent + 1, styler))
804 levelCurrent++;
805 else if (IsPreProcLine(lineCurrent - 1, styler)
806 && !IsPreProcLine(lineCurrent + 1, styler))
807 levelCurrent--;
808 }
809 else if (style == SCE_BAAN_PREPROCESSOR) {
810 // folds #ifdef/#if/#ifndef - they are not part of the IsPreProcLine folding.
811 if (ch == '#') {
812 if (styler.Match(i, "#ifdef") || styler.Match(i, "#if") || styler.Match(i, "#ifndef")
813 || styler.Match(i, "#context_on"))
814 levelCurrent++;
815 else if (styler.Match(i, "#endif") || styler.Match(i, "#context_off"))
816 levelCurrent--;
817 }
818 }
819 }
820 //Syntax Folding
821 if (options.baanFoldSyntaxBased && (style == SCE_BAAN_OPERATOR)) {
822 if (ch == '{' || ch == '(') {
823 levelCurrent++;
824 }
825 else if (ch == '}' || ch == ')') {
826 levelCurrent--;
827 }
828 }
829 //Keywords Folding
830 if (options.baanFoldKeywordsBased) {
831 if (atEOL && IsDeclarationLine(lineCurrent, styler)) {
832 if (!IsDeclarationLine(lineCurrent - 1, styler)
833 && IsDeclarationLine(lineCurrent + 1, styler))
834 levelCurrent++;
835 else if (IsDeclarationLine(lineCurrent - 1, styler)
836 && !IsDeclarationLine(lineCurrent + 1, styler))
837 levelCurrent--;
838 }
839 else if (style == SCE_BAAN_WORD) {
840 word[wordlen++] = static_cast<char>(MakeLowerCase(ch));
841 if (wordlen == 100) { // prevent overflow
842 word[0] = '\0';
843 wordlen = 1;
844 }
845 if (styleNext != SCE_BAAN_WORD) {
846 word[wordlen] = '\0';
847 wordlen = 0;
848 if (strcmp(word, "for") == 0) {
849 Sci_PositionU j = i + 1;
850 while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
851 j++;
852 }
853 if (styler.Match(j, "update")) {
854 // Means this is a "for update" used by Select which is already folded.
855 foldStart = false;
856 }
857 }
858 else if (strcmp(word, "on") == 0) {
859 Sci_PositionU j = i + 1;
860 while ((j < endPos) && IsASpaceOrTab(styler.SafeGetCharAt(j))) {
861 j++;
862 }
863 if (!styler.Match(j, "case")) {
864 // Means this is not a "on Case" statement... could be "on" used by index.
865 foldStart = false;
866 }
867 }
868 else if (strcmp(word, "select") == 0) {
869 if (foldNextSelect) {
870 // Next Selects are sub-clause till reach of selectCloseTags[] array.
871 foldNextSelect = false;
872 foldStart = true;
873 }
874 else {
875 foldNextSelect = false;
876 foldStart = false;
877 }
878 }
879 else if (wordInArray(word, selectCloseTags, 5)) {
880 // select clause ends, next select clause can be folded.
881 foldNextSelect = true;
882 foldStart = true;
883 }
884 else {
885 foldStart = true;
886 }
887 if (foldStart) {
888 if (wordInArray(word, startTags, 6)) {
889 levelCurrent++;
890 }
891 else if (wordInArray(word, endTags, 6)) {
892 levelCurrent--;
893 }
894 }
895 }
896 }
897 }
898 // Fold inner level of if/select/case statements
899 if (options.baanFoldInnerLevel && atEOL) {
900 bool currLineInnerLevel = IsInnerLevelFold(lineCurrent, styler);
901 bool nextLineInnerLevel = IsInnerLevelFold(lineCurrent + 1, styler);
902 if (currLineInnerLevel && currLineInnerLevel != nextLineInnerLevel) {
903 levelCurrent++;
904 }
905 else if (nextLineInnerLevel && nextLineInnerLevel != currLineInnerLevel) {
906 levelCurrent--;
907 }
908 }
909 // Section Foldings.
910 // One way of implementing Section Foldings, as there is no END markings of sections.
911 // first section ends on the previous line of next section.
912 // Re-written whole folding to accomodate this.
913 if (options.baanFoldSections && atEOL) {
914 currLineStyle = mainOrSubSectionLine(lineCurrent, styler);
915 nextLineStyle = mainOrSubSectionLine(lineCurrent + 1, styler);
916 if (currLineStyle != 0 && currLineStyle != nextLineStyle) {
917 if (levelCurrent < levelPrev)
918 --levelPrev;
919 for (Sci_Position j = styler.LineStart(lineCurrent); j < styler.LineStart(lineCurrent + 1) - 1; j++) {
920 if (IsASpaceOrTab(styler[j]))
921 continue;
922 else if (styler.StyleAt(j) == SCE_BAAN_WORD5) {
923 if (styler.Match(j, "functions:")) {
924 // Means functions: is the end of MainSections.
925 // Nothing to fold after this.
926 afterFunctionSection = true;
927 break;
928 }
929 else {
930 afterFunctionSection = false;
931 break;
932 }
933 }
934 else {
935 afterFunctionSection = false;
936 break;
937 }
938 }
939 if (!afterFunctionSection)
940 levelCurrent++;
941 }
942 else if (nextLineStyle != 0 && currLineStyle != nextLineStyle
943 && (priorSectionIsSubSection(lineCurrent -1 ,styler)
944 || !nextSectionIsSubSection(lineCurrent + 1, styler))) {
945 for (Sci_Position j = styler.LineStart(lineCurrent + 1); j < styler.LineStart(lineCurrent + 1 + 1) - 1; j++) {
946 if (IsASpaceOrTab(styler[j]))
947 continue;
948 else if (styler.StyleAt(j) == SCE_BAAN_WORD5) {
949 if (styler.Match(j, "declaration:")) {
950 // Means declaration: is the start of MainSections.
951 // Nothing to fold before this.
952 beforeDeclarationSection = true;
953 break;
954 }
955 else {
956 beforeDeclarationSection = false;
957 break;
958 }
959 }
960 else {
961 beforeDeclarationSection = false;
962 break;
963 }
964 }
965 if (!beforeDeclarationSection) {
966 levelCurrent--;
967 if (nextLineStyle == SCE_BAAN_WORD5 && priorSectionIsSubSection(lineCurrent-1, styler))
968 // next levelCurrent--; is to unfold previous subsection fold.
969 // On reaching the next main section, the previous main as well sub section ends.
970 levelCurrent--;
971 }
972 }
973 }
974 if (atEOL) {
975 int lev = levelPrev;
976 lev |= levelCurrent << 16;
977 if (visibleChars == 0 && options.foldCompact)
978 lev |= SC_FOLDLEVELWHITEFLAG;
979 if ((levelCurrent > levelPrev) && (visibleChars > 0))
980 lev |= SC_FOLDLEVELHEADERFLAG;
981 if (lev != styler.LevelAt(lineCurrent)) {
982 styler.SetLevel(lineCurrent, lev);
983 }
984 lineCurrent++;
985 levelPrev = levelCurrent;
986 visibleChars = 0;
987 }
988 if (!isspacechar(ch))
989 visibleChars++;
990 }
991 int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
992 styler.SetLevel(lineCurrent, levelPrev | flagsNext);
993}
994
995LexerModule lmBaan(SCLEX_BAAN, LexerBaan::LexerFactoryBaan, "baan", baanWordLists);
996