OSDN Git Service

compiler-calculated maximum value for `m_SourceDefs` (#966)
[winmerge-jp/winmerge-jp.git] / Externals / crystaledit / editlib / parsers / lua.cpp
1 ///////////////////////////////////////////////////////////////////////////\r
2 //  File:       lua.cpp\r
3 //  Version:    1.0.0.0\r
4 //  Created:    17-May-2019\r
5 //\r
6 //  Copyright:  Stcherbatchenko Andrei, portions by Takashi Sawanaka\r
7 //  E-mail:     sdottaka@users.sourceforge.net\r
8 //\r
9 //  Lua 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 "../utils/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 //  Lua keywords\r
28 static const TCHAR * s_apszLuaKeywordList[] =\r
29   {\r
30 _T ("and"),\r
31 _T ("break"),\r
32 _T ("do"),\r
33 _T ("else"),\r
34 _T ("elseif"),\r
35 _T ("end"),\r
36 _T ("false"),\r
37 _T ("for"),\r
38 _T ("function"),\r
39 _T ("if"),\r
40 _T ("in"),\r
41 _T ("local"),\r
42 _T ("nil"),\r
43 _T ("not"),\r
44 _T ("or"),\r
45 _T ("repeat"),\r
46 _T ("return"),\r
47 _T ("then"),\r
48 _T ("true"),\r
49 _T ("until"),\r
50 _T ("while"),\r
51   };\r
52 \r
53 static bool\r
54 IsLuaKeyword (const TCHAR *pszChars, int nLength)\r
55 {\r
56   return ISXKEYWORD (s_apszLuaKeywordList, pszChars, nLength);\r
57 }\r
58 \r
59 unsigned\r
60 CrystalLineParser::ParseLineLua (unsigned dwCookie, const TCHAR *pszChars, int nLength, TEXTBLOCK * pBuf, int &nActualItems)\r
61 {\r
62   if (nLength == 0)\r
63     return dwCookie & (COOKIE_EXT_COMMENT | COOKIE_RAWSTRING | 0xFF000000);\r
64 \r
65   bool bRedefineBlock = true;\r
66   bool bDecIndex = false;\r
67   int nIdentBegin = -1;\r
68   int nPrevI = -1;\r
69   int I=0;\r
70   for (I = 0;; nPrevI = I, I = static_cast<int>(::CharNext(pszChars+I) - pszChars))\r
71     {\r
72       if (I == nPrevI)\r
73         {\r
74           // CharNext did not advance, so we're at the end of the string\r
75           // and we already handled this character, so stop\r
76           break;\r
77         }\r
78 \r
79       if (bRedefineBlock)\r
80         {\r
81           int nPos = I;\r
82           if (bDecIndex)\r
83             nPos = nPrevI;\r
84           if (dwCookie & (COOKIE_COMMENT | COOKIE_EXT_COMMENT))\r
85             {\r
86               DEFINE_BLOCK (nPos, COLORINDEX_COMMENT);\r
87             }\r
88           else if (dwCookie & (COOKIE_CHAR | COOKIE_STRING | COOKIE_RAWSTRING))\r
89             {\r
90               DEFINE_BLOCK (nPos, COLORINDEX_STRING);\r
91             }\r
92           else\r
93             {\r
94               if (xisalnum (pszChars[nPos]) || pszChars[nPos] == '.' && nPos > 0 && (!xisalpha (*::CharPrev(pszChars, pszChars + nPos)) && !xisalpha (*::CharNext(pszChars + nPos))))\r
95                 {\r
96                   DEFINE_BLOCK (nPos, COLORINDEX_NORMALTEXT);\r
97                 }\r
98               else\r
99                 {\r
100                   DEFINE_BLOCK (nPos, COLORINDEX_OPERATOR);\r
101                   bRedefineBlock = true;\r
102                   bDecIndex = true;\r
103                   goto out;\r
104                 }\r
105             }\r
106           bRedefineBlock = false;\r
107           bDecIndex = false;\r
108         }\r
109 out:\r
110 \r
111       // Can be bigger than length if there is binary data\r
112       // See bug #1474782 Crash when comparing SQL with with binary data\r
113       if (I >= nLength || pszChars[I] == 0)\r
114         break;\r
115 \r
116       if (dwCookie & COOKIE_COMMENT)\r
117         {\r
118           DEFINE_BLOCK (I, COLORINDEX_COMMENT);\r
119           dwCookie |= COOKIE_COMMENT;\r
120           break;\r
121         }\r
122 \r
123       //  String constant "...."\r
124       if (dwCookie & COOKIE_STRING)\r
125         {\r
126           if (pszChars[I] == '"' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))\r
127             {\r
128               dwCookie &= ~COOKIE_STRING;\r
129               bRedefineBlock = true;\r
130             }\r
131           continue;\r
132         }\r
133 \r
134       //  Char constant '..'\r
135       if (dwCookie & COOKIE_CHAR)\r
136         {\r
137           if (pszChars[I] == '\'' && (I == 0 || I == 1 && pszChars[nPrevI] != '\\' || I >= 2 && (pszChars[nPrevI] != '\\' || *::CharPrev(pszChars, pszChars + nPrevI) == '\\')))\r
138             {\r
139               dwCookie &= ~COOKIE_CHAR;\r
140               bRedefineBlock = true;\r
141             }\r
142           continue;\r
143         }\r
144 \r
145       //  Raw string constant [[ ... ]], [=[ ... ]=], [==[ ... ]==], ...\r
146       if (dwCookie & COOKIE_RAWSTRING)\r
147         {\r
148           const int nEqualsSignCount = COOKIE_GET_LUA_EQUALS_SIGN_COUNT(dwCookie);\r
149           if (I >= nEqualsSignCount + 1 && pszChars[I] == ']' && pszChars[I - nEqualsSignCount - 1] == ']' && \r
150               std::all_of(pszChars + I - nEqualsSignCount, pszChars + I, [](const auto c) { return c == '='; }))\r
151             {\r
152               dwCookie &= ~COOKIE_RAWSTRING;\r
153               COOKIE_SET_LUA_EQUALS_SIGN_COUNT(dwCookie, 0);\r
154               bRedefineBlock = true;\r
155             }\r
156           continue;\r
157         }\r
158 \r
159       //  Extended comment --[[ ... ]] , --[=[ ... ]=], --[==[ ... ]==], ...\r
160       if (dwCookie & COOKIE_EXT_COMMENT)\r
161         {\r
162           const int nEqualsSignCount = COOKIE_GET_LUA_EQUALS_SIGN_COUNT(dwCookie);\r
163           if (I >= nEqualsSignCount + 1 && pszChars[I] == ']' && pszChars[I - nEqualsSignCount - 1] == ']' && \r
164               std::all_of(pszChars + I - nEqualsSignCount, pszChars + I, [](const auto c) { return c == '='; }))\r
165             {\r
166               dwCookie &= ~COOKIE_EXT_COMMENT;\r
167               COOKIE_SET_LUA_EQUALS_SIGN_COUNT(dwCookie, 0);\r
168               bRedefineBlock = true;\r
169             }\r
170           continue;\r
171         }\r
172 \r
173       if (I > 0 && pszChars[I] == '-' && pszChars[nPrevI] == '-')\r
174         {\r
175           DEFINE_BLOCK (nPrevI, COLORINDEX_COMMENT);\r
176           dwCookie |= COOKIE_COMMENT;\r
177           break;\r
178         }\r
179 \r
180       //  Normal text\r
181       if (pszChars[I] == '"')\r
182         {\r
183           DEFINE_BLOCK (I, COLORINDEX_STRING);\r
184           dwCookie |= COOKIE_STRING;\r
185           continue;\r
186         }\r
187       if (pszChars[I] == '\'')\r
188         {\r
189           // if (I + 1 < nLength && pszChars[I + 1] == '\'' || I + 2 < nLength && pszChars[I + 1] != '\\' && pszChars[I + 2] == '\'' || I + 3 < nLength && pszChars[I + 1] == '\\' && pszChars[I + 3] == '\'')\r
190           if (!I || !xisalnum (pszChars[nPrevI]))\r
191             {\r
192               DEFINE_BLOCK (I, COLORINDEX_STRING);\r
193               dwCookie |= COOKIE_CHAR;\r
194               continue;\r
195             }\r
196         }\r
197       // Raw string [[ ... ]], [=[ ... ]=], [==[ ... ]==], ...\r
198       if (pszChars[I] == '[' && I + 1 < nLength && (pszChars[I + 1] == '[' || pszChars[I + 1] == '='))\r
199         {\r
200           int nEqualsSignCount = 0;\r
201           while (I + 1 + nEqualsSignCount < nLength && pszChars[I + 1 + nEqualsSignCount] == '=')\r
202             ++nEqualsSignCount;\r
203           if (I + 1 + nEqualsSignCount < nLength && pszChars[I + 1 + nEqualsSignCount] == '[')\r
204             {\r
205               DEFINE_BLOCK (I, COLORINDEX_STRING);\r
206               dwCookie |= COOKIE_RAWSTRING;\r
207               COOKIE_SET_LUA_EQUALS_SIGN_COUNT(dwCookie, nEqualsSignCount);\r
208               continue;\r
209             }\r
210         }\r
211       // Extended comment [[ ... ]], [=[ ... ]=], [==[ ... ]==], ...\r
212       if (pszChars[I] == '-' && I + 3 < nLength && pszChars[I + 1] == '-' && pszChars[I + 2] == '[' && (pszChars[I + 3] == '[' || pszChars[I + 3] == '='))\r
213         {\r
214           int nEqualsSignCount = 0;\r
215           while (I + 3 + nEqualsSignCount < nLength && pszChars[I + 3 + nEqualsSignCount] == '=')\r
216             ++nEqualsSignCount;\r
217           if (I + 3 + nEqualsSignCount < nLength && pszChars[I + 3 + nEqualsSignCount] == '[')\r
218             {\r
219               DEFINE_BLOCK (I, COLORINDEX_COMMENT);\r
220               dwCookie |= COOKIE_EXT_COMMENT;\r
221               COOKIE_SET_LUA_EQUALS_SIGN_COUNT(dwCookie, nEqualsSignCount);\r
222               continue;\r
223             }\r
224         }\r
225 \r
226       if (pBuf == nullptr)\r
227         continue;               //  We don't need to extract keywords,\r
228       //  for faster parsing skip the rest of loop\r
229 \r
230       if (xisalnum (pszChars[I]) || pszChars[I] == '.' && I > 0 && (!xisalpha (pszChars[nPrevI]) && !xisalpha (pszChars[I + 1])))\r
231         {\r
232           if (nIdentBegin == -1)\r
233             nIdentBegin = I;\r
234         }\r
235       else\r
236         {\r
237           if (nIdentBegin >= 0)\r
238             {\r
239               if (IsLuaKeyword (pszChars + nIdentBegin, I - nIdentBegin))\r
240                 {\r
241                   DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);\r
242                 }\r
243               else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))\r
244                 {\r
245                   DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);\r
246                 }\r
247               else\r
248                 {\r
249                   bool bFunction = false;\r
250 \r
251                   for (int j = I; j < nLength; j++)\r
252                     {\r
253                       if (!xisspace (pszChars[j]))\r
254                         {\r
255                           if (pszChars[j] == '(')\r
256                             {\r
257                               bFunction = true;\r
258                             }\r
259                           break;\r
260                         }\r
261                     }\r
262                   if (bFunction)\r
263                     {\r
264                       DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);\r
265                     }\r
266                 }\r
267               bRedefineBlock = true;\r
268               bDecIndex = true;\r
269               nIdentBegin = -1;\r
270             }\r
271         }\r
272     }\r
273 \r
274   if (nIdentBegin >= 0)\r
275     {\r
276       if (IsLuaKeyword (pszChars + nIdentBegin, I - nIdentBegin))\r
277         {\r
278           DEFINE_BLOCK (nIdentBegin, COLORINDEX_KEYWORD);\r
279         }\r
280       else if (IsXNumber (pszChars + nIdentBegin, I - nIdentBegin))\r
281         {\r
282           DEFINE_BLOCK (nIdentBegin, COLORINDEX_NUMBER);\r
283         }\r
284       else\r
285         {\r
286           bool bFunction = false;\r
287 \r
288           for (int j = I; j < nLength; j++)\r
289             {\r
290               if (!xisspace (pszChars[j]))\r
291                 {\r
292                   if (pszChars[j] == '(')\r
293                     {\r
294                       bFunction = true;\r
295                     }\r
296                   break;\r
297                 }\r
298             }\r
299           if (bFunction)\r
300             {\r
301               DEFINE_BLOCK (nIdentBegin, COLORINDEX_FUNCNAME);\r
302             }\r
303         }\r
304     }\r
305 \r
306   dwCookie &= COOKIE_EXT_COMMENT | COOKIE_RAWSTRING | 0xFF000000;\r
307   return dwCookie;\r
308 }\r