OSDN Git Service

Add SCI Edit to GitBlameView
[tortoisegit/TortoiseGitJp.git] / ext / scintilla / src / LexMagik.cxx
1 // Scintilla source code edit control\r
2 /**\r
3  * @file LexMagik.cxx\r
4  * Lexer for GE(r) Smallworld(tm) MagikSF\r
5  */\r
6 // Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>\r
7 // The License.txt file describes the conditions under which this software may be distributed.\r
8 \r
9 #include <stdlib.h>\r
10 #include <string.h>\r
11 #include <ctype.h>\r
12 #include <stdio.h>\r
13 #include <stdarg.h>\r
14 \r
15 #include "Platform.h"\r
16 \r
17 #include "PropSet.h"\r
18 #include "Accessor.h"\r
19 #include "StyleContext.h"\r
20 #include "KeyWords.h"\r
21 #include "Scintilla.h"\r
22 #include "SciLexer.h"\r
23 \r
24 #ifdef SCI_NAMESPACE\r
25 using namespace Scintilla;\r
26 #endif\r
27 \r
28 /**\r
29  * Is it a core character (C isalpha(), exclamation and question mark)\r
30  *\r
31  * \param  ch The character\r
32  * \return True if ch is a character, False otherwise\r
33  */\r
34 static inline bool IsAlphaCore(int ch) {\r
35     return (isalpha(ch) || ch == '!' || ch == '?');\r
36 }\r
37 \r
38 /**\r
39  * Is it a character (IsAlphaCore() and underscore)\r
40  *\r
41  * \param  ch The character\r
42  * \return True if ch is a character, False otherwise\r
43  */\r
44 static inline bool IsAlpha(int ch) {\r
45     return (IsAlphaCore(ch) || ch == '_');\r
46 }\r
47 \r
48 /**\r
49  * Is it a symbolic character (IsAlpha() and colon)\r
50  *\r
51  * \param  ch The character\r
52  * \return True if ch is a character, False otherwise\r
53  */\r
54 static inline bool IsAlphaSym(int ch) {\r
55     return (IsAlpha(ch) || ch == ':');\r
56 }\r
57 \r
58 /**\r
59  * Is it a numerical character (IsAlpha() and 0 - 9)\r
60  *\r
61  * \param  ch The character\r
62  * \return True if ch is a character, False otherwise\r
63  */\r
64 static inline bool IsAlNum(int ch) {\r
65     return ((ch > '0' && ch < '9') || IsAlpha(ch));\r
66 }\r
67 \r
68 /**\r
69  * Is it a symbolic numerical character (IsAlNum() and colon)\r
70  *\r
71  * \param  ch The character\r
72  * \return True if ch is a character, False otherwise\r
73  */\r
74 static inline bool IsAlNumSym(int ch) {\r
75     return (IsAlNum(ch) || ch == ':');\r
76 }\r
77 \r
78 /**\r
79  * The lexer function\r
80  *\r
81  * \param  startPos Where to start scanning\r
82  * \param  length Where to scan to\r
83  * \param  initStyle The style at the initial point, not used in this folder\r
84  * \param  keywordslists The keywordslists, currently, number 5 is used\r
85  * \param  styler The styler\r
86  */\r
87 static void ColouriseMagikDoc(unsigned int startPos, int length, int initStyle,\r
88                            WordList *keywordlists[], Accessor &styler) {\r
89     styler.StartAt(startPos);\r
90 \r
91     WordList &keywords = *keywordlists[0];\r
92     WordList &pragmatics = *keywordlists[1];\r
93     WordList &containers = *keywordlists[2];\r
94     WordList &flow = *keywordlists[3];\r
95     WordList &characters = *keywordlists[4];\r
96 \r
97         StyleContext sc(startPos, length, initStyle, styler);\r
98 \r
99 \r
100         for (; sc.More(); sc.Forward()) {\r
101 \r
102     repeat:\r
103 \r
104         if(sc.ch == '#') {\r
105             if (sc.chNext == '#') sc.SetState(SCE_MAGIK_HYPER_COMMENT);\r
106             else sc.SetState(SCE_MAGIK_COMMENT);\r
107             for(; sc.More() && !(sc.atLineEnd); sc.Forward());\r
108             sc.SetState(SCE_MAGIK_DEFAULT);\r
109             goto repeat;\r
110         }\r
111 \r
112         if(sc.ch == '"') {\r
113             sc.SetState(SCE_MAGIK_STRING);\r
114 \r
115             if(sc.More())\r
116             {\r
117                 sc.Forward();\r
118                 for(; sc.More() && sc.ch != '"'; sc.Forward());\r
119             }\r
120 \r
121             sc.ForwardSetState(SCE_MAGIK_DEFAULT);\r
122             goto repeat;\r
123         }\r
124 \r
125             // The default state\r
126             if(sc.state == SCE_MAGIK_DEFAULT) {\r
127 \r
128                 // A certain keyword has been detected\r
129                 if (sc.ch == '_' && (\r
130                     sc.currentPos == 0 || !IsAlNum(sc.chPrev))) {\r
131                     char keyword[50];\r
132                     memset(keyword, '\0', 50);\r
133 \r
134                     for(\r
135                     int scanPosition = 0;\r
136                     scanPosition < 50;\r
137                     scanPosition++) {\r
138                         char keywordChar = static_cast<char>(\r
139                         tolower(styler.SafeGetCharAt(\r
140                             scanPosition +\r
141                                 static_cast<int>(sc.currentPos+1), ' ')));\r
142                     if(IsAlpha(keywordChar)) {\r
143                         keyword[scanPosition] = keywordChar;\r
144                     } else {\r
145                         break;\r
146                     }\r
147                     }\r
148 \r
149                 // It is a pragma\r
150                     if(pragmatics.InList(keyword)) {\r
151                         sc.SetState(SCE_MAGIK_PRAGMA);\r
152                     }\r
153 \r
154                     // it is a normal keyword like _local, _self, etc.\r
155                     else if(keywords.InList(keyword)) {\r
156                         sc.SetState(SCE_MAGIK_KEYWORD);\r
157                     }\r
158 \r
159                 // It is a container keyword, such as _method, _proc, etc.\r
160                     else if(containers.InList(keyword)) {\r
161                         sc.SetState(SCE_MAGIK_CONTAINER);\r
162                     }\r
163 \r
164                     // It is a flow keyword, such as _for, _if, _try, etc.\r
165                     else if(flow.InList(keyword)) {\r
166                         sc.SetState(SCE_MAGIK_FLOW);\r
167                     }\r
168 \r
169                     // Interpret as unknown keyword\r
170                     else {\r
171                         sc.SetState(SCE_MAGIK_UNKNOWN_KEYWORD);\r
172                     }\r
173                 }\r
174 \r
175             // Symbolic expression\r
176                 else if(sc.ch == ':' && !IsAlNum(sc.chPrev)) {\r
177                     sc.SetState(SCE_MAGIK_SYMBOL);\r
178                     bool firstTrip = true;\r
179                     for(sc.Forward(); sc.More(); sc.Forward()) {\r
180                         if(firstTrip && IsAlphaSym(sc.ch));\r
181                         else if(!firstTrip && IsAlNumSym(sc.ch));\r
182                         else if(sc.ch == '|') {\r
183                             for(sc.Forward();\r
184                             sc.More() && sc.ch != '|';\r
185                             sc.Forward());\r
186                         }\r
187                         else break;\r
188 \r
189                         firstTrip = false;\r
190                     }\r
191                     sc.SetState(SCE_MAGIK_DEFAULT);\r
192                     goto repeat;\r
193                 }\r
194 \r
195             // Identifier (label) expression\r
196                 else if(sc.ch == '@') {\r
197                     sc.SetState(SCE_MAGIK_IDENTIFIER);\r
198                     bool firstTrip = true;\r
199                     for(sc.Forward(); sc.More(); sc.Forward()) {\r
200                         if(firstTrip && IsAlphaCore(sc.ch)) {\r
201                             firstTrip = false;\r
202                         }\r
203                         else if(!firstTrip && IsAlpha(sc.ch));\r
204                         else break;\r
205                     }\r
206                     sc.SetState(SCE_MAGIK_DEFAULT);\r
207                     goto repeat;\r
208                 }\r
209 \r
210                 // Start of a character\r
211             else if(sc.ch == '%') {\r
212                 sc.SetState(SCE_MAGIK_CHARACTER);\r
213                 sc.Forward();\r
214                 char keyword[50];\r
215                     memset(keyword, '\0', 50);\r
216 \r
217                     for(\r
218                     int scanPosition = 0;\r
219                     scanPosition < 50;\r
220                     scanPosition++) {\r
221                         char keywordChar = static_cast<char>(\r
222                         tolower(styler.SafeGetCharAt(\r
223                             scanPosition +\r
224                                 static_cast<int>(sc.currentPos), ' ')));\r
225                     if(IsAlpha(keywordChar)) {\r
226                         keyword[scanPosition] = keywordChar;\r
227                     } else {\r
228                         break;\r
229                     }\r
230                     }\r
231 \r
232                     if(characters.InList(keyword)) {\r
233                         sc.Forward(strlen(keyword));\r
234                     } else {\r
235                         sc.Forward();\r
236                     }\r
237 \r
238                 sc.SetState(SCE_MAGIK_DEFAULT);\r
239                 goto repeat;\r
240             }\r
241 \r
242             // Operators\r
243                 else if(\r
244                 sc.ch == '>' ||\r
245                 sc.ch == '<' ||\r
246                 sc.ch == '.' ||\r
247                 sc.ch == ',' ||\r
248                 sc.ch == '+' ||\r
249                 sc.ch == '-' ||\r
250                 sc.ch == '/' ||\r
251                 sc.ch == '*' ||\r
252                 sc.ch == '~' ||\r
253                 sc.ch == '$' ||\r
254                 sc.ch == '=') {\r
255                 sc.SetState(SCE_MAGIK_OPERATOR);\r
256             }\r
257 \r
258             // Braces\r
259             else if(sc.ch == '(' || sc.ch == ')') {\r
260                 sc.SetState(SCE_MAGIK_BRACE_BLOCK);\r
261             }\r
262 \r
263             // Brackets\r
264             else if(sc.ch == '{' || sc.ch == '}') {\r
265                 sc.SetState(SCE_MAGIK_BRACKET_BLOCK);\r
266             }\r
267 \r
268             // Square Brackets\r
269             else if(sc.ch == '[' || sc.ch == ']') {\r
270                 sc.SetState(SCE_MAGIK_SQBRACKET_BLOCK);\r
271             }\r
272 \r
273 \r
274             }\r
275 \r
276             // It is an operator\r
277             else if(\r
278             sc.state == SCE_MAGIK_OPERATOR ||\r
279             sc.state == SCE_MAGIK_BRACE_BLOCK ||\r
280             sc.state == SCE_MAGIK_BRACKET_BLOCK ||\r
281             sc.state == SCE_MAGIK_SQBRACKET_BLOCK) {\r
282                 sc.SetState(SCE_MAGIK_DEFAULT);\r
283                 goto repeat;\r
284             }\r
285 \r
286             // It is the pragma state\r
287             else if(sc.state == SCE_MAGIK_PRAGMA) {\r
288                 if(!IsAlpha(sc.ch)) {\r
289                     sc.SetState(SCE_MAGIK_DEFAULT);\r
290                 goto repeat;\r
291                 }\r
292             }\r
293 \r
294             // It is the keyword state\r
295             else if(\r
296             sc.state == SCE_MAGIK_KEYWORD ||\r
297             sc.state == SCE_MAGIK_CONTAINER ||\r
298             sc.state == SCE_MAGIK_FLOW ||\r
299             sc.state == SCE_MAGIK_UNKNOWN_KEYWORD) {\r
300                 if(!IsAlpha(sc.ch)) {\r
301                     sc.SetState(SCE_MAGIK_DEFAULT);\r
302                     goto repeat;\r
303                 }\r
304             }\r
305         }\r
306 \r
307         sc.Complete();\r
308 }\r
309 \r
310 /**\r
311  * The word list description\r
312  */\r
313 static const char * const magikWordListDesc[] = {\r
314     "Accessors (local, global, self, super, thisthread)",\r
315     "Pragmatic (pragma, private)",\r
316     "Containers (method, block, proc)",\r
317     "Flow (if, then, elif, else)",\r
318     "Characters (space, tab, newline, return)",\r
319     "Fold Containers (method, proc, block, if, loop)",\r
320     0};\r
321 \r
322 /**\r
323  * This function detects keywords which are able to have a body. Note that it\r
324  * uses the Fold Containers word description, not the containers description. It\r
325  * only works when the style at that particular position is set on Containers\r
326  * or Flow (number 3 or 4).\r
327  *\r
328  * \param  keywordslist The list of keywords that are scanned, they should only\r
329  *         contain the start keywords, not the end keywords\r
330  * \param  The actual keyword\r
331  * \return 1 if it is a folding start-keyword, -1 if it is a folding end-keyword\r
332  *         0 otherwise\r
333  */\r
334 static inline int IsFoldingContainer(WordList &keywordslist, char * keyword) {\r
335     if(\r
336         strlen(keyword) > 3 &&\r
337         keyword[0] == 'e' && keyword[1] == 'n' && keyword[2] == 'd') {\r
338         if (keywordslist.InList(keyword + 3)) {\r
339             return -1;\r
340         }\r
341 \r
342     } else {\r
343         if(keywordslist.InList(keyword)) {\r
344             return 1;\r
345         }\r
346     }\r
347 \r
348     return 0;\r
349 }\r
350 \r
351 /**\r
352  * The folding function\r
353  *\r
354  * \param  startPos Where to start scanning\r
355  * \param  length Where to scan to\r
356  * \param  keywordslists The keywordslists, currently, number 5 is used\r
357  * \param  styler The styler\r
358  */\r
359 static void FoldMagikDoc(unsigned int startPos, int length, int,\r
360     WordList *keywordslists[], Accessor &styler) {\r
361 \r
362     bool compact = styler.GetPropertyInt("fold.compact") != 0;\r
363 \r
364     WordList &foldingElements = *keywordslists[5];\r
365     int endPos = startPos + length;\r
366     int line = styler.GetLine(startPos);\r
367     int level = styler.LevelAt(line) & SC_FOLDLEVELNUMBERMASK;\r
368     int flags = styler.LevelAt(line) & ~SC_FOLDLEVELNUMBERMASK;\r
369 \r
370     for(\r
371         int currentPos = startPos;\r
372         currentPos < endPos;\r
373         currentPos++) {\r
374             char currentState = styler.StyleAt(currentPos);\r
375             char c = styler.SafeGetCharAt(currentPos, ' ');\r
376             int prevLine = styler.GetLine(currentPos - 1);\r
377             line = styler.GetLine(currentPos);\r
378 \r
379             // Default situation\r
380             if(prevLine < line) {\r
381                 styler.SetLevel(line, (level|flags) & ~SC_FOLDLEVELHEADERFLAG);\r
382                 flags = styler.LevelAt(line) & ~SC_FOLDLEVELNUMBERMASK;\r
383             }\r
384 \r
385             if(\r
386                 (\r
387                     currentState == SCE_MAGIK_CONTAINER ||\r
388                     currentState == SCE_MAGIK_FLOW\r
389                 ) &&\r
390                 c == '_') {\r
391 \r
392                 char keyword[50];\r
393                 memset(keyword, '\0', 50);\r
394 \r
395                 for(\r
396                     int scanPosition = 0;\r
397                     scanPosition < 50;\r
398                     scanPosition++) {\r
399                     char keywordChar = static_cast<char>(\r
400                         tolower(styler.SafeGetCharAt(\r
401                             scanPosition +\r
402                                 currentPos + 1, ' ')));\r
403                     if(IsAlpha(keywordChar)) {\r
404                         keyword[scanPosition] = keywordChar;\r
405                     } else {\r
406                         break;\r
407                     }\r
408                 }\r
409 \r
410                 if(IsFoldingContainer(foldingElements, keyword) > 0) {\r
411                     styler.SetLevel(\r
412                         line,\r
413                         styler.LevelAt(line) | SC_FOLDLEVELHEADERFLAG);\r
414                     level++;\r
415                 } else if(IsFoldingContainer(foldingElements, keyword) < 0) {\r
416                     styler.SetLevel(line, styler.LevelAt(line));\r
417                     level--;\r
418                 }\r
419             }\r
420 \r
421             if(\r
422                 compact && (\r
423                     currentState == SCE_MAGIK_BRACE_BLOCK ||\r
424                     currentState == SCE_MAGIK_BRACKET_BLOCK ||\r
425                     currentState == SCE_MAGIK_SQBRACKET_BLOCK)) {\r
426                 if(c == '{' || c == '[' || c == '(') {\r
427                     styler.SetLevel(\r
428                         line,\r
429                         styler.LevelAt(line) | SC_FOLDLEVELHEADERFLAG);\r
430                     level++;\r
431                 } else if(c == '}' || c == ']' || c == ')') {\r
432                     styler.SetLevel(line, styler.LevelAt(line));\r
433                     level--;\r
434                 }\r
435             }\r
436         }\r
437 \r
438 }\r
439 \r
440 /**\r
441  * Injecting the module\r
442  */\r
443 LexerModule lmMagikSF(\r
444     SCLEX_MAGIK, ColouriseMagikDoc, "magiksf", FoldMagikDoc, magikWordListDesc);\r
445 \r