updated Scintilla to 2.29
[TortoiseGit.git] / ext / scintilla / lexers / LexMagik.cxx
blobae7fb2bccaebdec3ba9b66d047a2a51737e11ae1
1 // Scintilla source code edit control
2 /**
3 * @file LexMagik.cxx
4 * Lexer for GE(r) Smallworld(tm) MagikSF
5 */
6 // Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
7 // The License.txt file describes the conditions under which this software may be distributed.
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <assert.h>
14 #include <ctype.h>
16 #include "ILexer.h"
17 #include "Scintilla.h"
18 #include "SciLexer.h"
20 #include "WordList.h"
21 #include "LexAccessor.h"
22 #include "Accessor.h"
23 #include "StyleContext.h"
24 #include "CharacterSet.h"
25 #include "LexerModule.h"
27 #ifdef SCI_NAMESPACE
28 using namespace Scintilla;
29 #endif
31 /**
32 * Is it a core character (C isalpha(), exclamation and question mark)
34 * \param ch The character
35 * \return True if ch is a character, False otherwise
37 static inline bool IsAlphaCore(int ch) {
38 return (isalpha(ch) || ch == '!' || ch == '?');
41 /**
42 * Is it a character (IsAlphaCore() and underscore)
44 * \param ch The character
45 * \return True if ch is a character, False otherwise
47 static inline bool IsAlpha(int ch) {
48 return (IsAlphaCore(ch) || ch == '_');
51 /**
52 * Is it a symbolic character (IsAlpha() and colon)
54 * \param ch The character
55 * \return True if ch is a character, False otherwise
57 static inline bool IsAlphaSym(int ch) {
58 return (IsAlpha(ch) || ch == ':');
61 /**
62 * Is it a numerical character (IsAlpha() and 0 - 9)
64 * \param ch The character
65 * \return True if ch is a character, False otherwise
67 static inline bool IsAlNum(int ch) {
68 return ((ch >= '0' && ch <= '9') || IsAlpha(ch));
71 /**
72 * Is it a symbolic numerical character (IsAlNum() and colon)
74 * \param ch The character
75 * \return True if ch is a character, False otherwise
77 static inline bool IsAlNumSym(int ch) {
78 return (IsAlNum(ch) || ch == ':');
81 /**
82 * The lexer function
84 * \param startPos Where to start scanning
85 * \param length Where to scan to
86 * \param initStyle The style at the initial point, not used in this folder
87 * \param keywordslists The keywordslists, currently, number 5 is used
88 * \param styler The styler
90 static void ColouriseMagikDoc(unsigned int startPos, int length, int initStyle,
91 WordList *keywordlists[], Accessor &styler) {
92 styler.StartAt(startPos);
94 WordList &keywords = *keywordlists[0];
95 WordList &pragmatics = *keywordlists[1];
96 WordList &containers = *keywordlists[2];
97 WordList &flow = *keywordlists[3];
98 WordList &characters = *keywordlists[4];
100 StyleContext sc(startPos, length, initStyle, styler);
103 for (; sc.More(); sc.Forward()) {
105 repeat:
107 if(sc.ch == '#') {
108 if (sc.chNext == '#') sc.SetState(SCE_MAGIK_HYPER_COMMENT);
109 else sc.SetState(SCE_MAGIK_COMMENT);
110 for(; sc.More() && !(sc.atLineEnd); sc.Forward());
111 sc.SetState(SCE_MAGIK_DEFAULT);
112 goto repeat;
115 if(sc.ch == '"') {
116 sc.SetState(SCE_MAGIK_STRING);
118 if(sc.More())
120 sc.Forward();
121 for(; sc.More() && sc.ch != '"'; sc.Forward());
124 sc.ForwardSetState(SCE_MAGIK_DEFAULT);
125 goto repeat;
128 // The default state
129 if(sc.state == SCE_MAGIK_DEFAULT) {
131 // A certain keyword has been detected
132 if (sc.ch == '_' && (
133 sc.currentPos == 0 || !IsAlNum(sc.chPrev))) {
134 char keyword[50];
135 memset(keyword, '\0', 50);
137 for(
138 int scanPosition = 0;
139 scanPosition < 50;
140 scanPosition++) {
141 char keywordChar = static_cast<char>(
142 tolower(styler.SafeGetCharAt(
143 scanPosition +
144 static_cast<int>(sc.currentPos+1), ' ')));
145 if(IsAlpha(keywordChar)) {
146 keyword[scanPosition] = keywordChar;
147 } else {
148 break;
152 // It is a pragma
153 if(pragmatics.InList(keyword)) {
154 sc.SetState(SCE_MAGIK_PRAGMA);
157 // it is a normal keyword like _local, _self, etc.
158 else if(keywords.InList(keyword)) {
159 sc.SetState(SCE_MAGIK_KEYWORD);
162 // It is a container keyword, such as _method, _proc, etc.
163 else if(containers.InList(keyword)) {
164 sc.SetState(SCE_MAGIK_CONTAINER);
167 // It is a flow keyword, such as _for, _if, _try, etc.
168 else if(flow.InList(keyword)) {
169 sc.SetState(SCE_MAGIK_FLOW);
172 // Interpret as unknown keyword
173 else {
174 sc.SetState(SCE_MAGIK_UNKNOWN_KEYWORD);
178 // Symbolic expression
179 else if(sc.ch == ':' && !IsAlNum(sc.chPrev)) {
180 sc.SetState(SCE_MAGIK_SYMBOL);
181 bool firstTrip = true;
182 for(sc.Forward(); sc.More(); sc.Forward()) {
183 if(firstTrip && IsAlphaSym(sc.ch));
184 else if(!firstTrip && IsAlNumSym(sc.ch));
185 else if(sc.ch == '|') {
186 for(sc.Forward();
187 sc.More() && sc.ch != '|';
188 sc.Forward());
190 else break;
192 firstTrip = false;
194 sc.SetState(SCE_MAGIK_DEFAULT);
195 goto repeat;
198 // Identifier (label) expression
199 else if(sc.ch == '@') {
200 sc.SetState(SCE_MAGIK_IDENTIFIER);
201 bool firstTrip = true;
202 for(sc.Forward(); sc.More(); sc.Forward()) {
203 if(firstTrip && IsAlphaCore(sc.ch)) {
204 firstTrip = false;
206 else if(!firstTrip && IsAlpha(sc.ch));
207 else break;
209 sc.SetState(SCE_MAGIK_DEFAULT);
210 goto repeat;
213 // Start of a character
214 else if(sc.ch == '%') {
215 sc.SetState(SCE_MAGIK_CHARACTER);
216 sc.Forward();
217 char keyword[50];
218 memset(keyword, '\0', 50);
220 for(
221 int scanPosition = 0;
222 scanPosition < 50;
223 scanPosition++) {
224 char keywordChar = static_cast<char>(
225 tolower(styler.SafeGetCharAt(
226 scanPosition +
227 static_cast<int>(sc.currentPos), ' ')));
228 if(IsAlpha(keywordChar)) {
229 keyword[scanPosition] = keywordChar;
230 } else {
231 break;
235 if(characters.InList(keyword)) {
236 sc.Forward(static_cast<int>(strlen(keyword)));
237 } else {
238 sc.Forward();
241 sc.SetState(SCE_MAGIK_DEFAULT);
242 goto repeat;
245 // Operators
246 else if(
247 sc.ch == '>' ||
248 sc.ch == '<' ||
249 sc.ch == '.' ||
250 sc.ch == ',' ||
251 sc.ch == '+' ||
252 sc.ch == '-' ||
253 sc.ch == '/' ||
254 sc.ch == '*' ||
255 sc.ch == '~' ||
256 sc.ch == '$' ||
257 sc.ch == '=') {
258 sc.SetState(SCE_MAGIK_OPERATOR);
261 // Braces
262 else if(sc.ch == '(' || sc.ch == ')') {
263 sc.SetState(SCE_MAGIK_BRACE_BLOCK);
266 // Brackets
267 else if(sc.ch == '{' || sc.ch == '}') {
268 sc.SetState(SCE_MAGIK_BRACKET_BLOCK);
271 // Square Brackets
272 else if(sc.ch == '[' || sc.ch == ']') {
273 sc.SetState(SCE_MAGIK_SQBRACKET_BLOCK);
279 // It is an operator
280 else if(
281 sc.state == SCE_MAGIK_OPERATOR ||
282 sc.state == SCE_MAGIK_BRACE_BLOCK ||
283 sc.state == SCE_MAGIK_BRACKET_BLOCK ||
284 sc.state == SCE_MAGIK_SQBRACKET_BLOCK) {
285 sc.SetState(SCE_MAGIK_DEFAULT);
286 goto repeat;
289 // It is the pragma state
290 else if(sc.state == SCE_MAGIK_PRAGMA) {
291 if(!IsAlpha(sc.ch)) {
292 sc.SetState(SCE_MAGIK_DEFAULT);
293 goto repeat;
297 // It is the keyword state
298 else if(
299 sc.state == SCE_MAGIK_KEYWORD ||
300 sc.state == SCE_MAGIK_CONTAINER ||
301 sc.state == SCE_MAGIK_FLOW ||
302 sc.state == SCE_MAGIK_UNKNOWN_KEYWORD) {
303 if(!IsAlpha(sc.ch)) {
304 sc.SetState(SCE_MAGIK_DEFAULT);
305 goto repeat;
310 sc.Complete();
314 * The word list description
316 static const char * const magikWordListDesc[] = {
317 "Accessors (local, global, self, super, thisthread)",
318 "Pragmatic (pragma, private)",
319 "Containers (method, block, proc)",
320 "Flow (if, then, elif, else)",
321 "Characters (space, tab, newline, return)",
322 "Fold Containers (method, proc, block, if, loop)",
326 * This function detects keywords which are able to have a body. Note that it
327 * uses the Fold Containers word description, not the containers description. It
328 * only works when the style at that particular position is set on Containers
329 * or Flow (number 3 or 4).
331 * \param keywordslist The list of keywords that are scanned, they should only
332 * contain the start keywords, not the end keywords
333 * \param The actual keyword
334 * \return 1 if it is a folding start-keyword, -1 if it is a folding end-keyword
335 * 0 otherwise
337 static inline int IsFoldingContainer(WordList &keywordslist, char * keyword) {
339 strlen(keyword) > 3 &&
340 keyword[0] == 'e' && keyword[1] == 'n' && keyword[2] == 'd') {
341 if (keywordslist.InList(keyword + 3)) {
342 return -1;
345 } else {
346 if(keywordslist.InList(keyword)) {
347 return 1;
351 return 0;
355 * The folding function
357 * \param startPos Where to start scanning
358 * \param length Where to scan to
359 * \param keywordslists The keywordslists, currently, number 5 is used
360 * \param styler The styler
362 static void FoldMagikDoc(unsigned int startPos, int length, int,
363 WordList *keywordslists[], Accessor &styler) {
365 bool compact = styler.GetPropertyInt("fold.compact") != 0;
367 WordList &foldingElements = *keywordslists[5];
368 int endPos = startPos + length;
369 int line = styler.GetLine(startPos);
370 int level = styler.LevelAt(line) & SC_FOLDLEVELNUMBERMASK;
371 int flags = styler.LevelAt(line) & ~SC_FOLDLEVELNUMBERMASK;
373 for(
374 int currentPos = startPos;
375 currentPos < endPos;
376 currentPos++) {
377 char currentState = styler.StyleAt(currentPos);
378 char c = styler.SafeGetCharAt(currentPos, ' ');
379 int prevLine = styler.GetLine(currentPos - 1);
380 line = styler.GetLine(currentPos);
382 // Default situation
383 if(prevLine < line) {
384 styler.SetLevel(line, (level|flags) & ~SC_FOLDLEVELHEADERFLAG);
385 flags = styler.LevelAt(line) & ~SC_FOLDLEVELNUMBERMASK;
390 currentState == SCE_MAGIK_CONTAINER ||
391 currentState == SCE_MAGIK_FLOW
392 ) &&
393 c == '_') {
395 char keyword[50];
396 memset(keyword, '\0', 50);
398 for(
399 int scanPosition = 0;
400 scanPosition < 50;
401 scanPosition++) {
402 char keywordChar = static_cast<char>(
403 tolower(styler.SafeGetCharAt(
404 scanPosition +
405 currentPos + 1, ' ')));
406 if(IsAlpha(keywordChar)) {
407 keyword[scanPosition] = keywordChar;
408 } else {
409 break;
413 if(IsFoldingContainer(foldingElements, keyword) > 0) {
414 styler.SetLevel(
415 line,
416 styler.LevelAt(line) | SC_FOLDLEVELHEADERFLAG);
417 level++;
418 } else if(IsFoldingContainer(foldingElements, keyword) < 0) {
419 styler.SetLevel(line, styler.LevelAt(line));
420 level--;
425 compact && (
426 currentState == SCE_MAGIK_BRACE_BLOCK ||
427 currentState == SCE_MAGIK_BRACKET_BLOCK ||
428 currentState == SCE_MAGIK_SQBRACKET_BLOCK)) {
429 if(c == '{' || c == '[' || c == '(') {
430 styler.SetLevel(
431 line,
432 styler.LevelAt(line) | SC_FOLDLEVELHEADERFLAG);
433 level++;
434 } else if(c == '}' || c == ']' || c == ')') {
435 styler.SetLevel(line, styler.LevelAt(line));
436 level--;
444 * Injecting the module
446 LexerModule lmMagikSF(
447 SCLEX_MAGIK, ColouriseMagikDoc, "magiksf", FoldMagikDoc, magikWordListDesc);