1 // =================================
  2 // Copyright (c) 2024 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.Collections;
  8 
  9 namespace System.RegularExpressions
 10 {
 11     [nodiscard]
 12     public Result<bool> ParseHexChar(const string& fileNameuchar& valueconst uchar*& pconst uchar* econst System.Lex.Token& token)
 13     {
 14         if (p != e)
 15         {
 16             bool notHex = false;
 17             uchar c = *p;
 18             switch (c)
 19             {
 20                 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
 21                 {
 22                     value = cast<uchar>(16 * cast<int>(value) + cast<int>(c) - cast<int>('0'));
 23                     break;
 24                 }
 25                 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
 26                 {
 27                     value = cast<uchar>(16 * cast<int>(value) + 10 + cast<int>(c) - cast<int>('A'));
 28                     break;
 29                 }
 30                 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
 31                 {
 32                     value = cast<uchar>(16 * cast<int>(value) + 10 + cast<int>(c) - cast<int>('a'));
 33                     break;
 34                 }
 35                 default:
 36                 {
 37                     notHex = true;
 38                     break;
 39                 }
 40             }
 41             if (notHex)
 42             {
 43                 string errorMessage = "hex character expected at " + fileName + ":" + ToString(token.line);
 44                 int errorId = AllocateError(errorMessage);
 45                 return Result<bool>(ErrorId(errorId));
 46             }
 47             ++p;
 48         }
 49         else
 50         {
 51             string errorMessage = "hex character expected at " + fileName + ":" + ToString(token.line);
 52             int errorId = AllocateError(errorMessage);
 53             return Result<bool>(ErrorId(errorId));
 54         }
 55         return Result<bool>(true);
 56     }
 57 
 58     [nodiscard]
 59     public Result<uchar> ParseEscape(const string& fileNameconst uchar*& pconst uchar* econst System.Lex.Token& token)
 60     {
 61         uchar value;
 62         if (p != e && (*p == 'x' || *p == 'X'))
 63         {
 64             ++p;
 65             while (p != e && ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')))
 66             {
 67                 auto hexCharResult = ParseHexChar(fileNamevaluepetoken);
 68                 if (hexCharResult.Error())
 69                 {
 70                     return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
 71                 }
 72             }
 73         }
 74         else if (p != e && (*p == 'd' || *p == 'D'))
 75         {
 76             ++p;
 77             while (p != e && *p >= '0' && *p <= '9')
 78             {
 79                 value = cast<uchar>(10 * cast<int>(value) + (cast<int>(*p) - cast<int>('0')));
 80                 ++p;
 81             }
 82         }
 83         else if (p != e && (*p >= '0' && *p <= '7'))
 84         {
 85             while (p != e && *p >= '0' && *p <= '7')
 86             {
 87                 value = cast<uchar>(8 * cast<int>(value) + (cast<int>(*p) - cast<int>('0')));
 88                 ++p;
 89             }
 90         }
 91         else if (p != e && *p == 'u')
 92         {
 93             ++p;
 94             auto hexCharResult = ParseHexChar(fileNamevaluepetoken);
 95             if (hexCharResult.Error())
 96             {
 97                 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
 98             }
 99             hexCharResult = ParseHexChar(fileNamevaluepetoken);
100             if (hexCharResult.Error())
101             {
102                 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
103             }
104             hexCharResult = ParseHexChar(fileNamevaluepetoken);
105             if (hexCharResult.Error())
106             {
107                 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
108             }
109             hexCharResult = ParseHexChar(fileNamevaluepetoken);
110             if (hexCharResult.Error())
111             {
112                 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
113             }
114         }
115         else if (p != e && *p == 'U')
116         {
117             ++p;
118             auto hexCharResult = ParseHexChar(fileNamevaluepetoken);
119             if (hexCharResult.Error())
120             {
121                 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
122             }
123             hexCharResult = ParseHexChar(fileNamevaluepetoken);
124             if (hexCharResult.Error())
125             {
126                 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
127             }
128             hexCharResult = ParseHexChar(fileNamevaluepetoken);
129             if (hexCharResult.Error())
130             {
131                 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
132             }
133             hexCharResult = ParseHexChar(fileNamevaluepetoken);
134             if (hexCharResult.Error())
135             {
136                 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
137             }
138             hexCharResult = ParseHexChar(fileNamevaluepetoken);
139             if (hexCharResult.Error())
140             {
141                 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
142             }
143             hexCharResult = ParseHexChar(fileNamevaluepetoken);
144             if (hexCharResult.Error())
145             {
146                 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
147             }
148             hexCharResult = ParseHexChar(fileNamevaluepetoken);
149             if (hexCharResult.Error())
150             {
151                 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
152             }
153             hexCharResult = ParseHexChar(fileNamevaluepetoken);
154             if (hexCharResult.Error())
155             {
156                 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
157             }
158         }
159         else if (p != e)
160         {
161             uchar c = *p;
162             switch (c)
163             {
164                 case 'a': value = '\a'; break;
165                 case 'b': value = '\b'; break;
166                 case 'f': value = '\f'; break;
167                 case 'n': value = '\n'; break;
168                 case 'r': value = '\r'; break;
169                 case 't': value = '\t'; break;
170                 case 'v': value = '\v'; break;
171                 default: value = c; break;
172             }
173             ++p;
174         }
175         return Result<uchar>(value);
176     }
177 
178     [nodiscard]
179     public Result<uchar> MakeEscapeValue(const string& fileNameconst System.Lex.Token& token)
180     {
181         uchar* p = token.match.begin;
182         uchar* e = token.match.end;
183         Result<uchar> escapeValue;
184         if (*p == '\\')
185         {
186             ++p;
187             escapeValue = ParseEscape(fileNamepetoken);
188             if (escapeValue.Error())
189             {
190                 return Result<uchar>(ErrorId(escapeValue.GetErrorId()));
191             }
192         }
193         if (p != e)
194         {
195             string matchValue;
196             auto utf8Result = ToUtf8(token.match.ToString());
197             if (!utf8Result.Error())
198             {
199                 matchValue = utf8Result.Value();
200             }
201             int errorId = AllocateError("invalid escape value at " + fileName + ":" + ToString(token.line) + ": " + matchValue);
202             return Result<uchar>(ErrorId(errorId));
203         }
204         return escapeValue;
205     }
206