| author | |
| committer | |
| log | a5251a1c102334a5dcb07e4fcc2b676be55fe2be |
| tree | 459d720365823b10473be028d25ad86b87b825f5 |
| parent | 100e8e15fa087be8975173c03a2f89b227b16730 |
4 files changed, 79 insertions(+), 6 deletions(-)
src/ast_render.cpp+8-4| ... | @@ -251,7 +251,7 @@ static bool is_digit(uint8_t c) { | ... | @@ -251,7 +251,7 @@ static bool is_digit(uint8_t c) { |
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | static bool is_printable(uint8_t c) { | 253 | static bool is_printable(uint8_t c) { |
| 254 | return is_alpha_under(c) || is_digit(c); | 254 | return is_alpha_under(c) || is_digit(c) || c == ' '; |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | static void string_literal_escape(Buf *source, Buf *dest) { | 257 | static void string_literal_escape(Buf *source, Buf *dest) { |
| ... | @@ -463,10 +463,14 @@ static void render_node(AstRender *ar, AstNode *node) { | ... | @@ -463,10 +463,14 @@ static void render_node(AstRender *ar, AstNode *node) { |
| 463 | } | 463 | } |
| 464 | break; | 464 | break; |
| 465 | case NodeTypeStringLiteral: | 465 | case NodeTypeStringLiteral: |
| 466 | if (node->data.string_literal.c) { | 466 | { |
| 467 | fprintf(ar->f, "c"); | 467 | if (node->data.string_literal.c) { |
| 468 | fprintf(ar->f, "c"); | ||
| 469 | } | ||
| 470 | Buf tmp_buf = BUF_INIT; | ||
| 471 | string_literal_escape(&node->data.string_literal.buf, &tmp_buf); | ||
| 472 | fprintf(ar->f, "\"%s\"", buf_ptr(&tmp_buf)); | ||
| 468 | } | 473 | } |
| 469 | fprintf(ar->f, "\"%s\"", buf_ptr(&node->data.string_literal.buf)); | ||
| 470 | break; | 474 | break; |
| 471 | case NodeTypeCharLiteral: | 475 | case NodeTypeCharLiteral: |
| 472 | { | 476 | { |
src/c_tokenizer.cpp+59-2| ... | @@ -539,8 +539,17 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { | ... | @@ -539,8 +539,17 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { |
| 539 | case 'v': | 539 | case 'v': |
| 540 | add_char(ctok, '\v'); | 540 | add_char(ctok, '\v'); |
| 541 | break; | 541 | break; |
| 542 | case DIGIT: | 542 | case '0': |
| 543 | zig_panic("TODO octal"); | 543 | case '1': |
| 544 | case '2': | ||
| 545 | case '3': | ||
| 546 | case '4': | ||
| 547 | case '5': | ||
| 548 | case '6': | ||
| 549 | case '7': | ||
| 550 | ctok->state = CTokStateStrOctal; | ||
| 551 | ctok->cur_char = *c - '0'; | ||
| 552 | ctok->octal_index = 1; | ||
| 544 | break; | 553 | break; |
| 545 | case 'x': | 554 | case 'x': |
| 546 | zig_panic("TODO hex"); | 555 | zig_panic("TODO hex"); |
| ... | @@ -555,6 +564,53 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { | ... | @@ -555,6 +564,53 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { |
| 555 | return mark_error(ctok); | 564 | return mark_error(ctok); |
| 556 | } | 565 | } |
| 557 | break; | 566 | break; |
| 567 | case CTokStateStrOctal: | ||
| 568 | switch (*c) { | ||
| 569 | case '0': | ||
| 570 | case '1': | ||
| 571 | case '2': | ||
| 572 | case '3': | ||
| 573 | case '4': | ||
| 574 | case '5': | ||
| 575 | case '6': | ||
| 576 | case '7': | ||
| 577 | // TODO @mul_with_overflow | ||
| 578 | if (((long)ctok->cur_char) * 8 >= 256) { | ||
| 579 | zig_panic("TODO"); | ||
| 580 | } | ||
| 581 | ctok->cur_char *= 8; | ||
| 582 | // TODO @add_with_overflow | ||
| 583 | if (((long)ctok->cur_char) + (long)(*c - '0') >= 256) { | ||
| 584 | zig_panic("TODO"); | ||
| 585 | } | ||
| 586 | ctok->cur_char += *c - '0'; | ||
| 587 | ctok->octal_index += 1; | ||
| 588 | if (ctok->octal_index == 3) { | ||
| 589 | if (ctok->cur_tok->id == CTokIdStrLit) { | ||
| 590 | add_char(ctok, ctok->cur_char); | ||
| 591 | ctok->state = CTokStateString; | ||
| 592 | } else if (ctok->cur_tok->id == CTokIdCharLit) { | ||
| 593 | ctok->cur_tok->data.char_lit = ctok->cur_char; | ||
| 594 | ctok->state = CTokStateExpectEndQuot; | ||
| 595 | } else { | ||
| 596 | zig_unreachable(); | ||
| 597 | } | ||
| 598 | } | ||
| 599 | break; | ||
| 600 | default: | ||
| 601 | c -= 1; | ||
| 602 | if (ctok->cur_tok->id == CTokIdStrLit) { | ||
| 603 | add_char(ctok, ctok->cur_char); | ||
| 604 | ctok->state = CTokStateString; | ||
| 605 | } else if (ctok->cur_tok->id == CTokIdCharLit) { | ||
| 606 | ctok->cur_tok->data.char_lit = ctok->cur_char; | ||
| 607 | ctok->state = CTokStateExpectEndQuot; | ||
| 608 | } else { | ||
| 609 | zig_unreachable(); | ||
| 610 | } | ||
| 611 | continue; | ||
| 612 | } | ||
| 613 | break; | ||
| 558 | case CTokStateExpectEndQuot: | 614 | case CTokStateExpectEndQuot: |
| 559 | switch (*c) { | 615 | switch (*c) { |
| 560 | case '\'': | 616 | case '\'': |
| ... | @@ -644,6 +700,7 @@ found_end_of_macro: | ... | @@ -644,6 +700,7 @@ found_end_of_macro: |
| 644 | case CTokStateString: | 700 | case CTokStateString: |
| 645 | case CTokStateExpSign: | 701 | case CTokStateExpSign: |
| 646 | case CTokStateFloatExpFirst: | 702 | case CTokStateFloatExpFirst: |
| 703 | case CTokStateStrOctal: | ||
| 647 | return mark_error(ctok); | 704 | return mark_error(ctok); |
| 648 | } | 705 | } |
| 649 | 706 |
src/c_tokenizer.hpp+3| ... | @@ -53,6 +53,7 @@ enum CTokState { | ... | @@ -53,6 +53,7 @@ enum CTokState { |
| 53 | CTokStateExpSign, | 53 | CTokStateExpSign, |
| 54 | CTokStateFloatExp, | 54 | CTokStateFloatExp, |
| 55 | CTokStateFloatExpFirst, | 55 | CTokStateFloatExpFirst, |
| 56 | CTokStateStrOctal, | ||
| 56 | }; | 57 | }; |
| 57 | 58 | ||
| 58 | struct CTokenize { | 59 | struct CTokenize { |
| ... | @@ -63,6 +64,8 @@ struct CTokenize { | ... | @@ -63,6 +64,8 @@ struct CTokenize { |
| 63 | Buf buf; | 64 | Buf buf; |
| 64 | bool unsigned_suffix; | 65 | bool unsigned_suffix; |
| 65 | bool long_suffix; | 66 | bool long_suffix; |
| 67 | uint8_t cur_char; | ||
| 68 | int octal_index; | ||
| 66 | }; | 69 | }; |
| 67 | 70 | ||
| 68 | void tokenize_c_macro(CTokenize *ctok, const uint8_t *c); | 71 | void tokenize_c_macro(CTokenize *ctok, const uint8_t *c); |
test/run_tests.cpp+9| ... | @@ -1731,6 +1731,15 @@ struct type { | ... | @@ -1731,6 +1731,15 @@ struct type { |
| 1731 | )SOURCE", 2, R"(export struct struct_type { | 1731 | )SOURCE", 2, R"(export struct struct_type { |
| 1732 | @"defer": c_int, | 1732 | @"defer": c_int, |
| 1733 | })", R"(pub const @"type" = struct_type;)"); | 1733 | })", R"(pub const @"type" = struct_type;)"); |
| 1734 | |||
| 1735 | add_parseh_case("macro defines string literal with octal", R"SOURCE( | ||
| 1736 | #define FOO "aoeu\023 derp" | ||
| 1737 | #define FOO2 "aoeu\0234 derp" | ||
| 1738 | #define FOO_CHAR '\077' | ||
| 1739 | )SOURCE", 3, | ||
| 1740 | R"(pub const FOO = c"aoeu\x13 derp")", | ||
| 1741 | R"(pub const FOO2 = c"aoeu\x134 derp")", | ||
| 1742 | R"(pub const FOO_CHAR = '\x3f')"); | ||
| 1734 | } | 1743 | } |
| 1735 | 1744 | ||
| 1736 | static void run_self_hosted_test(bool is_release_mode) { | 1745 | static void run_self_hosted_test(bool is_release_mode) { |