OSDN Git Service

Enable X64 Build
[tortoisegit/TortoiseGitJp.git] / ext / scintilla / src / LexRebol.cxx
1 // Scintilla source code edit control\r
2 /** @file LexRebol.cxx\r
3  ** Lexer for REBOL.\r
4  ** Written by Pascal Hurni, inspired from LexLua by Paul Winwood & Marcos E. Wurzius & Philippe Lhoste\r
5  **\r
6  ** History:\r
7  **             2005-04-07      First release.\r
8  **             2005-04-10      Closing parens and brackets go now in default style\r
9  **                                     String and comment nesting should be more safe\r
10  **/\r
11 // Copyright 2005 by Pascal Hurni <pascal_hurni@fastmail.fm>\r
12 // The License.txt file describes the conditions under which this software may be distributed.\r
13 \r
14 #include <stdlib.h>\r
15 #include <string.h>\r
16 #include <ctype.h>\r
17 #include <stdio.h>\r
18 #include <stdarg.h>\r
19 \r
20 #include "Platform.h"\r
21 \r
22 #include "PropSet.h"\r
23 #include "Accessor.h"\r
24 #include "KeyWords.h"\r
25 #include "Scintilla.h"\r
26 #include "SciLexer.h"\r
27 #include "StyleContext.h"\r
28 \r
29 #ifdef SCI_NAMESPACE\r
30 using namespace Scintilla;\r
31 #endif\r
32 \r
33 static inline bool IsAWordChar(const int ch) {\r
34         return (isalnum(ch) || ch == '?' || ch == '!' || ch == '.' || ch == '\'' || ch == '+' || ch == '-' || ch == '*' || ch == '&' || ch == '|' || ch == '=' || ch == '_' || ch == '~');\r
35 }\r
36 \r
37 static inline bool IsAWordStart(const int ch, const int ch2) {\r
38         return ((ch == '+' || ch == '-' || ch == '.') && !isdigit(ch2)) ||\r
39                 (isalpha(ch) || ch == '?' || ch == '!' || ch == '\'' || ch == '*' || ch == '&' || ch == '|' || ch == '=' || ch == '_' || ch == '~');\r
40 }\r
41 \r
42 static inline bool IsAnOperator(const int ch, const int ch2, const int ch3) {\r
43         // One char operators\r
44         if (IsASpaceOrTab(ch2)) {\r
45                 return ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '<' || ch == '>' || ch == '=' || ch == '?';\r
46         }\r
47 \r
48         // Two char operators\r
49         if (IsASpaceOrTab(ch3)) {\r
50                 return (ch == '*' && ch2 == '*') ||\r
51                            (ch == '/' && ch2 == '/') ||\r
52                            (ch == '<' && (ch2 == '=' || ch2 == '>')) ||\r
53                            (ch == '>' && ch2 == '=') ||\r
54                            (ch == '=' && (ch2 == '=' || ch2 == '?')) ||\r
55                            (ch == '?' && ch2 == '?');\r
56         }\r
57 \r
58         return false;\r
59 }\r
60 \r
61 static inline bool IsBinaryStart(const int ch, const int ch2, const int ch3, const int ch4) {\r
62         return (ch == '#' && ch2 == '{') ||\r
63                    (IsADigit(ch) && ch2 == '#' && ch3 == '{' ) ||\r
64                    (IsADigit(ch) && IsADigit(ch2) && ch3 == '#' && ch4 == '{' );\r
65 }\r
66 \r
67 \r
68 static void ColouriseRebolDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) {\r
69 \r
70         WordList &keywords = *keywordlists[0];\r
71         WordList &keywords2 = *keywordlists[1];\r
72         WordList &keywords3 = *keywordlists[2];\r
73         WordList &keywords4 = *keywordlists[3];\r
74         WordList &keywords5 = *keywordlists[4];\r
75         WordList &keywords6 = *keywordlists[5];\r
76         WordList &keywords7 = *keywordlists[6];\r
77         WordList &keywords8 = *keywordlists[7];\r
78 \r
79         int currentLine = styler.GetLine(startPos);\r
80         // Initialize the braced string {.. { ... } ..} nesting level, if we are inside such a string.\r
81         int stringLevel = 0;\r
82         if (initStyle == SCE_REBOL_BRACEDSTRING || initStyle == SCE_REBOL_COMMENTBLOCK) {\r
83                 stringLevel = styler.GetLineState(currentLine - 1);\r
84         }\r
85 \r
86         bool blockComment = initStyle == SCE_REBOL_COMMENTBLOCK;\r
87         int dotCount = 0;\r
88 \r
89         // Do not leak onto next line\r
90         if (initStyle == SCE_REBOL_COMMENTLINE) {\r
91                 initStyle = SCE_REBOL_DEFAULT;\r
92         }\r
93 \r
94         StyleContext sc(startPos, length, initStyle, styler);\r
95         if (startPos == 0) {\r
96                 sc.SetState(SCE_REBOL_PREFACE);\r
97         }\r
98         for (; sc.More(); sc.Forward()) {\r
99 \r
100                 //--- What to do at line end ?\r
101                 if (sc.atLineEnd) {\r
102                         // Can be either inside a {} string or simply at eol\r
103                         if (sc.state != SCE_REBOL_BRACEDSTRING && sc.state != SCE_REBOL_COMMENTBLOCK &&\r
104                                 sc.state != SCE_REBOL_BINARY && sc.state != SCE_REBOL_PREFACE)\r
105                                 sc.SetState(SCE_REBOL_DEFAULT);\r
106 \r
107                         // Update the line state, so it can be seen by next line\r
108                         currentLine = styler.GetLine(sc.currentPos);\r
109                         switch (sc.state) {\r
110                         case SCE_REBOL_BRACEDSTRING:\r
111                         case SCE_REBOL_COMMENTBLOCK:\r
112                                 // Inside a braced string, we set the line state\r
113                                 styler.SetLineState(currentLine, stringLevel);\r
114                                 break;\r
115                         default:\r
116                                 // Reset the line state\r
117                                 styler.SetLineState(currentLine, 0);\r
118                                 break;\r
119                         }\r
120 \r
121                         // continue with next char\r
122                         continue;\r
123                 }\r
124 \r
125                 //--- What to do on white-space ?\r
126                 if (IsASpaceOrTab(sc.ch))\r
127                 {\r
128                         // Return to default if any of these states\r
129                         if (sc.state == SCE_REBOL_OPERATOR || sc.state == SCE_REBOL_CHARACTER ||\r
130                                 sc.state == SCE_REBOL_NUMBER || sc.state == SCE_REBOL_PAIR ||\r
131                                 sc.state == SCE_REBOL_TUPLE || sc.state == SCE_REBOL_FILE ||\r
132                                 sc.state == SCE_REBOL_DATE || sc.state == SCE_REBOL_TIME ||\r
133                                 sc.state == SCE_REBOL_MONEY || sc.state == SCE_REBOL_ISSUE ||\r
134                                 sc.state == SCE_REBOL_URL || sc.state == SCE_REBOL_EMAIL) {\r
135                                 sc.SetState(SCE_REBOL_DEFAULT);\r
136                         }\r
137                 }\r
138 \r
139                 //--- Specialize state ?\r
140                 // URL, Email look like identifier\r
141                 if (sc.state == SCE_REBOL_IDENTIFIER)\r
142                 {\r
143                         if (sc.ch == ':' && !IsASpace(sc.chNext)) {\r
144                                 sc.ChangeState(SCE_REBOL_URL);\r
145                         } else if (sc.ch == '@') {\r
146                                 sc.ChangeState(SCE_REBOL_EMAIL);\r
147                         } else if (sc.ch == '$') {\r
148                                 sc.ChangeState(SCE_REBOL_MONEY);\r
149                         }\r
150                 }\r
151                 // Words look like identifiers\r
152                 if (sc.state == SCE_REBOL_IDENTIFIER || (sc.state >= SCE_REBOL_WORD && sc.state <= SCE_REBOL_WORD8)) {\r
153                         // Keywords ?\r
154                         if (!IsAWordChar(sc.ch) || sc.Match('/')) {\r
155                                 char s[100];\r
156                                 sc.GetCurrentLowered(s, sizeof(s));\r
157                                 blockComment = strcmp(s, "comment") == 0;\r
158                                 if (keywords8.InList(s)) {\r
159                                         sc.ChangeState(SCE_REBOL_WORD8);\r
160                                 } else if (keywords7.InList(s)) {\r
161                                         sc.ChangeState(SCE_REBOL_WORD7);\r
162                                 } else if (keywords6.InList(s)) {\r
163                                         sc.ChangeState(SCE_REBOL_WORD6);\r
164                                 } else if (keywords5.InList(s)) {\r
165                                         sc.ChangeState(SCE_REBOL_WORD5);\r
166                                 } else if (keywords4.InList(s)) {\r
167                                         sc.ChangeState(SCE_REBOL_WORD4);\r
168                                 } else if (keywords3.InList(s)) {\r
169                                         sc.ChangeState(SCE_REBOL_WORD3);\r
170                                 } else if (keywords2.InList(s)) {\r
171                                         sc.ChangeState(SCE_REBOL_WORD2);\r
172                                 } else if (keywords.InList(s)) {\r
173                                         sc.ChangeState(SCE_REBOL_WORD);\r
174                                 }\r
175                                 // Keep same style if there are refinements\r
176                                 if (!sc.Match('/')) {\r
177                                         sc.SetState(SCE_REBOL_DEFAULT);\r
178                                 }\r
179                         }\r
180                 // special numbers\r
181                 } else if (sc.state == SCE_REBOL_NUMBER) {\r
182                         switch (sc.ch) {\r
183                         case 'x':       sc.ChangeState(SCE_REBOL_PAIR);\r
184                                                 break;\r
185                         case ':':       sc.ChangeState(SCE_REBOL_TIME);\r
186                                                 break;\r
187                         case '-':\r
188                         case '/':       sc.ChangeState(SCE_REBOL_DATE);\r
189                                                 break;\r
190                         case '.':       if (++dotCount >= 2) sc.ChangeState(SCE_REBOL_TUPLE);\r
191                                                 break;\r
192                         }\r
193                 }\r
194 \r
195                 //--- Determine if the current state should terminate\r
196                 if (sc.state == SCE_REBOL_QUOTEDSTRING || sc.state == SCE_REBOL_CHARACTER) {\r
197                         if (sc.ch == '^' && sc.chNext == '\"') {\r
198                                 sc.Forward();\r
199                         } else if (sc.ch == '\"') {\r
200                                 sc.ForwardSetState(SCE_REBOL_DEFAULT);\r
201                         }\r
202                 } else if (sc.state == SCE_REBOL_BRACEDSTRING || sc.state == SCE_REBOL_COMMENTBLOCK) {\r
203                         if (sc.ch == '}') {\r
204                                 if (--stringLevel == 0) {\r
205                                         sc.ForwardSetState(SCE_REBOL_DEFAULT);\r
206                                 }\r
207                         } else if (sc.ch == '{') {\r
208                                 stringLevel++;\r
209                         }\r
210                 } else if (sc.state == SCE_REBOL_BINARY) {\r
211                         if (sc.ch == '}') {\r
212                                 sc.ForwardSetState(SCE_REBOL_DEFAULT);\r
213                         }\r
214                 } else if (sc.state == SCE_REBOL_TAG) {\r
215                         if (sc.ch == '>') {\r
216                                 sc.ForwardSetState(SCE_REBOL_DEFAULT);\r
217                         }\r
218                 } else if (sc.state == SCE_REBOL_PREFACE) {\r
219                         if (sc.MatchIgnoreCase("rebol"))\r
220                         {\r
221                                 int i;\r
222                                 for (i=5; IsASpaceOrTab(styler.SafeGetCharAt(sc.currentPos+i, 0)); i++);\r
223                                 if (sc.GetRelative(i) == '[')\r
224                                         sc.SetState(SCE_REBOL_DEFAULT);\r
225                         }\r
226                 }\r
227 \r
228                 //--- Parens and bracket changes to default style when the current is a number\r
229                 if (sc.state == SCE_REBOL_NUMBER || sc.state == SCE_REBOL_PAIR || sc.state == SCE_REBOL_TUPLE ||\r
230                         sc.state == SCE_REBOL_MONEY || sc.state == SCE_REBOL_ISSUE || sc.state == SCE_REBOL_EMAIL ||\r
231                         sc.state == SCE_REBOL_URL || sc.state == SCE_REBOL_DATE || sc.state == SCE_REBOL_TIME) {\r
232                         if (sc.ch == '(' || sc.ch == '[' || sc.ch == ')' || sc.ch == ']') {\r
233                                 sc.SetState(SCE_REBOL_DEFAULT);\r
234                         }\r
235                 }\r
236 \r
237                 //--- Determine if a new state should be entered.\r
238                 if (sc.state == SCE_REBOL_DEFAULT) {\r
239                         if (IsAnOperator(sc.ch, sc.chNext, sc.GetRelative(2))) {\r
240                                 sc.SetState(SCE_REBOL_OPERATOR);\r
241                         } else if (IsBinaryStart(sc.ch, sc.chNext, sc.GetRelative(2), sc.GetRelative(3))) {\r
242                                 sc.SetState(SCE_REBOL_BINARY);\r
243                         } else if (IsAWordStart(sc.ch, sc.chNext)) {\r
244                                 sc.SetState(SCE_REBOL_IDENTIFIER);\r
245                         } else if (IsADigit(sc.ch) || sc.ch == '+' || sc.ch == '-' || /*Decimal*/ sc.ch == '.' || sc.ch == ',') {\r
246                                 dotCount = 0;\r
247                                 sc.SetState(SCE_REBOL_NUMBER);\r
248                         } else if (sc.ch == '\"') {\r
249                                 sc.SetState(SCE_REBOL_QUOTEDSTRING);\r
250                         } else if (sc.ch == '{') {\r
251                                 sc.SetState(blockComment ? SCE_REBOL_COMMENTBLOCK : SCE_REBOL_BRACEDSTRING);\r
252                                 ++stringLevel;\r
253                         } else if (sc.ch == ';') {\r
254                                 sc.SetState(SCE_REBOL_COMMENTLINE);\r
255                         } else if (sc.ch == '$') {\r
256                                 sc.SetState(SCE_REBOL_MONEY);\r
257                         } else if (sc.ch == '%') {\r
258                                 sc.SetState(SCE_REBOL_FILE);\r
259                         } else if (sc.ch == '<') {\r
260                                 sc.SetState(SCE_REBOL_TAG);\r
261                         } else if (sc.ch == '#' && sc.chNext == '"') {\r
262                                 sc.SetState(SCE_REBOL_CHARACTER);\r
263                                 sc.Forward();\r
264                         } else if (sc.ch == '#' && sc.chNext != '"' && sc.chNext != '{' ) {\r
265                                 sc.SetState(SCE_REBOL_ISSUE);\r
266                         }\r
267                 }\r
268         }\r
269         sc.Complete();\r
270 }\r
271 \r
272 \r
273 static void FoldRebolDoc(unsigned int startPos, int length, int /* initStyle */, WordList *[],\r
274                             Accessor &styler) {\r
275         unsigned int lengthDoc = startPos + length;\r
276         int visibleChars = 0;\r
277         int lineCurrent = styler.GetLine(startPos);\r
278         int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;\r
279         int levelCurrent = levelPrev;\r
280         char chNext = styler[startPos];\r
281         int styleNext = styler.StyleAt(startPos);\r
282         for (unsigned int i = startPos; i < lengthDoc; i++) {\r
283                 char ch = chNext;\r
284                 chNext = styler.SafeGetCharAt(i + 1);\r
285                 int style = styleNext;\r
286                 styleNext = styler.StyleAt(i + 1);\r
287                 bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');\r
288                 if (style == SCE_REBOL_DEFAULT) {\r
289                         if (ch == '[') {\r
290                                 levelCurrent++;\r
291                         } else if (ch == ']') {\r
292                                 levelCurrent--;\r
293                         }\r
294                 }\r
295                 if (atEOL) {\r
296                         int lev = levelPrev;\r
297                         if (visibleChars == 0)\r
298                                 lev |= SC_FOLDLEVELWHITEFLAG;\r
299                         if ((levelCurrent > levelPrev) && (visibleChars > 0))\r
300                                 lev |= SC_FOLDLEVELHEADERFLAG;\r
301                         if (lev != styler.LevelAt(lineCurrent)) {\r
302                                 styler.SetLevel(lineCurrent, lev);\r
303                         }\r
304                         lineCurrent++;\r
305                         levelPrev = levelCurrent;\r
306                         visibleChars = 0;\r
307                 }\r
308                 if (!isspacechar(ch))\r
309                         visibleChars++;\r
310         }\r
311         // Fill in the real level of the next line, keeping the current flags as they will be filled in later\r
312         int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;\r
313         styler.SetLevel(lineCurrent, levelPrev | flagsNext);\r
314 }\r
315 \r
316 static const char * const rebolWordListDesc[] = {\r
317         "Keywords",\r
318         0\r
319 };\r
320 \r
321 LexerModule lmREBOL(SCLEX_REBOL, ColouriseRebolDoc, "rebol", FoldRebolDoc, rebolWordListDesc);\r
322 \r