| 179 | } |
| 180 | |
| 181 | static std::pair<uint32_t, size_t> parse_char_class_char(const std::string & content, size_t pos) { |
| 182 | if (content[pos] == '\\' && pos + 1 < content.length()) { |
| 183 | switch (content[pos + 1]) { |
| 184 | case 'x': { |
| 185 | auto result = parse_hex_escape(content, pos + 2, 2); |
| 186 | if (result.second > 0) { |
| 187 | return {result.first, 2 + result.second}; |
| 188 | } |
| 189 | // Invalid escape, treat as literal 'x' |
| 190 | return {static_cast<uint32_t>('x'), 2}; |
| 191 | } |
| 192 | case 'u': { |
| 193 | auto result = parse_hex_escape(content, pos + 2, 4); |
| 194 | if (result.second > 0) { |
| 195 | return {result.first, 2 + result.second}; |
| 196 | } |
| 197 | // Invalid escape, treat as literal 'u' |
| 198 | return {static_cast<uint32_t>('u'), 2}; |
| 199 | } |
| 200 | case 'U': { |
| 201 | auto result = parse_hex_escape(content, pos + 2, 8); |
| 202 | if (result.second > 0) { |
| 203 | return {result.first, 2 + result.second}; |
| 204 | } |
| 205 | // Invalid escape, treat as literal 'U' |
| 206 | return {static_cast<uint32_t>('U'), 2}; |
| 207 | } |
| 208 | case 'n': return {'\n', 2}; |
| 209 | case 't': return {'\t', 2}; |
| 210 | case 'r': return {'\r', 2}; |
| 211 | case '\\': return {'\\', 2}; |
| 212 | case ']': return {']', 2}; |
| 213 | case '[': return {'[', 2}; |
| 214 | default: return {static_cast<uint32_t>(content[pos + 1]), 2}; |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | // Regular character - return as codepoint |
| 219 | return {static_cast<uint32_t>(static_cast<unsigned char>(content[pos])), 1}; |
| 220 | } |
| 221 | |
| 222 | static std::pair<std::vector<common_peg_chars_parser::char_range>, bool> parse_char_classes(const std::string & classes) { |
| 223 | std::vector<common_peg_chars_parser::char_range> ranges; |
no test coverage detected