| ... | @@ -223,6 +223,42 @@ static uint8_t parse_char_literal(ParseContext *pc, Token *token) { | ... | @@ -223,6 +223,42 @@ static uint8_t parse_char_literal(ParseContext *pc, Token *token) { |
| 223 | return return_value; | 223 | return return_value; |
| 224 | } | 224 | } |
| 225 | | 225 | |
| | 226 | static int get_hex_digit(uint8_t c) { |
| | 227 | switch (c) { |
| | 228 | case '0': return 0; |
| | 229 | case '1': return 1; |
| | 230 | case '2': return 2; |
| | 231 | case '3': return 3; |
| | 232 | case '4': return 4; |
| | 233 | case '5': return 5; |
| | 234 | case '6': return 6; |
| | 235 | case '7': return 7; |
| | 236 | case '8': return 8; |
| | 237 | case '9': return 9; |
| | 238 | |
| | 239 | case 'a': |
| | 240 | case 'A': |
| | 241 | return 10; |
| | 242 | case 'b': |
| | 243 | case 'B': |
| | 244 | return 11; |
| | 245 | case 'c': |
| | 246 | case 'C': |
| | 247 | return 12; |
| | 248 | case 'd': |
| | 249 | case 'D': |
| | 250 | return 13; |
| | 251 | case 'e': |
| | 252 | case 'E': |
| | 253 | return 14; |
| | 254 | case 'f': |
| | 255 | case 'F': |
| | 256 | return 15; |
| | 257 | default: |
| | 258 | return -1; |
| | 259 | } |
| | 260 | } |
| | 261 | |
| 226 | static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool *out_c_str, | 262 | static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool *out_c_str, |
| 227 | ZigList<SrcPos> *offset_map) | 263 | ZigList<SrcPos> *offset_map) |
| 228 | { | 264 | { |
| ... | @@ -240,12 +276,22 @@ static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool | ... | @@ -240,12 +276,22 @@ static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool |
| 240 | // convert escape sequences | 276 | // convert escape sequences |
| 241 | // detect c string literal | 277 | // detect c string literal |
| 242 | | 278 | |
| | 279 | enum State { |
| | 280 | StateStart, |
| | 281 | StateEscape, |
| | 282 | StateHex1, |
| | 283 | StateHex2, |
| | 284 | }; |
| | 285 | |
| 243 | buf_resize(buf, 0); | 286 | buf_resize(buf, 0); |
| 244 | bool escape = false; | 287 | |
| | 288 | State state = StateStart; |
| 245 | bool skip_quote; | 289 | bool skip_quote; |
| 246 | SrcPos pos = {token->start_line, token->start_column}; | 290 | SrcPos pos = {token->start_line, token->start_column}; |
| | 291 | int hex_value = 0; |
| 247 | for (int i = token->start_pos; i < token->end_pos - 1; i += 1) { | 292 | for (int i = token->start_pos; i < token->end_pos - 1; i += 1) { |
| 248 | uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i); | 293 | uint8_t c = *((uint8_t*)buf_ptr(pc->buf) + i); |
| | 294 | |
| 249 | if (i == token->start_pos) { | 295 | if (i == token->start_pos) { |
| 250 | skip_quote = (c == 'c'); | 296 | skip_quote = (c == 'c'); |
| 251 | if (out_c_str) { | 297 | if (out_c_str) { |
| ... | @@ -256,41 +302,72 @@ static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool | ... | @@ -256,41 +302,72 @@ static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool |
| 256 | } else if (skip_quote) { | 302 | } else if (skip_quote) { |
| 257 | skip_quote = false; | 303 | skip_quote = false; |
| 258 | } else { | 304 | } else { |
| 259 | if (escape) { | 305 | switch (state) { |
| 260 | switch (c) { | 306 | case StateStart: |
| 261 | case '\\': | 307 | if (c == '\\') { |
| 262 | buf_append_char(buf, '\\'); | 308 | state = StateEscape; |
| 263 | if (offset_map) offset_map->append(pos); | 309 | } else { |
| 264 | break; | 310 | buf_append_char(buf, c); |
| 265 | case 'r': | | |
| 266 | buf_append_char(buf, '\r'); | | |
| 267 | if (offset_map) offset_map->append(pos); | | |
| 268 | break; | | |
| 269 | case 'n': | | |
| 270 | buf_append_char(buf, '\n'); | | |
| 271 | if (offset_map) offset_map->append(pos); | | |
| 272 | break; | | |
| 273 | case 't': | | |
| 274 | buf_append_char(buf, '\t'); | | |
| 275 | if (offset_map) offset_map->append(pos); | | |
| 276 | break; | | |
| 277 | case '"': | | |
| 278 | buf_append_char(buf, '"'); | | |
| 279 | if (offset_map) offset_map->append(pos); | 311 | if (offset_map) offset_map->append(pos); |
| | 312 | } |
| | 313 | break; |
| | 314 | case StateEscape: |
| | 315 | switch (c) { |
| | 316 | case '\\': |
| | 317 | buf_append_char(buf, '\\'); |
| | 318 | if (offset_map) offset_map->append(pos); |
| | 319 | state = StateStart; |
| | 320 | break; |
| | 321 | case 'r': |
| | 322 | buf_append_char(buf, '\r'); |
| | 323 | if (offset_map) offset_map->append(pos); |
| | 324 | state = StateStart; |
| | 325 | break; |
| | 326 | case 'n': |
| | 327 | buf_append_char(buf, '\n'); |
| | 328 | if (offset_map) offset_map->append(pos); |
| | 329 | state = StateStart; |
| | 330 | break; |
| | 331 | case 't': |
| | 332 | buf_append_char(buf, '\t'); |
| | 333 | if (offset_map) offset_map->append(pos); |
| | 334 | state = StateStart; |
| | 335 | break; |
| | 336 | case '"': |
| | 337 | buf_append_char(buf, '"'); |
| | 338 | if (offset_map) offset_map->append(pos); |
| | 339 | state = StateStart; |
| | 340 | break; |
| | 341 | case 'x': |
| | 342 | state = StateHex1; |
| | 343 | break; |
| | 344 | default: |
| | 345 | ast_error(pc, token, "invalid escape character"); |
| | 346 | break; |
| | 347 | } |
| | 348 | break; |
| | 349 | case StateHex1: |
| | 350 | { |
| | 351 | int hex_digit = get_hex_digit(c); |
| | 352 | if (hex_digit == -1) { |
| | 353 | ast_error(pc, token, "invalid hex digit: '%c'", c); |
| | 354 | } |
| | 355 | hex_value = hex_digit * 16; |
| | 356 | state = StateHex2; |
| 280 | break; | 357 | break; |
| 281 | case 'x': | 358 | } |
| 282 | zig_panic("TODO"); | 359 | case StateHex2: |
| 283 | break; | 360 | { |
| 284 | default: | 361 | int hex_digit = get_hex_digit(c); |
| 285 | ast_error(pc, token, "invalid escape character"); | 362 | if (hex_digit == -1) { |
| | 363 | ast_error(pc, token, "invalid hex digit: '%c'", c); |
| | 364 | } |
| | 365 | hex_value += hex_digit; |
| | 366 | assert(hex_value >= 0 && hex_value <= 255); |
| | 367 | buf_append_char(buf, hex_value); |
| | 368 | state = StateStart; |
| 286 | break; | 369 | break; |
| 287 | } | 370 | } |
| 288 | escape = false; | | |
| 289 | } else if (c == '\\') { | | |
| 290 | escape = true; | | |
| 291 | } else { | | |
| 292 | buf_append_char(buf, c); | | |
| 293 | if (offset_map) offset_map->append(pos); | | |
| 294 | } | 371 | } |
| 295 | } | 372 | } |
| 296 | if (c == '\n') { | 373 | if (c == '\n') { |
| ... | @@ -300,7 +377,7 @@ static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool | ... | @@ -300,7 +377,7 @@ static void parse_string_literal(ParseContext *pc, Token *token, Buf *buf, bool |
| 300 | pos.column += 1; | 377 | pos.column += 1; |
| 301 | } | 378 | } |
| 302 | } | 379 | } |
| 303 | assert(!escape); | 380 | assert(state == StateStart); |
| 304 | if (offset_map) offset_map->append(pos); | 381 | if (offset_map) offset_map->append(pos); |
| 305 | } | 382 | } |
| 306 | | 383 | |