OSDN Git Service

crystaledit: Make almost the same code into a common function
[winmerge-jp/winmerge-jp.git] / Externals / crystaledit / editlib / rust.cpp
1 ///////////////////////////////////////////////////////////////////////////\r
2 //  File:       rust.cpp\r
3 //  Version:    1.0.0.0\r
4 //  Created:    23-Jul-2017\r
5 //\r
6 //  Copyright:  Stcherbatchenko Andrei, portions by Takashi Sawanaka\r
7 //  E-mail:     sdottaka@users.sourceforge.net\r
8 //\r
9 //  Rust syntax highlighing definition\r
10 //\r
11 //  You are free to use or modify this code to the following restrictions:\r
12 //  - Acknowledge me somewhere in your about box, simple "Parts of code by.."\r
13 //  will be enough. If you can't (or don't want to), contact me personally.\r
14 //  - LEAVE THIS HEADER INTACT\r
15 ////////////////////////////////////////////////////////////////////////////\r
16 \r
17 #include "StdAfx.h"\r
18 #include "crystallineparser.h"\r
19 #include "SyntaxColors.h"\r
20 #include "string_util.h"\r
21 #include <algorithm>\r
22 \r
23 #ifdef _DEBUG\r
24 #define new DEBUG_NEW\r
25 #endif\r
26 \r
27 //  Rust keywords\r
28 static LPCTSTR s_apszRustKeywordList[] =\r
29   {\r
30     _T ("Self"),\r
31     _T ("abstract"),\r
32     _T ("alignof"),\r
33     _T ("as"),\r
34     _T ("become"),\r
35     _T ("box"),\r
36     _T ("break"),\r
37     _T ("const"),\r
38     _T ("continue"),\r
39     _T ("crate"),\r
40     _T ("do"),\r
41     _T ("else"),\r
42     _T ("enum"),\r
43     _T ("extern"),\r
44     _T ("false"),\r
45     _T ("final"),\r
46     _T ("fn"),\r
47     _T ("for"),\r
48     _T ("if"),\r
49     _T ("impl"),\r
50     _T ("in"),\r
51     _T ("let"),\r
52     _T ("loop"),\r
53     _T ("macro"),\r
54     _T ("match"),\r
55     _T ("mod"),\r
56     _T ("move"),\r
57     _T ("mut"),\r
58     _T ("offsetof"),\r
59     _T ("override"),\r
60     _T ("priv"),\r
61     _T ("proc"),\r
62     _T ("pub"),\r
63     _T ("pure"),\r
64     _T ("ref"),\r
65     _T ("return"),\r
66     _T ("self"),\r
67     _T ("sizeof"),\r
68     _T ("static"),\r
69     _T ("struct"),\r
70     _T ("super"),\r
71     _T ("trait"),\r
72     _T ("true"),\r
73     _T ("type"),\r
74     _T ("typeof"),\r
75     _T ("unsafe"),\r
76     _T ("unsized"),\r
77     _T ("use"),\r
78     _T ("virtual"),\r
79     _T ("where"),\r
80     _T ("while"),\r
81     _T ("yield"),\r
82   };\r
83 \r
84 static LPCTSTR s_apszUser1KeywordList[] =\r
85   {\r
86     _T ("String"),\r
87     _T ("binary32"),\r
88     _T ("binary64"),\r
89     _T ("bool"),\r
90     _T ("char"),\r
91     _T ("f32"),\r
92     _T ("f64"),\r
93     _T ("i16"),\r
94     _T ("i32"),\r
95     _T ("i64"),\r
96     _T ("i8"),\r
97     _T ("isize"),\r
98     _T ("str"),\r
99     _T ("u16"),\r
100     _T ("u32"),\r
101     _T ("u64"),\r
102     _T ("u8"),\r
103     _T ("usize"),\r
104   };\r
105 \r
106 static bool\r
107 IsRustKeyword (LPCTSTR pszChars, int nLength)\r
108 {\r
109   return ISXKEYWORD (s_apszRustKeywordList, pszChars, nLength);\r
110 }\r
111 \r
112 static bool\r
113 IsUser1Keyword (LPCTSTR pszChars, int nLength)\r
114 {\r
115   return ISXKEYWORD (s_apszUser1KeywordList, pszChars, nLength);\r
116 }\r
117 \r
118 DWORD\r
119 CrystalLineParser::ParseLineRust (DWORD dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems)\r
120 {\r
121   if (nLength == 0)\r
122     return dwCookie & (COOKIE_EXT_COMMENT | COOKIE_RAWSTRING | COOKIE_STRING | 0xFF000000);\r
123 \r
124   LPCTSTR pszRawStringBegin = nullptr;\r
125   LPCTSTR pszCommentBegin = nullptr;\r
126   LPCTSTR pszCommentEnd = nullptr;\r
127   bool bRedefineBlock = true;\r
128   bool bDecIndex = false;\r
129   int nIdentBegin = -1;\r
130   int nPrevI = -1;\r
131   int I=0;\r
132   for (I = 0;; nPrevI = I, I = static_cast<int>(::CharNext(pszChars+I) - pszChars))\r
133     {\r
134       if (I == nPrevI)\r
135         {\r
136           // CharNext did not advance, so we're at the end of the string\r
137           // and we already handled this character, so stop\r
138           break;\r
139         }\r
140 \r
141       if (bRedefineBlock)\r
142         {\r
143           int nPos = I;\r
144           if (bDecIndex)\r
145             nPos = nPrevI;\r
146           if (dwCookie & (COOKIE_COMMENT | COOKIE_EXT_COMMENT))\r
147             {\r
148               DEFINE_BLOCK (nPos, COLORINDEX_COMMENT);\r
149             }\r
150           else if (dwCookie & (COOKIE_STRING | COOKIE_RAWSTRING))\r
151             {\r
152               DEFINE_BLOCK (nPos, COLORINDEX_STRING);\r
153             }\r
154           else\r
155             {\r
156               if (xisalnum (pszChars[nPos]) || pszChars[nPos] == '.' && nPos > 0 && (!xisalpha (*::CharPrev(pszChars, pszChars + nPos)) && !xisalpha (*::CharNext(pszChars + nPos))))\r
157                 {\r
158                   DEFINE_BLOCK (nPos, COLORINDEX_NORMALTEXT);\r
159                 }\r
160               else\r
161                 {\r
162                   DEFINE_BLOCK (nPos, COLORINDEX_OPERATOR);\r
163                   bRedefineBlock = true;\r
164                   bDecIndex = true;\r
165                   goto out;\r
166                 }\r
167             }\r
168           bRedefineBlock = false;\r
169           bDecIndex = false;\r
170         }\r
171 out:\r
172 \r
173       // Can be bigger than length if there is binary data\r
174       // See bug #1474782 Crash when comparing SQL with with binary data\r
175       if (I >= nLength || pszChars[I] == 0)\r
176         break;\r
177 \r
178       if (dwCookie & COOKIE_COMMENT)\r
179         {\r
180           DEFINE_BLOCK (I, COLORINDEX_COMMENT);\r
181           dwCookie |= COOKIE_COMMENT;\r
182           break;\r
183         }\r
184 \r
185       //  String constant "...."\r
186       if (dwCookie & COOKIE_STRING)\r
187         {\r
188           if (pszChars[I] == '"' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))\r
189             {\r
190               dwCookie &= ~COOKIE_STRING;\r
191               bRedefineBlock = true;\r
192             }\r
193           continue;\r
194         }\r
195 \r
196       //  Raw string constant r"...." ,  r#"..."# , r##"..."##\r
197       if (dwCookie & COOKIE_RAWSTRING)\r
198         {\r
199           const int nNumberCount = COOKIE_GET_RAWSTRING_NUMBER_COUNT(dwCookie);\r
200           if (I >= nNumberCount && pszChars[I - nNumberCount] == '"')\r
201             {\r
202               if ((pszRawStringBegin < pszChars + I - nNumberCount) && \r
203                   (nNumberCount == 0 ||\r
204                   std::all_of(pszChars + I - nNumberCount + 1, pszChars + I + 1, [](const auto c) { return c == '#'; })))\r
205                 {\r
206                   dwCookie &= ~COOKIE_RAWSTRING;\r
207                   bRedefineBlock = true;\r
208                   pszRawStringBegin = nullptr;\r
209                 }\r
210             }\r
211           continue;\r
212         }\r
213 \r
214       //  Extended comment /*....*/\r
215       if (dwCookie & COOKIE_EXT_COMMENT)\r
216         {\r
217           const int depth = COOKIE_GET_EXT_COMMENT_DEPTH(dwCookie);\r
218           if ((pszCommentEnd < pszChars + I) && (I > 0 && pszChars[I] == '*' && pszChars[nPrevI] == '/'))\r
219             {\r
220               COOKIE_SET_EXT_COMMENT_DEPTH(dwCookie, depth + 1);\r
221               pszCommentBegin = pszChars + I + 1;\r
222             }\r
223           else if ((pszCommentBegin < pszChars + I) && (I > 0 && pszChars[I] == '/' && pszChars[nPrevI] == '*'))\r
224             {\r
225               if (depth == 0)\r
226                 {\r
227                   dwCookie &= ~COOKIE_EXT_COMMENT;\r
228                   bRedefineBlock = true;\r
229                 }\r
230               else\r
231                 {\r
232                   COOKIE_SET_EXT_COMMENT_DEPTH(dwCookie, depth - 1);\r
233                 }\r
234               pszCommentEnd = pszChars + I + 1;\r
235             }\r
236           continue;\r
237         }\r
238 \r
239       if (I > 0 && pszChars[I] == '/' && pszChars[nPrevI] == '/')\r
240         {\r
241           DEFINE_BLOCK (nPrevI, COLORINDEX_COMMENT);\r
242           dwCookie |= COOKIE_COMMENT;\r
243           break;\r
244         }\r
245 \r
246       //  Normal text\r
247       if (pszChars[I] == '"')\r
248         {\r
249           DEFINE_BLOCK (I, COLORINDEX_STRING);\r
250           dwCookie |= COOKIE_STRING;\r
251           continue;\r
252         }\r
253 \r
254       //  Raw string\r
255       if ((pszChars[I] == 'r' && I + 1 < nLength && (pszChars[I + 1] == '"' || pszChars[I + 1] == '#')) ||\r
256           (pszChars[I] == 'b' && I + 2 < nLength && pszChars[I + 1] == 'r' && (pszChars[I + 2] == '"' || pszChars[I + 2] == '#')))\r
257         {\r
258           const int nprefix = (pszChars[I] == 'r' ? 1 : 2);\r
259           const TCHAR *p = std::find_if(pszChars + I + nprefix, pszChars + nLength,\r
260               [](const auto c) { return c != '#'; });\r
261           if (p != pszChars + nLength && *p == '"')\r
262             {\r
263               DEFINE_BLOCK (I, COLORINDEX_STRING);\r
264               dwCookie |= COOKIE_RAWSTRING;\r
265               COOKIE_SET_RAWSTRING_NUMBER_COUNT(dwCookie, static_cast<int>(p - (pszChars + I + nprefix)));\r
266               pszRawStringBegin = p + 1;\r
267               continue;\r
268             }\r
269         }\r
270       if ((pszCommentEnd < pszChars + I) && (I > 0 && pszChars[I] == '*' && pszChars[nPrevI] == '/'))\r
271         {\r
272           DEFINE_BLOCK (nPrevI, COLORINDEX_COMMENT);\r
273           dwCookie |= COOKIE_EXT_COMMENT;\r
274           pszCommentBegin = pszChars + I + 1;\r
275           continue;\r
276         }\r
277 \r
278       if (pBuf == nullptr)\r
279         continue;               //  We don't need to extract keywords,\r
280       //  for faster parsing skip the rest of loop\r
281 \r
282       if (xisalnum (pszChars[I]) || pszChars[I] == '.' && I > 0 && (!xisalpha (pszChars[nPrevI]) && !xisalpha (pszChars[I + 1])))\r
283         {\r
284           if (nIdentBegin == -1)\r
285             nIdentBegin = I;\r
286         }\r
287       else\r
288         {\r
289           if (nIdentBegin >= 0)\r
290             {\r
291               if (IsRustKeyword (pszChars + nIdentBegin, I - nIdentBegin))\r
292                 {\r
293                   DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);\r
294                 }\r
295               else if (IsUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))\r
296                 {\r
297                   DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);\r
298                 }\r
299               else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))\r
300                 {\r
301                   DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);\r
302                 }\r
303               else\r
304                 {\r
305                   bool bFunction = false;\r
306 \r
307                   for (int j = I; j < nLength; j++)\r
308                     {\r
309                       if (!xisspace (pszChars[j]) && pszChars[j] != '!')\r
310                         {\r
311                           if (pszChars[j] == '(')\r
312                             {\r
313                               bFunction = true;\r
314                             }\r
315                           break;\r
316                         }\r
317                     }\r
318                   if (bFunction)\r
319                     {\r
320                       DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);\r
321                     }\r
322                 }\r
323               bRedefineBlock = true;\r
324               bDecIndex = true;\r
325               nIdentBegin = -1;\r
326             }\r
327         }\r
328     }\r
329 \r
330   if (nIdentBegin >= 0)\r
331     {\r
332       if (IsRustKeyword (pszChars + nIdentBegin, I - nIdentBegin))\r
333         {\r
334           DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);\r
335         }\r
336       else if (IsUser1Keyword (pszChars + nIdentBegin, I - nIdentBegin))\r
337         {\r
338           DEFINE_BLOCK (nIdentBegin, COLORINDEX_USER1);\r
339         }\r
340       else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))\r
341         {\r
342           DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);\r
343         }\r
344       else\r
345         {\r
346           bool bFunction = false;\r
347 \r
348           for (int j = I; j < nLength; j++)\r
349             {\r
350               if (!xisspace (pszChars[j]) && pszChars[j] != '!')\r
351                 {\r
352                   if (pszChars[j] == '(')\r
353                     {\r
354                       bFunction = true;\r
355                     }\r
356                   break;\r
357                 }\r
358             }\r
359           if (bFunction)\r
360             {\r
361               DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);\r
362             }\r
363         }\r
364     }\r
365 \r
366   dwCookie &= COOKIE_EXT_COMMENT | COOKIE_RAWSTRING | COOKIE_STRING | 0xFF000000;\r
367   return dwCookie;\r
368 }\r