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