1 // =================================
  2 // Copyright (c) 2020 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <sng2html/sng2html/TokenValueParsers.hpp>
  7 #include <soulng/util/Unicode.hpp>
  8 
  9 namespace sng2html { namespace sng2html {
 10 
 11 using namespace soulng::unicode;
 12 
 13 void ParseHexChar(const std::string& fileNamechar32_t& valueconst char32_t*& pconst char32_t* econst soulng::lexer::Token& token)
 14 {
 15     if (p != e)
 16     {
 17         switch (*p)
 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 = 16 * value + *p - '0';
 22             break;
 23         }
 24         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
 25         {
 26             value = 16 * value + 10 + *p - 'A';
 27             break;
 28         }
 29         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
 30         {
 31             value = 16 * value + 10 + *p - 'a';
 32             break;
 33         }
 34         }
 35         ++p;
 36     }
 37     else
 38     {
 39         throw std::runtime_error("hex character expected at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
 40     }
 41 }
 42 
 43 char32_t ParseEscape(const std::string& fileNameconst char32_t*& pconst char32_t* econst soulng::lexer::Token& token)
 44 {
 45     char32_t value = '\0';
 46     if (p != e&&(  *p == 'x' || *p == 'X'))
 47     {
 48         ++p;
 49         while (p != e&&(  (*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')))
 50         {
 51             ParseHexChar(fileNamevaluepetoken);
 52         }
 53     }
 54     else if (p != e&&(  *p == 'd' || *p == 'D'))
 55     {
 56         ++p;
 57         while (p != e && *p >= '0' && *p <= '9')
 58         {
 59             value = 10 * value + (*p - '0');
 60             ++p;
 61         }
 62     }
 63     else if (p != e&&(  *p >= '0' && *p <= '7'))
 64     {
 65         while (p != e && *p >= '0' && *p <= '7')
 66         {
 67             value = 8 * value + (*p - '0');
 68             ++p;
 69         }
 70     }
 71     else if (p != e && *p == 'u')
 72     {
 73         ++p;
 74         ParseHexChar(fileNamevaluepetoken);
 75         ParseHexChar(fileNamevaluepetoken);
 76         ParseHexChar(fileNamevaluepetoken);
 77         ParseHexChar(fileNamevaluepetoken);
 78     }
 79     else if (p != e && *p == 'U')
 80     {
 81         ++p;
 82         ParseHexChar(fileNamevaluepetoken);
 83         ParseHexChar(fileNamevaluepetoken);
 84         ParseHexChar(fileNamevaluepetoken);
 85         ParseHexChar(fileNamevaluepetoken);
 86         ParseHexChar(fileNamevaluepetoken);
 87         ParseHexChar(fileNamevaluepetoken);
 88         ParseHexChar(fileNamevaluepetoken);
 89         ParseHexChar(fileNamevaluepetoken);
 90     }
 91     else if (p != e)
 92     {
 93         switch (*p)
 94         {
 95             case 'a': value = '\a'; break;
 96             case 'b': value = '\b'; break;
 97             case 'f': value = '\f'; break;
 98             case 'n': value = '\n'; break;
 99             case 'r': value = '\r'; break;
100             case 't': value = '\t'; break;
101             case 'v': value = '\v'; break;
102             default: value = *p; break;
103         }
104         ++p;
105     }
106     return value;
107 }
108 
109 std::u32string MakeStrValue(const std::string& fileNameconst soulng::lexer::Token& token)
110 {
111     std::u32string strValue;
112     const char32_t* p = token.match.begin;
113     const char32_t* e = token.match.end;
114     if (p != e && *p == '"')
115     {
116         ++p;
117     }
118     while (p != e && *p != '\r' && *p != '\n' && *p != '"')
119     {
120         if (*p == '\\')
121         {
122             ++p;
123             strValue.append(1ParseEscape(fileNamepetoken));
124         }
125         else
126         {
127             strValue.append(1*p);
128             ++p;
129         }
130     }
131     if (p != e && *p == '"')
132     {
133         ++p;
134     }
135     if (p != e)
136     {
137         throw std::runtime_error("invalid string literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
138     }
139     return strValue;
140 }
141 
142 std::u32string MakeExprStringValue(const std::string& fileNameconst soulng::lexer::Token& token)
143 {
144     std::u32string strValue;
145     const char32_t* p = token.match.begin;
146     const char32_t* e = token.match.end;
147     if (p != e && *p == '"')
148     {
149         ++p;
150     }
151     while (p != e && *p != '\r' && *p != '\n' && *p != '"')
152     {
153         if (*p == '\\')
154         {
155             ++p;
156             if (p != e && *p == '"')
157             {
158                 strValue.append(1'"');
159                 ++p;
160             }
161             else
162             {
163                 strValue.append(1'\\');
164                 strValue.append(1*p);
165                 ++p;
166             }
167         }
168         else
169         {
170             strValue.append(1*p);
171             ++p;
172         }
173     }
174     if (p != e && *p == '"')
175     {
176         ++p;
177     }
178     if (p != e)
179     {
180         throw std::runtime_error("invalid expression string literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
181     }
182     return strValue;
183 }
184 
185 std::u32string MakePathValue(const std::string& fileNameconst soulng::lexer::Token& token)
186 {
187     std::u32string pathValue;
188     const char32_t* p = token.match.begin;
189     const char32_t* e = token.match.end;
190     if (p != e && *p == '<')
191     {
192         ++p;
193     }
194     while (p != e && *p != '\r' && *p != '\n' && *p != '>')
195     {
196         pathValue.append(1*p);
197         ++p;
198     }
199     if (p != e && *p == '>')
200     {
201         ++p;
202     }
203     if (p != e)
204     {
205         throw std::runtime_error("invalid path literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
206     }
207     return pathValue;
208 }
209 
210 int MakeActionIntValue(const std::string& fileNameconst soulng::lexer::Token& token)
211 {
212     int actionIntValue = 0;
213     const char32_t* p = token.match.begin;
214     const char32_t* e = token.match.end;
215     if (p == e)
216     {
217         throw std::runtime_error("invalid action integer value at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
218     }
219     while (p != e && *p >= '0' && *p <= '9')
220     {
221         actionIntValue = 10 * actionIntValue + (*p - '0');
222         ++p;
223     }
224     if (p != e)
225     {
226         throw std::runtime_error("invalid action integer value at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
227     }
228     return actionIntValue;
229 }
230 
231 std::u32string MakeExprRefId(const std::string& fileNameconst std::u32string& matchint line)
232 {
233     std::u32string exprRefId;
234     const char32_t* p = match.c_str();
235     const char32_t* e = match.c_str() + match.length();
236     if (p != e && *p == '{')
237     {
238         ++p;
239     }
240     while (p != e && *p != '\r' && *p != '\n' && *p != '}')
241     {
242         exprRefId.append(1*p);
243         ++p;
244     }
245     if (p != e && *p == '}')
246     {
247         ++p;
248     }
249     if (p != e)
250     {
251         throw std::runtime_error("invalid expression reference at " + fileName + ":" + std::to_string(line) + ": " + ToUtf8(match));
252     }
253     return exprRefId;
254 }
255 
256 char32_t MakeEscapeValue(const std::string& fileNameconst soulng::lexer::Token& token)
257 {
258     char32_t escapeValue = '\0';
259     const char32_t* p = token.match.begin;
260     const char32_t* e = token.match.end;
261     if (p != e && *p == '\\')
262     {
263         ++p;
264     }
265     escapeValue = ParseEscape(fileNamepetoken);
266     if (p != e)
267     {
268         throw std::runtime_error("invalid escape at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
269     }
270     return escapeValue;
271 }
272 
273 std::string MakeFilePath(const std::string& fileNameconst soulng::lexer::Token& token)
274 {
275     std::u32string s;
276     const char32_t* p = token.match.begin;
277     const char32_t* e = token.match.end;
278     if (p != e && *p == '<')
279     {
280         ++p;
281     }
282     while (p != e && *p != '>')
283     {
284         s.append(1*p);
285         ++p;
286     }
287     if (p != e && *p == '>')
288     {
289         ++p;
290     }
291     if (p != e)
292     {
293         throw std::runtime_error("invalid file path at " + fileName + ":" + std::to_string(token.line) + " : '" + ToUtf8(token.match.ToString()) + "'");
294     }
295     return ToUtf8(s);
296 }
297 
298 std::u32string ParseStringLiteral(const std::string& fileNameconst soulng::lexer::Token& token)
299 {
300     std::u32string stringLiteral;
301     const char32_t* p = token.match.begin;
302     const char32_t* e = token.match.end;
303     if (p != e && *p == '"')
304     {
305         ++p;
306         while (p != e && *p != '\r' && *p != '\n' && *p != '"')
307         {
308             if (*p == '\\')
309             {
310                 ++p;
311                 stringLiteral.append(1ParseEscape(fileNamepetoken));
312             }
313             else
314             {
315                 stringLiteral.append(1*p);
316                 ++p;
317             }
318         }
319         if (p != e && *p == '"')
320         {
321             ++p;
322         }
323         if (p != e)
324         {
325             throw std::runtime_error("invalid string literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
326         }
327     }
328     else
329     {
330         throw std::runtime_error("invalid string literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
331     }
332     return stringLiteral;
333 }
334 
335 char32_t ParseCharLiteral(const std::string& fileNameconst soulng::lexer::Token& token)
336 {
337     char32_t charLit = '\0';
338     const char32_t* p = token.match.begin;
339     const char32_t* e = token.match.end;
340     bool first = true;
341     if (p != e && *p == '\'')
342     {
343         ++p;
344         while (p != e && *p != '\r' && *p != '\n' && *p != '\'')
345         {
346             if (*p == '\\')
347             {
348                 ++p;
349                 if (first)
350                 {
351                     charLit = ParseEscape(fileNamepetoken);
352                     first = false;
353                 }
354                 else
355                 {
356                     throw std::runtime_error("invalid character literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
357                 }
358             }
359             else
360             {
361                 if (first)
362                 {
363                     charLit = *p;
364                     first = false;
365                 }
366                 else
367                 {
368                     throw std::runtime_error("invalid character literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
369                 }
370                 ++p;
371             }
372         }
373         if (p != e && *p == '\'')
374         {
375             ++p;
376         }
377         if (p != e)
378         {
379             throw std::runtime_error("invalid character literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
380         }
381     }
382     else
383     {
384         throw std::runtime_error("invalid character literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
385     }
386     return charLit;
387 }
388 
389 CharSet ParseCharSet(const std::string& fileNameconst soulng::lexer::Token& tokenconst std::u32string& str)
390 {
391     CharSet set;
392     const char32_t* p = str.c_str();
393     const char32_t* e = str.c_str() + str.length();
394     bool inverse = false;
395     if (p != e && *p == '[')
396     {
397         ++p;
398         if (p != e && *p == '^')
399         {
400             set.SetInverse();
401             ++p;
402         }
403         while (p != e && *p != ']')
404         {
405             char32_t first = *p;
406             char32_t last = first;
407             ++p;
408             if (p != e && *p != ']')
409             {
410                 if (*p == '-')
411                 {
412                     ++p;
413                     if (p != e && *p != ']')
414                     {
415                         last = *p;
416                         ++p;
417                     }
418                     else
419                     {
420                         soulng::parser::Range range;
421                         range.first = first;
422                         range.last = first;
423                         set.AddRange(range);
424                         first = '-';
425                         last = '-';
426                     }
427                 }
428             }
429             soulng::parser::Range range;
430             range.first = first;
431             range.last = last;
432             set.AddRange(range);
433         }
434         if (p != e && *p == ']')
435         {
436             ++p;
437         }
438         if (p != e)
439         {
440             throw std::runtime_error("invalid character set literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
441         }
442     }
443     else
444     {
445         throw std::runtime_error("invalid character set literal at " + fileName + ":" + std::to_string(token.line) + ": " + ToUtf8(token.match.ToString()));
446     }
447     return set;
448 }
449 
450 
451 } } // namespace soulng::slg