| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -459,6 +459,54 @@ constexpr auto as( std::optional<T> const& x ) -> auto&& | |||
| 459 | 459 | { return x.value(); } | |
| 460 | 460 | ||
| 461 | 461 | ||
| 462 | + //----------------------------------------------------------------------- | ||
| 463 | + // | ||
| 464 | + // A variation of GSL's final_action_success and finally to run only on success | ||
| 465 | + // (based on a PR I contributed to Microsoft GSL) | ||
| 466 | + // | ||
| 467 | + // final_action_success_success ensures something is run at the end of a scope | ||
| 468 | + // if no exception is thrown | ||
| 469 | + // | ||
| 470 | + // finally_success is a convenience function to make a final_action_success_success | ||
| 471 | + // | ||
| 472 | + //----------------------------------------------------------------------- | ||
| 473 | + // | ||
| 474 | + | ||
| 475 | + template <class F> | ||
| 476 | + class final_action_success | ||
| 477 | + { | ||
| 478 | + public: | ||
| 479 | + explicit final_action_success(const F& ff) noexcept : f{ff} { } | ||
| 480 | + explicit final_action_success(F&& ff) noexcept : f{std::move(ff)} { } | ||
| 481 | + | ||
| 482 | + ~final_action_success() noexcept | ||
| 483 | + { | ||
| 484 | + if (invoke && ecount == std::uncaught_exceptions()) { | ||
| 485 | + f(); | ||
| 486 | + } | ||
| 487 | + } | ||
| 488 | + | ||
| 489 | + final_action_success(final_action_success&& other) noexcept | ||
| 490 | + : f(std::move(other.f)), invoke(std::exchange(other.invoke, false)) | ||
| 491 | + { } | ||
| 492 | + | ||
| 493 | + final_action_success(const final_action_success&) = delete; | ||
| 494 | + void operator=(const final_action_success&) = delete; | ||
| 495 | + void operator=(final_action_success&&) = delete; | ||
| 496 | + | ||
| 497 | + private: | ||
| 498 | + F f; | ||
| 499 | + int ecount = std::uncaught_exceptions(); | ||
| 500 | + bool invoke = true; | ||
| 501 | + }; | ||
| 502 | + | ||
| 503 | + template <class F> | ||
| 504 | + [[nodiscard]] auto finally_success(F&& f) noexcept | ||
| 505 | + { | ||
| 506 | + return final_action_success<std::remove_cvref_t<F>>{std::forward<F>(f)}; | ||
| 507 | + } | ||
| 508 | + | ||
| 509 | + | ||
| 462 | 510 | //----------------------------------------------------------------------- | |
| 463 | 511 | // | |
| 464 | 512 | // to_string for string interpolation | |
@@ -482,7 +530,7 @@ auto to_string(std::optional<T> const& o) -> std::string { | |||
| 482 | 530 | if (o.has_value()) { | |
| 483 | 531 | return std::to_string(o.value()); | |
| 484 | 532 | } | |
| 485 | - return "nullopt"; | ||
| 533 | + return "(empty)"; | ||
| 486 | 534 | } | |
| 487 | 535 | ||
| 488 | 536 | ||
@@ -513,46 +561,6 @@ constexpr auto narrow_cast(From&& from) noexcept -> To | |||
| 513 | 561 | return static_cast<To>(std::forward<From>(from)); | |
| 514 | 562 | } | |
| 515 | 563 | ||
| 516 | - | ||
| 517 | - //----------------------------------------------------------------------- | ||
| 518 | - // | ||
| 519 | - // An implementation of GSL's final_action and finally | ||
| 520 | - // (based on a PR I contributed to Microsoft GSL) | ||
| 521 | - // | ||
| 522 | - // final_action ensures something is run at the end of a scope | ||
| 523 | - // | ||
| 524 | - // finally is a convenience function to generate a final_action | ||
| 525 | - // | ||
| 526 | - //----------------------------------------------------------------------- | ||
| 527 | - // | ||
| 528 | - template <class F> | ||
| 529 | - class final_action | ||
| 530 | - { | ||
| 531 | - public: | ||
| 532 | - explicit final_action(const F& ff) noexcept : f{ff} { } | ||
| 533 | - explicit final_action(F&& ff) noexcept : f{std::move(ff)} { } | ||
| 534 | - | ||
| 535 | - ~final_action() noexcept { if (invoke) f(); } | ||
| 536 | - | ||
| 537 | - final_action(final_action&& other) noexcept | ||
| 538 | - : f(std::move(other.f)), invoke(std::exchange(other.invoke, false)) | ||
| 539 | - { } | ||
| 540 | - | ||
| 541 | - final_action(const final_action&) = delete; | ||
| 542 | - void operator=(const final_action&) = delete; | ||
| 543 | - void operator=(final_action&&) = delete; | ||
| 544 | - | ||
| 545 | - private: | ||
| 546 | - F f; | ||
| 547 | - bool invoke = true; | ||
| 548 | - }; | ||
| 549 | - | ||
| 550 | - template <class F> | ||
| 551 | - [[nodiscard]] auto finally(F&& f) noexcept | ||
| 552 | - { | ||
| 553 | - return final_action<std::remove_cvref_t<F>>{std::forward<F>(f)}; | ||
| 554 | - } | ||
| 555 | - | ||
| 556 | 564 | } | |
| 557 | 565 | ||
| 558 | 566 | #endif | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -29,7 +29,7 @@ std::vector<int> vec { }; | |||
| 29 | 29 | auto insert_at(cpp2::in<int> where, cpp2::in<int> val) -> void | |
| 30 | 30 | { | |
| 31 | 31 | cpp2::Default.expects(0 <= where && where <= CPP2_UFCS_0(ssize, vec), ""); | |
| 32 | - auto final18_5 = gsl::finally([_0 = CPP2_UFCS_0(ssize, vec)]{cpp2::Default.expects(CPP2_UFCS_0(ssize, vec) == _0 + 1, "");} ); | ||
| 32 | + auto post_18_5 = cpp2::finally_success([_0 = CPP2_UFCS_0(ssize, vec)]{cpp2::Default.expects(CPP2_UFCS_0(ssize, vec) == _0 + 1, "");} ); | ||
| 33 | 33 | #line 18 "mixed-captures-in-expressions-and-postconditions.cpp2" | |
| 34 | 34 | ||
| 35 | 35 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -27,7 +27,7 @@ std::vector<int> vec { }; | |||
| 27 | 27 | auto insert_at(cpp2::in<int> where, cpp2::in<int> val) -> void | |
| 28 | 28 | { | |
| 29 | 29 | cpp2::Default.expects(0 <= where && where <= CPP2_UFCS_0(ssize, vec), ""); | |
| 30 | - auto final16_5 = gsl::finally([_0 = CPP2_UFCS_0(size, vec)]{cpp2::Default.expects(CPP2_UFCS_0(size, vec) == _0 + 1, "");} ); | ||
| 30 | + auto post_16_5 = cpp2::finally_success([_0 = CPP2_UFCS_0(size, vec)]{cpp2::Default.expects(CPP2_UFCS_0(size, vec) == _0 + 1, "");} ); | ||
| 31 | 31 | #line 16 "mixed-postexpression-with-capture.cpp2" | |
| 32 | 32 | ||
| 33 | 33 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,20 @@ | |||
| 1 | + // ----- Cpp2 support ----- | ||
| 2 | + #include "cpp2util.h" | ||
| 3 | + | ||
| 4 | + #line 1 "mixed-string-interpolation.cpp2" | ||
| 5 | + #include <iostream> | ||
| 6 | + | ||
| 7 | + [[nodiscard]] auto main() -> int; | ||
| 8 | + | ||
| 9 | + //=== Cpp2 definitions ========================================================== | ||
| 10 | + | ||
| 11 | + #line 2 "mixed-string-interpolation.cpp2" | ||
| 12 | + | ||
| 13 | + [[nodiscard]] auto main() -> int{ | ||
| 14 | + auto a { 2 }; | ||
| 15 | + std::optional<int> b { }; | ||
| 16 | + std::cout << "a = " + cpp2::to_string(a) + ", b = " + cpp2::to_string(b) + "\n"; | ||
| 17 | + | ||
| 18 | + b = 42; | ||
| 19 | + std::cout << "a^2 + b = " + cpp2::to_string(a * a + b.value()) + "\n"; | ||
| 20 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,10 @@ | |||
| 1 | + #include <iostream> | ||
| 2 | + | ||
| 3 | + main: () -> int = { | ||
| 4 | + a := 2; | ||
| 5 | + b: std::optional<int> = (); | ||
| 6 | + std::cout << "a = (a)$, b = (b)$\n"; | ||
| 7 | + | ||
| 8 | + b = 42; | ||
| 9 | + std::cout << "a^2 + b = (a * a + b.value())$\n"; | ||
| 10 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,2 @@ | |||
| 1 | + mixed-string-interpolation.cpp2... ok (mixed Cpp1/Cpp2, Cpp2 code passes safety checks) | ||
| 2 | + | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -846,13 +846,127 @@ class cppfront | |||
| 846 | 846 | } | |
| 847 | 847 | ||
| 848 | 848 | ||
| 849 | + //----------------------------------------------------------------------- | ||
| 850 | + // | ||
| 851 | + // A StringLiteral could include captures | ||
| 852 | + // | ||
| 853 | + auto expand_string_literal(token const& n) -> std::string | ||
| 854 | + { | ||
| 855 | + assert(n.type() == lexeme::StringLiteral); | ||
| 856 | + | ||
| 857 | + auto text = std::string_view(n); | ||
| 858 | + auto length = n.length(); | ||
| 859 | + assert (std::ssize(text) == length); | ||
| 860 | + | ||
| 861 | + assert(length >= 2); | ||
| 862 | + assert(text.back() == '"'); | ||
| 863 | + | ||
| 864 | + auto pos = 0; | ||
| 865 | + auto ret = std::string{}; // the return string we're going to build | ||
| 866 | + auto current_start = 0; // the current offset before which the string has been into ret | ||
| 867 | + | ||
| 868 | + // Skip prefix to first non-" character | ||
| 869 | + while (pos < length && text[pos] != '"') { | ||
| 870 | + ++pos; | ||
| 871 | + } | ||
| 872 | + assert(pos < length && text[pos] == '"'); | ||
| 873 | + ++pos; | ||
| 874 | + | ||
| 875 | + // Now we're on the first character of the string itself | ||
| 876 | + for ( ; pos < length && text[pos] != '"'; ++pos) | ||
| 877 | + { | ||
| 878 | + // Find the next )$ | ||
| 879 | + if (text[pos] == '$' && text[pos-1] == ')') | ||
| 880 | + { | ||
| 881 | + // Scan back to find the matching ( | ||
| 882 | + auto paren_depth = 1; | ||
| 883 | + auto open = pos - 2; | ||
| 884 | + for( ; text[open] != '"'; --open) | ||
| 885 | + { | ||
| 886 | + if (text[open] == ')') { | ||
| 887 | + ++paren_depth; | ||
| 888 | + } | ||
| 889 | + else if (text[open] == '(') { | ||
| 890 | + --paren_depth; | ||
| 891 | + if (paren_depth == 0) { | ||
| 892 | + break; | ||
| 893 | + } | ||
| 894 | + } | ||
| 895 | + else if ( | ||
| 896 | + (text[open] == '-' && text[open - 1] == '-') || | ||
| 897 | + (text[open] == '-' && text[open - 1] == '-') | ||
| 898 | + ) | ||
| 899 | + { | ||
| 900 | + errors.emplace_back( | ||
| 901 | + source_position( n.position().lineno, n.position().colno + pos ), | ||
| 902 | + "a string interpolation expression may not contain ++ or --" | ||
| 903 | + ); | ||
| 904 | + return ""; | ||
| 905 | + } | ||
| 906 | + else if ( | ||
| 907 | + (text[open] == '*' && !isspace(text[open - 1])) || | ||
| 908 | + (text[open] == '&' && !isspace(text[open - 1])) || | ||
| 909 | + (text[open] == '!' && !isspace(text[open - 1])) | ||
| 910 | + ) | ||
| 911 | + { | ||
| 912 | + errors.emplace_back( | ||
| 913 | + source_position( n.position().lineno, n.position().colno + pos ), | ||
| 914 | + "a string interpolation expression may not contain unary *, &, or ~ (if you meant binary, add a space before the operator)" | ||
| 915 | + ); | ||
| 916 | + return ""; | ||
| 917 | + } | ||
| 918 | + } | ||
| 919 | + if (text[open] == '"') | ||
| 920 | + { | ||
| 921 | + errors.emplace_back( | ||
| 922 | + source_position( n.position().lineno, n.position().colno + pos ), | ||
| 923 | + "no matching ( for string interpolation ending in )$" | ||
| 924 | + ); | ||
| 925 | + return ""; | ||
| 926 | + } | ||
| 927 | + assert (text[open] == '('); | ||
| 928 | + | ||
| 929 | + // 'open' is now at the matching ( | ||
| 930 | + | ||
| 931 | + // Put the next non-interpolated chunk straight into ret | ||
| 932 | + if (current_start > 0) { | ||
| 933 | + ret += '"'; | ||
| 934 | + } | ||
| 935 | + ret += text.substr(current_start, open - current_start); | ||
| 936 | + ret += '"'; | ||
| 937 | + | ||
| 938 | + // Then put interpolated chunk into ret | ||
| 939 | + ret += " + cpp2::to_string"; | ||
| 940 | + ret += text.substr(open, pos - open); | ||
| 941 | + ret += " + "; | ||
| 942 | + | ||
| 943 | + current_start = pos+1; | ||
| 944 | + } | ||
| 945 | + } | ||
| 946 | + | ||
| 947 | + // Now we should be on the the final " closing the string | ||
| 948 | + assert(pos == length-1 && text[pos] == '"'); | ||
| 949 | + | ||
| 950 | + // Put the final non-interpolated chunk straight into ret | ||
| 951 | + if (current_start > 0) { | ||
| 952 | + ret += '"'; | ||
| 953 | + } | ||
| 954 | + ret += text.substr(current_start); | ||
| 955 | + | ||
| 956 | + return ret; | ||
| 957 | + } | ||
| 958 | + | ||
| 959 | + | ||
| 849 | 960 | //----------------------------------------------------------------------- | |
| 850 | 961 | // | |
| 851 | 962 | auto emit(token const& n) -> void | |
| 852 | 963 | { | |
| 853 | 964 | if (n == "new") { | |
| 854 | 965 | printer.print_cpp2("cpp2_new", n.position()); | |
| 855 | 966 | } | |
| 967 | + else if (n.type() == lexeme::StringLiteral) { | ||
| 968 | + printer.print_cpp2( expand_string_literal(n), n.position() ); | ||
| 969 | + } | ||
| 856 | 970 | else { | |
| 857 | 971 | printer.print_cpp2(n, n.position()); | |
| 858 | 972 | } | |
@@ -1880,13 +1994,13 @@ class cppfront | |||
| 1880 | 1994 | { | |
| 1881 | 1995 | assert (n.kind); | |
| 1882 | 1996 | ||
| 1883 | - // For a postcondition, we'll wrap it in a final_action lambda | ||
| 1997 | + // For a postcondition, we'll wrap it in a final_action_success lambda | ||
| 1884 | 1998 | // | |
| 1885 | 1999 | if (*n.kind == "post") { | |
| 1886 | 2000 | auto lambda_intro = build_capture_lambda_intro_for(n.captures, n.position()); | |
| 1887 | 2001 | printer.print_cpp2( | |
| 1888 | - "auto final" + std::to_string(n.position().lineno) + "_" + | ||
| 1889 | - std::to_string(n.position().colno) + " = gsl::finally(" + | ||
| 2002 | + "auto post_" + std::to_string(n.position().lineno) + "_" + | ||
| 2003 | + std::to_string(n.position().colno) + " = cpp2::finally_success(" + | ||
| 1890 | 2004 | lambda_intro + "{", | |
| 1891 | 2005 | n.position() | |
| 1892 | 2006 | ); | |
@@ -1934,7 +2048,7 @@ class cppfront | |||
| 1934 | 2048 | } | |
| 1935 | 2049 | printer.print_cpp2(");", n.position()); | |
| 1936 | 2050 | ||
| 1937 | - // For a postcondition, close out the final_action lambda | ||
| 2051 | + // For a postcondition, close out the final_action_success lambda | ||
| 1938 | 2052 | // | |
| 1939 | 2053 | if (*n.kind == "post") { | |
| 1940 | 2054 | printer.print_cpp2( "} );", n.position() | |
| Back | FazBrowse Home | New Git URL |
0 commit comments