1
2
3
4
5
6 using System;
7
8 namespace System.XPath
9 {
10 [nodiscard]
11 public Result<bool> ParseHexChar(const string& fileName, uchar& value, const uchar*& p, const uchar* e, const System.Lex.Token& token)
12 {
13 if (p != e)
14 {
15 bool notHex = false;
16 uchar c = *p;
17 switch (c)
18 {
19 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
20 {
21 value = cast<uchar>(16 * cast<int>(value) + cast<int>(c) - cast<int>('0'));
22 break;
23 }
24 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
25 {
26 value = cast<uchar>(16 * cast<int>(value) + 10 + cast<int>(c) - cast<int>('A'));
27 break;
28 }
29 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
30 {
31 value = cast<uchar>(16 * cast<int>(value) + 10 + cast<int>(c) - cast<int>('a'));
32 break;
33 }
34 default:
35 {
36 notHex = true;
37 break;
38 }
39 }
40 if (notHex)
41 {
42 string errorMessage = "hex character expected at " + fileName + ":" + ToString(token.line);
43 int errorId = AllocateError(errorMessage);
44 return Result<bool>(ErrorId(errorId));
45 }
46 ++p;
47 }
48 else
49 {
50 string errorMessage = "hex character expected at " + fileName + ":" + ToString(token.line);
51 int errorId = AllocateError(errorMessage);
52 return Result<bool>(ErrorId(errorId));
53 }
54 return Result<bool>(true);
55 }
56
57 [nodiscard]
58 public Result<uchar> ParseEscape(const string& fileName, const uchar*& p, const uchar* e, const System.Lex.Token& token)
59 {
60 uchar value;
61 if (p != e && (*p == 'x' || *p == 'X'))
62 {
63 ++p;
64 while (p != e && ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')))
65 {
66 auto hexCharResult = ParseHexChar(fileName, value, p, e, token);
67 if (hexCharResult.Error())
68 {
69 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
70 }
71 }
72 }
73 else if (p != e && (*p == 'd' || *p == 'D'))
74 {
75 ++p;
76 while (p != e && *p >= '0' && *p <= '9')
77 {
78 value = cast<uchar>(10 * cast<int>(value) + (cast<int>(*p) - cast<int>('0')));
79 ++p;
80 }
81 }
82 else if (p != e && (*p >= '0' && *p <= '7'))
83 {
84 while (p != e && *p >= '0' && *p <= '7')
85 {
86 value = cast<uchar>(8 * cast<int>(value) + (cast<int>(*p) - cast<int>('0')));
87 ++p;
88 }
89 }
90 else if (p != e && *p == 'u')
91 {
92 ++p;
93 auto hexCharResult = ParseHexChar(fileName, value, p, e, token);
94 if (hexCharResult.Error())
95 {
96 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
97 }
98 hexCharResult = ParseHexChar(fileName, value, p, e, token);
99 if (hexCharResult.Error())
100 {
101 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
102 }
103 hexCharResult = ParseHexChar(fileName, value, p, e, token);
104 if (hexCharResult.Error())
105 {
106 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
107 }
108 hexCharResult = ParseHexChar(fileName, value, p, e, token);
109 if (hexCharResult.Error())
110 {
111 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
112 }
113 }
114 else if (p != e && *p == 'U')
115 {
116 ++p;
117 auto hexCharResult = ParseHexChar(fileName, value, p, e, token);
118 if (hexCharResult.Error())
119 {
120 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
121 }
122 hexCharResult = ParseHexChar(fileName, value, p, e, token);
123 if (hexCharResult.Error())
124 {
125 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
126 }
127 hexCharResult = ParseHexChar(fileName, value, p, e, token);
128 if (hexCharResult.Error())
129 {
130 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
131 }
132 hexCharResult = ParseHexChar(fileName, value, p, e, token);
133 if (hexCharResult.Error())
134 {
135 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
136 }
137 hexCharResult = ParseHexChar(fileName, value, p, e, token);
138 if (hexCharResult.Error())
139 {
140 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
141 }
142 hexCharResult = ParseHexChar(fileName, value, p, e, token);
143 if (hexCharResult.Error())
144 {
145 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
146 }
147 hexCharResult = ParseHexChar(fileName, value, p, e, token);
148 if (hexCharResult.Error())
149 {
150 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
151 }
152 hexCharResult = ParseHexChar(fileName, value, p, e, token);
153 if (hexCharResult.Error())
154 {
155 return Result<uchar>(ErrorId(hexCharResult.GetErrorId()));
156 }
157 }
158 else if (p != e)
159 {
160 uchar c = *p;
161 switch (c)
162 {
163 case 'a': value = '\a'; break;
164 case 'b': value = '\b'; break;
165 case 'f': value = '\f'; break;
166 case 'n': value = '\n'; break;
167 case 'r': value = '\r'; break;
168 case 't': value = '\t'; break;
169 case 'v': value = '\v'; break;
170 default: value = c; break;
171 }
172 ++p;
173 }
174 return Result<uchar>(value);
175 }
176
177 [nodiscard]
178 public Result<string> ParseDQString(const string& fileName, const System.Lex.Token& token)
179 {
180 ustring stringLiteral;
181 uchar* p = token.match.begin;
182 uchar* e = token.match.end;
183 if (p != e && *p == '\"')
184 {
185 ++p;
186 while (p != e && *p != '\r' && *p != '\n' && *p != '\"')
187 {
188 if (*p == '\\')
189 {
190 ++p;
191 auto escape = ParseEscape(fileName, p, e, token);
192 if (escape.Error())
193 {
194 return Result<string>(ErrorId(escape.GetErrorId()));
195 }
196 stringLiteral.Append(escape.Value());
197 }
198 else
199 {
200 stringLiteral.Append(*p);
201 ++p;
202 }
203 }
204 if (p != e && *p == '\"')
205 {
206 ++p;
207 }
208 if (p != e)
209 {
210 string matchValue;
211 auto utf8Result = ToUtf8(token.match.ToString());
212 if (!utf8Result.Error())
213 {
214 matchValue = utf8Result.Value();
215 }
216 int errorId = AllocateError("invalid string literal at " + fileName + ":" + ToString(token.line) + ": " + matchValue);
217 return Result<string>(ErrorId(errorId));
218 }
219 }
220 else
221 {
222 string matchValue;
223 auto utf8Result = ToUtf8(token.match.ToString());
224 if (!utf8Result.Error())
225 {
226 matchValue = utf8Result.Value();
227 }
228 int errorId = AllocateError("invalid string literal at " + fileName + ":" + ToString(token.line) + ": " + matchValue);
229 return Result<string>(ErrorId(errorId));
230 }
231 auto utf8Result = ToUtf8(stringLiteral);
232 if (utf8Result.Error())
233 {
234 return Result<string>(ErrorId(utf8Result.GetErrorId()));
235 }
236 return Result<string>(utf8Result.Value());
237 }
238
239 [nodiscard]
240 public Result<string> ParseSQString(const string& fileName, const System.Lex.Token& token)
241 {
242 ustring stringLiteral;
243 uchar* p = token.match.begin;
244 uchar* e = token.match.end;
245 if (p != e && *p == '\'')
246 {
247 ++p;
248 while (p != e && *p != '\r' && *p != '\n' && *p != '\'')
249 {
250 if (*p == '\\')
251 {
252 ++p;
253 auto escape = ParseEscape(fileName, p, e, token);
254 if (escape.Error())
255 {
256 return Result<string>(ErrorId(escape.GetErrorId()));
257 }
258 stringLiteral.Append(escape.Value());
259 }
260 else
261 {
262 stringLiteral.Append(*p);
263 ++p;
264 }
265 }
266 if (p != e && *p == '\'')
267 {
268 ++p;
269 }
270 if (p != e)
271 {
272 string matchValue;
273 auto utf8Result = ToUtf8(token.match.ToString());
274 if (!utf8Result.Error())
275 {
276 matchValue = utf8Result.Value();
277 }
278 int errorId = AllocateError("invalid string literal at " + fileName + ":" + ToString(token.line) + ": " + matchValue);
279 return Result<string>(ErrorId(errorId));
280 }
281 }
282 else
283 {
284 string matchValue;
285 auto utf8Result = ToUtf8(token.match.ToString());
286 if (!utf8Result.Error())
287 {
288 matchValue = utf8Result.Value();
289 }
290 int errorId = AllocateError("invalid string literal at " + fileName + ":" + ToString(token.line) + ": " + matchValue);
291 return Result<string>(ErrorId(errorId));
292 }
293 auto utf8Result = ToUtf8(stringLiteral);
294 if (utf8Result.Error())
295 {
296 return Result<string>(ErrorId(utf8Result.GetErrorId()));
297 }
298 return Result<string>(utf8Result.Value());
299 }