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