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