diff --git a/include/cpp2util.h b/include/cpp2util.h index 9f26085c5..c824bf08c 100644 --- a/include/cpp2util.h +++ b/include/cpp2util.h @@ -391,7 +391,7 @@ class contract_group { public: using handler = void (*)(CPP2_MESSAGE_PARAM msg CPP2_SOURCE_LOCATION_PARAM); - constexpr contract_group (handler h = {}) : reporter(h) { } + constexpr contract_group (handler h) : reporter{h} { } constexpr auto set_handler(handler h); constexpr auto get_handler() const -> handler { return reporter; } constexpr auto expects (bool b, CPP2_MESSAGE_PARAM msg = "" CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT) diff --git a/source/parse.h b/source/parse.h index 51076fba5..bc320d39c 100644 --- a/source/parse.h +++ b/source/parse.h @@ -2987,7 +2987,7 @@ struct declaration_node } - auto add_type_member( std::unique_ptr statement ) + auto add_type_member( std::unique_ptr&& statement ) -> bool { if ( @@ -3019,6 +3019,23 @@ struct declaration_node } + auto add_function_initializer( std::unique_ptr&& statement ) + -> bool + { + if ( + !is_function() + || initializer + ) + { + return false; + } + + // Adopt it as our initializer statement + initializer = std::move( statement ); + return true; + } + + auto get_decl_if_type_scope_object_name_before_a_base_type( std::string_view s ) const -> declaration_node const* { @@ -3388,6 +3405,20 @@ struct declaration_node return false; } + auto get_function_parameters() + -> std::vector + { + if (!is_function()) { + return {}; + } + // else + auto ret = std::vector{}; + for (auto& param : std::get(type)->parameters->parameters) { + ret.push_back( param.get() ); + } + return ret; + } + auto unnamed_return_type_to_string() const -> std::string { @@ -5281,17 +5312,22 @@ class parser tokens = &tokens_; generated_tokens = &generated_tokens_; - // Parse one declaration - we succeed if the parse succeeded, - // and there were no new errors, and all tokens were consumed - auto errors_size = std::ssize(errors); - pos = 0; - if (auto d = statement(); - d - && std::ssize(errors) == errors_size - && done() - ) - { - return d; + try { + // Parse one declaration - we succeed if the parse succeeded, + // and there were no new errors, and all tokens were consumed + auto errors_size = std::ssize(errors); + pos = 0; + if (auto d = statement(); + d + && std::ssize(errors) == errors_size + && done() + ) + { + return d; + } + } + catch(std::runtime_error& e) { + error(e.what(), true, {}, true); } return {}; diff --git a/source/reflect.h b/source/reflect.h index 11596cde1..d1410315f 100644 --- a/source/reflect.h +++ b/source/reflect.h @@ -18,28 +18,28 @@ namespace meta { #line 32 "reflect.h2" class compiler_services; -#line 193 "reflect.h2" +#line 218 "reflect.h2" class declaration_base; -#line 219 "reflect.h2" +#line 244 "reflect.h2" class declaration; -#line 301 "reflect.h2" +#line 326 "reflect.h2" class function_declaration; -#line 360 "reflect.h2" +#line 413 "reflect.h2" class object_declaration; -#line 396 "reflect.h2" +#line 449 "reflect.h2" class type_declaration; -#line 509 "reflect.h2" +#line 584 "reflect.h2" class alias_declaration; -#line 848 "reflect.h2" +#line 923 "reflect.h2" class value_member_info; -#line 1363 "reflect.h2" +#line 1438 "reflect.h2" } } @@ -82,6 +82,8 @@ namespace meta { class compiler_services { + // Common data members + // private: std::vector* errors; private: int errors_original_size; private: std::deque* generated_tokens; @@ -90,45 +92,62 @@ class compiler_services private: std::vector metafunction_args {}; private: bool metafunctions_used {false}; + // Constructor + // public: explicit compiler_services( std::vector* errors_, std::deque* generated_tokens_ ); -#line 54 "reflect.h2" +#line 58 "reflect.h2" + // Common API + // public: auto set_metafunction_name(cpp2::in name, cpp2::in> args) & -> void; -#line 60 "reflect.h2" +#line 66 "reflect.h2" public: [[nodiscard]] auto get_metafunction_name() const& -> std::string_view; public: [[nodiscard]] auto get_argument(cpp2::in index) & -> std::string; -#line 70 "reflect.h2" +#line 76 "reflect.h2" + public: [[nodiscard]] auto get_arguments() & -> std::vector; + +#line 81 "reflect.h2" public: [[nodiscard]] auto arguments_were_used() const& -> bool; +using parse_statement_ret = std::unique_ptr; + +#line 83 "reflect.h2" protected: [[nodiscard]] auto parse_statement( std::string_view source - ) & -> std::unique_ptr; + ) & -> parse_statement_ret; -#line 120 "reflect.h2" +#line 136 "reflect.h2" public: [[nodiscard]] virtual auto position() const -> source_position; -#line 126 "reflect.h2" +#line 142 "reflect.h2" + // Error diagnosis and handling, integrated with compiler output + // public: auto require( cpp2::in b, cpp2::in msg ) const& -> void; -#line 137 "reflect.h2" +#line 155 "reflect.h2" public: auto error(cpp2::in msg) const& -> void; + +#line 164 "reflect.h2" + // Enable custom contracts on this object + // + public: auto expects(auto const& b, auto const& msg) const& -> void; public: virtual ~compiler_services() noexcept; public: compiler_services(compiler_services const& that); -#line 145 "reflect.h2" +#line 170 "reflect.h2" }; /* @@ -167,7 +186,7 @@ type_id: @polymorphic_base @copyable type = } */ -#line 184 "reflect.h2" +#line 209 "reflect.h2" //----------------------------------------------------------------------- // // Declarations @@ -180,7 +199,7 @@ type_id: @polymorphic_base @copyable type = class declaration_base : public compiler_services { -#line 197 "reflect.h2" +#line 222 "reflect.h2" protected: declaration_node* n; protected: explicit declaration_base( @@ -189,31 +208,31 @@ class declaration_base cpp2::in s ); -#line 210 "reflect.h2" +#line 235 "reflect.h2" public: [[nodiscard]] auto position() const -> source_position override; public: [[nodiscard]] auto print() const& -> std::string; public: virtual ~declaration_base() noexcept; public: declaration_base(declaration_base const& that); -#line 213 "reflect.h2" +#line 238 "reflect.h2" }; -#line 216 "reflect.h2" +#line 241 "reflect.h2" //----------------------------------------------------------------------- // All declarations // class declaration : public declaration_base { -#line 223 "reflect.h2" +#line 248 "reflect.h2" public: explicit declaration( declaration_node* n_, cpp2::in s ); -#line 232 "reflect.h2" +#line 257 "reflect.h2" public: [[nodiscard]] auto is_public() const& -> bool; public: [[nodiscard]] auto is_protected() const& -> bool; public: [[nodiscard]] auto is_private() const& -> bool; @@ -232,7 +251,7 @@ class declaration public: [[nodiscard]] auto name() const& -> std::string_view; -#line 253 "reflect.h2" +#line 278 "reflect.h2" public: [[nodiscard]] auto has_initializer() const& -> bool; public: [[nodiscard]] auto is_global() const& -> bool; @@ -275,24 +294,24 @@ public: declaration(declaration const& that); // this precondition should be sufficient ... -#line 295 "reflect.h2" +#line 320 "reflect.h2" }; -#line 298 "reflect.h2" +#line 323 "reflect.h2" //----------------------------------------------------------------------- // Function declarations // class function_declaration : public declaration { -#line 305 "reflect.h2" +#line 330 "reflect.h2" public: explicit function_declaration( declaration_node* n_, cpp2::in s ); -#line 315 "reflect.h2" +#line 340 "reflect.h2" public: [[nodiscard]] auto index_of_parameter_named(cpp2::in s) const& -> int; public: [[nodiscard]] auto has_parameter_named(cpp2::in s) const& -> bool; public: [[nodiscard]] auto has_in_parameter_named(cpp2::in s) const& -> bool; @@ -327,107 +346,116 @@ class function_declaration public: [[nodiscard]] auto unnamed_return_type() const& -> std::string; + public: [[nodiscard]] auto get_parameters() const& -> std::vector; + +#line 384 "reflect.h2" public: [[nodiscard]] auto is_binary_comparison_function() const& -> bool; public: auto default_to_virtual() & -> void; public: [[nodiscard]] auto make_virtual() & -> bool; + + public: auto add_initializer(cpp2::in source) & -> void; public: function_declaration(function_declaration const& that); -#line 354 "reflect.h2" + +#line 407 "reflect.h2" }; -#line 357 "reflect.h2" +#line 410 "reflect.h2" //----------------------------------------------------------------------- // Object declarations // class object_declaration : public declaration { -#line 364 "reflect.h2" +#line 417 "reflect.h2" public: explicit object_declaration( declaration_node* n_, cpp2::in s ); -#line 374 "reflect.h2" +#line 427 "reflect.h2" public: [[nodiscard]] auto is_const() const& -> bool; public: [[nodiscard]] auto has_wildcard_type() const& -> bool; public: [[nodiscard]] auto type() const& -> std::string; -#line 384 "reflect.h2" +#line 437 "reflect.h2" public: [[nodiscard]] auto initializer() const& -> std::string; public: object_declaration(object_declaration const& that); -#line 390 "reflect.h2" +#line 443 "reflect.h2" }; -#line 393 "reflect.h2" +#line 446 "reflect.h2" //----------------------------------------------------------------------- // Type declarations // class type_declaration : public declaration { -#line 400 "reflect.h2" +#line 453 "reflect.h2" public: explicit type_declaration( declaration_node* n_, cpp2::in s ); -#line 410 "reflect.h2" +#line 463 "reflect.h2" public: auto reserve_names(cpp2::in name, auto&& ...etc) const& -> void; -#line 422 "reflect.h2" +#line 475 "reflect.h2" public: [[nodiscard]] auto is_polymorphic() const& -> bool; public: [[nodiscard]] auto is_final() const& -> bool; public: [[nodiscard]] auto make_final() & -> bool; public: [[nodiscard]] auto get_member_functions() const& -> std::vector; -#line 436 "reflect.h2" +#line 490 "reflect.h2" + public: [[nodiscard]] auto get_member_functions_needing_initializer() const& -> std::vector; + +#line 505 "reflect.h2" public: [[nodiscard]] auto get_member_objects() const& -> std::vector; -#line 446 "reflect.h2" +#line 515 "reflect.h2" public: [[nodiscard]] auto get_member_types() const& -> std::vector; -#line 456 "reflect.h2" +#line 525 "reflect.h2" public: [[nodiscard]] auto get_member_aliases() const& -> std::vector; -#line 466 "reflect.h2" +#line 535 "reflect.h2" public: [[nodiscard]] auto get_members() const& -> std::vector; struct query_declared_value_set_functions_ret { bool out_this_in_that; bool out_this_move_that; bool inout_this_in_that; bool inout_this_move_that; }; -#line 476 "reflect.h2" +#line 545 "reflect.h2" public: [[nodiscard]] auto query_declared_value_set_functions() const& -> query_declared_value_set_functions_ret; -#line 491 "reflect.h2" +#line 560 "reflect.h2" public: auto add_member(cpp2::in source) & -> void; -#line 499 "reflect.h2" +#line 574 "reflect.h2" public: auto remove_marked_members() & -> void; public: auto remove_all_members() & -> void; public: auto disable_member_function_generation() & -> void; public: type_declaration(type_declaration const& that); -#line 503 "reflect.h2" +#line 578 "reflect.h2" }; -#line 506 "reflect.h2" +#line 581 "reflect.h2" //----------------------------------------------------------------------- // Alias declarations // class alias_declaration : public declaration { -#line 513 "reflect.h2" +#line 588 "reflect.h2" public: explicit alias_declaration( declaration_node* n_, @@ -436,10 +464,10 @@ class alias_declaration public: alias_declaration(alias_declaration const& that); -#line 522 "reflect.h2" +#line 597 "reflect.h2" }; -#line 525 "reflect.h2" +#line 600 "reflect.h2" //----------------------------------------------------------------------- // // Metafunctions - these are hardwired for now until we get to the @@ -454,7 +482,7 @@ class alias_declaration // auto add_virtual_destructor(meta::type_declaration& t) -> void; -#line 543 "reflect.h2" +#line 618 "reflect.h2" //----------------------------------------------------------------------- // // "... an abstract base class defines an interface ..." @@ -469,7 +497,7 @@ auto add_virtual_destructor(meta::type_declaration& t) -> void; // auto interface(meta::type_declaration& t) -> void; -#line 582 "reflect.h2" +#line 657 "reflect.h2" //----------------------------------------------------------------------- // // "C.35: A base class destructor should be either public and @@ -491,7 +519,7 @@ auto interface(meta::type_declaration& t) -> void; // auto polymorphic_base(meta::type_declaration& t) -> void; -#line 626 "reflect.h2" +#line 701 "reflect.h2" //----------------------------------------------------------------------- // // "... A totally ordered type ... requires operator<=> that @@ -517,7 +545,7 @@ auto ordered_impl( cpp2::in ordering// must be "strong_ordering" etc. ) -> void; -#line 670 "reflect.h2" +#line 745 "reflect.h2" //----------------------------------------------------------------------- // ordered - a totally ordered type // @@ -525,19 +553,19 @@ auto ordered_impl( // auto ordered(meta::type_declaration& t) -> void; -#line 680 "reflect.h2" +#line 755 "reflect.h2" //----------------------------------------------------------------------- // weakly_ordered - a weakly ordered type // auto weakly_ordered(meta::type_declaration& t) -> void; -#line 688 "reflect.h2" +#line 763 "reflect.h2" //----------------------------------------------------------------------- // partially_ordered - a partially ordered type // auto partially_ordered(meta::type_declaration& t) -> void; -#line 697 "reflect.h2" +#line 772 "reflect.h2" //----------------------------------------------------------------------- // // "A value is ... a regular type. It must have all public @@ -556,7 +584,7 @@ auto partially_ordered(meta::type_declaration& t) -> void; // auto copyable(meta::type_declaration& t) -> void; -#line 734 "reflect.h2" +#line 809 "reflect.h2" //----------------------------------------------------------------------- // // basic_value @@ -566,11 +594,11 @@ auto copyable(meta::type_declaration& t) -> void; // auto basic_value(meta::type_declaration& t) -> void; -#line 759 "reflect.h2" +#line 834 "reflect.h2" //----------------------------------------------------------------------- // // "A 'value' is a totally ordered basic_value..." -// +// // -- P0707R4, section 3 // // value - a value type that is totally ordered @@ -579,13 +607,13 @@ auto basic_value(meta::type_declaration& t) -> void; // auto value(meta::type_declaration& t) -> void; -#line 775 "reflect.h2" +#line 850 "reflect.h2" auto weakly_ordered_value(meta::type_declaration& t) -> void; -#line 781 "reflect.h2" +#line 856 "reflect.h2" auto partially_ordered_value(meta::type_declaration& t) -> void; -#line 788 "reflect.h2" +#line 863 "reflect.h2" //----------------------------------------------------------------------- // // "By definition, a `struct` is a `class` in which members @@ -613,7 +641,7 @@ auto partially_ordered_value(meta::type_declaration& t) -> void; // auto cpp2_struct(meta::type_declaration& t) -> void; -#line 831 "reflect.h2" +#line 906 "reflect.h2" //----------------------------------------------------------------------- // // "C enumerations constitute a curiously half-baked concept. ... @@ -643,32 +671,32 @@ auto basic_enum( cpp2::in bitwise ) -> void; -#line 1035 "reflect.h2" +#line 1110 "reflect.h2" //----------------------------------------------------------------------- // // "An enum[...] is a totally ordered value type that stores a // value of its enumerators's type, and otherwise has only public // member variables of its enumerator's type, all of which are // naturally scoped because they are members of a type." -// +// // -- P0707R4, section 3 // auto cpp2_enum(meta::type_declaration& t) -> void; -#line 1061 "reflect.h2" +#line 1136 "reflect.h2" //----------------------------------------------------------------------- // -// "flag_enum expresses an enumeration that stores values +// "flag_enum expresses an enumeration that stores values // corresponding to bitwise-or'd enumerators. The enumerators must // be powers of two, and are automatically generated [...] A none // value is provided [...] Operators | and & are provided to // combine and extract values." -// +// // -- P0707R4, section 3 // auto flag_enum(meta::type_declaration& t) -> void; -#line 1093 "reflect.h2" +#line 1168 "reflect.h2" //----------------------------------------------------------------------- // // "As with void*, programmers should know that unions [...] are @@ -677,10 +705,10 @@ auto flag_enum(meta::type_declaration& t) -> void; // // -- Stroustrup (The Design and Evolution of C++, 14.3.4.1) // -// "C++17 needs a type-safe union... The implications of the -// consensus `variant` design are well understood and have been -// explored over several LEWG discussions, over a thousand emails, -// a joint LEWG/EWG session, and not to mention 12 years of +// "C++17 needs a type-safe union... The implications of the +// consensus `variant` design are well understood and have been +// explored over several LEWG discussions, over a thousand emails, +// a joint LEWG/EWG session, and not to mention 12 years of // experience with Boost and other libraries." // // -- Axel Naumann, in P0088 (wg21.link/p0088), @@ -689,20 +717,20 @@ auto flag_enum(meta::type_declaration& t) -> void; //----------------------------------------------------------------------- // // union -// +// // a type that contains exactly one of a fixed set of values at a time -// +// auto cpp2_union(meta::type_declaration& t) -> void; -#line 1249 "reflect.h2" +#line 1324 "reflect.h2" //----------------------------------------------------------------------- // // print - output a pretty-printed visualization of t // auto print(cpp2::in t) -> void; -#line 1259 "reflect.h2" +#line 1334 "reflect.h2" //----------------------------------------------------------------------- // // apply_metafunctions @@ -713,7 +741,7 @@ auto print(cpp2::in t) -> void; auto const& error ) -> bool; -#line 1363 "reflect.h2" +#line 1438 "reflect.h2" } } @@ -728,7 +756,7 @@ namespace cpp2 { namespace meta { -#line 42 "reflect.h2" +#line 46 "reflect.h2" compiler_services::compiler_services( std::vector* errors_, @@ -738,12 +766,13 @@ namespace meta { , errors_original_size{ cpp2::unsafe_narrow(std::ssize(*cpp2::assert_not_null(errors))) } , generated_tokens{ generated_tokens_ } , parser{ *cpp2::assert_not_null(errors) } -#line 47 "reflect.h2" +#line 51 "reflect.h2" { -#line 52 "reflect.h2" +#line 56 "reflect.h2" } +#line 60 "reflect.h2" auto compiler_services::set_metafunction_name(cpp2::in name, cpp2::in> args) & -> void{ metafunction_name = name; metafunction_args = args; @@ -760,14 +789,23 @@ namespace meta { return ""; } + [[nodiscard]] auto compiler_services::get_arguments() & -> std::vector{ + metafunctions_used = true; + return metafunction_args; + } + [[nodiscard]] auto compiler_services::arguments_were_used() const& -> bool { return metafunctions_used; } [[nodiscard]] auto compiler_services::parse_statement( std::string_view source - ) & -> std::unique_ptr + ) & -> parse_statement_ret { + cpp2::deferred_init> ret; +#line 89 "reflect.h2" + auto original_source {source}; + CPP2_UFCS(push_back)(generated_lines, std::vector()); auto lines {&CPP2_UFCS(back)(generated_lines)}; @@ -780,7 +818,7 @@ auto newline_pos = CPP2_UFCS(find)(source, '\n'); // First split this string into source_lines // -#line 88 "reflect.h2" +#line 101 "reflect.h2" if ( cpp2::cmp_greater(CPP2_UFCS(ssize)(source),1) && newline_pos != source.npos) { @@ -793,7 +831,7 @@ auto newline_pos = CPP2_UFCS(find)(source, '\n'); } } -#line 99 "reflect.h2" +#line 112 "reflect.h2" if (!(CPP2_UFCS(empty)(source))) { std::move(add_line)(std::move(source)); } @@ -809,10 +847,13 @@ auto newline_pos = CPP2_UFCS(find)(source, '\n'); // Now parse this single declaration from // the lexed tokens - return CPP2_UFCS(parse_one_declaration)(parser, - (*cpp2::assert_not_null(CPP2_UFCS(begin)(CPP2_UFCS(get_map)(*cpp2::assert_not_null(std::move(tokens)))))).second, - *cpp2::assert_not_null(generated_tokens) - ); + ret.construct(CPP2_UFCS(parse_one_declaration)(parser, + (*cpp2::assert_not_null(CPP2_UFCS(begin)(CPP2_UFCS(get_map)(*cpp2::assert_not_null(std::move(tokens)))))).second, + *cpp2::assert_not_null(generated_tokens) + )); + if (!(ret.value())) { + error("parse failed - the source string is not a valid statement:\n" + cpp2::to_string(std::move(original_source))); + }return std::move(ret.value()); } [[nodiscard]] auto compiler_services::position() const -> source_position @@ -821,6 +862,7 @@ auto newline_pos = CPP2_UFCS(find)(source, '\n'); return { }; } +#line 144 "reflect.h2" auto compiler_services::require( cpp2::in b, @@ -836,11 +878,17 @@ auto newline_pos = CPP2_UFCS(find)(source, '\n'); { auto message {cpp2::as_(msg)}; if (!(CPP2_UFCS(empty)(metafunction_name))) { - message = "while applying @" + metafunction_name + " - " + message; + message = "while applying @" + cpp2::to_string(metafunction_name) + " - " + cpp2::to_string(message); } static_cast(CPP2_UFCS(emplace_back)((*cpp2::assert_not_null(errors)), position(), std::move(message))); } +#line 166 "reflect.h2" + auto compiler_services::expects(auto const& b, auto const& msg) const& -> void{ + require(b, msg); + if (!(b)) {throw(std::runtime_error(" ==> programming bug found in metafunction @" + cpp2::to_string(metafunction_name) + " - precondition violation - see previous errors")); } + } + compiler_services::~compiler_services() noexcept{} compiler_services::compiler_services(compiler_services const& that) : errors{ that.errors } @@ -851,7 +899,7 @@ compiler_services::compiler_services(compiler_services const& that) , metafunction_args{ that.metafunction_args } , metafunctions_used{ that.metafunctions_used }{} -#line 199 "reflect.h2" +#line 224 "reflect.h2" declaration_base::declaration_base( declaration_node* n_, @@ -859,10 +907,10 @@ compiler_services::compiler_services(compiler_services const& that) ) : compiler_services{ s } , n{ n_ } -#line 204 "reflect.h2" +#line 229 "reflect.h2" { -#line 207 "reflect.h2" +#line 232 "reflect.h2" cpp2::Default.expects(n, "a meta::declaration must point to a valid declaration_node, not null"); } @@ -875,14 +923,14 @@ declaration_base::declaration_base(declaration_base const& that) : compiler_services{ static_cast(that) } , n{ that.n }{} -#line 223 "reflect.h2" +#line 248 "reflect.h2" declaration::declaration( declaration_node* n_, cpp2::in s ) : declaration_base{ n_, s } -#line 228 "reflect.h2" +#line 253 "reflect.h2" { } @@ -930,7 +978,7 @@ declaration_base::declaration_base(declaration_base const& that) [[nodiscard]] auto declaration::as_type() const& -> type_declaration { return type_declaration(n, (*this)); } [[nodiscard]] auto declaration::as_alias() const& -> alias_declaration { return alias_declaration(n, (*this)); } - [[nodiscard]] auto declaration::get_parent() const& -> declaration { return declaration(n, (*this)); } + [[nodiscard]] auto declaration::get_parent() const& -> declaration { return declaration((*cpp2::assert_not_null(n)).parent_declaration, (*this)); } [[nodiscard]] auto declaration::parent_is_function() const& -> bool { return CPP2_UFCS(parent_is_function)((*cpp2::assert_not_null(n))); } [[nodiscard]] auto declaration::parent_is_object() const& -> bool { return CPP2_UFCS(parent_is_object)((*cpp2::assert_not_null(n))); } @@ -948,7 +996,7 @@ declaration_base::declaration_base(declaration_base const& that) { cpp2::Type.expects(parent_is_type(), ""); -#line 292 "reflect.h2" +#line 317 "reflect.h2" auto test {CPP2_UFCS(type_member_mark_for_removal)((*cpp2::assert_not_null(n)))}; cpp2::Default.expects(std::move(test), ""); // ... to ensure this assert is true } @@ -957,14 +1005,14 @@ declaration_base::declaration_base(declaration_base const& that) declaration::declaration(declaration const& that) : declaration_base{ static_cast(that) }{} -#line 305 "reflect.h2" +#line 330 "reflect.h2" function_declaration::function_declaration( declaration_node* n_, cpp2::in s ) : declaration{ n_, s } -#line 310 "reflect.h2" +#line 335 "reflect.h2" { cpp2::Default.expects(CPP2_UFCS(is_function)((*cpp2::assert_not_null(n))), ""); @@ -1004,23 +1052,54 @@ declaration::declaration(declaration const& that) [[nodiscard]] auto function_declaration::unnamed_return_type() const& -> std::string { return CPP2_UFCS(unnamed_return_type_to_string)((*cpp2::assert_not_null(n))); } + [[nodiscard]] auto function_declaration::get_parameters() const& -> std::vector + + { + std::vector ret {}; + for ( auto const& param : CPP2_UFCS(get_function_parameters)((*cpp2::assert_not_null(n))) ) { + static_cast(CPP2_UFCS(emplace_back)(ret, &*cpp2::assert_not_null((*cpp2::assert_not_null(param)).declaration), (*this))); + } + return ret; + } + [[nodiscard]] auto function_declaration::is_binary_comparison_function() const& -> bool { return CPP2_UFCS(is_binary_comparison_function)((*cpp2::assert_not_null(n))); } auto function_declaration::default_to_virtual() & -> void { static_cast(CPP2_UFCS(make_function_virtual)((*cpp2::assert_not_null(n)))); } [[nodiscard]] auto function_declaration::make_virtual() & -> bool { return CPP2_UFCS(make_function_virtual)((*cpp2::assert_not_null(n))); } + auto function_declaration::add_initializer(cpp2::in source) & -> void + +#line 393 "reflect.h2" + { + (*this).expects(!(has_initializer()), "cannot add an initializer to a function that already has one"); + (*this).expects(parent_is_type(), "cannot add an initializer to a function that isn't in a type scope"); + //require( !has_initializer(), + // "cannot add an initializer to a function that already has one"); + //require( parent_is_type(), + // "cannot add an initializer to a function that isn't in a type scope"); + +#line 399 "reflect.h2" + auto stmt {parse_statement(source)}; + if (!((cpp2::as_(stmt)))) { + error("cannot add an initializer that is not a valid statement"); + return ; + } + require(CPP2_UFCS(add_function_initializer)((*cpp2::assert_not_null(n)), std::move(stmt)), + std::string("unexpected error while attempting to add initializer")); + } + function_declaration::function_declaration(function_declaration const& that) : declaration{ static_cast(that) }{} -#line 364 "reflect.h2" +#line 417 "reflect.h2" object_declaration::object_declaration( declaration_node* n_, cpp2::in s ) : declaration{ n_, s } -#line 369 "reflect.h2" +#line 422 "reflect.h2" { cpp2::Default.expects(CPP2_UFCS(is_object)((*cpp2::assert_not_null(n))), ""); @@ -1046,14 +1125,14 @@ declaration::declaration(declaration const& that) object_declaration::object_declaration(object_declaration const& that) : declaration{ static_cast(that) }{} -#line 400 "reflect.h2" +#line 453 "reflect.h2" type_declaration::type_declaration( declaration_node* n_, cpp2::in s ) : declaration{ n_, s } -#line 405 "reflect.h2" +#line 458 "reflect.h2" { cpp2::Default.expects(CPP2_UFCS(is_type)((*cpp2::assert_not_null(n))), ""); @@ -1079,7 +1158,23 @@ declaration::declaration(declaration const& that) { std::vector ret {}; - for ( auto const& d : CPP2_UFCS(get_type_scope_declarations)((*cpp2::assert_not_null(n)), declaration_node::functions) ) { + for ( + auto const& d : CPP2_UFCS(get_type_scope_declarations)((*cpp2::assert_not_null(n)), declaration_node::functions) ) { + static_cast(CPP2_UFCS(emplace_back)(ret, d, (*this))); + } + return ret; + } + + [[nodiscard]] auto type_declaration::get_member_functions_needing_initializer() const& -> std::vector + + { + std::vector ret {}; + for ( + auto const& d : CPP2_UFCS(get_type_scope_declarations)((*cpp2::assert_not_null(n)), declaration_node::functions) ) + if ( !(CPP2_UFCS(has_initializer)((*cpp2::assert_not_null(d)))) + && !(CPP2_UFCS(is_virtual_function)((*cpp2::assert_not_null(d)))) + && !(CPP2_UFCS(is_defaultable_function)((*cpp2::assert_not_null(d))))) + { static_cast(CPP2_UFCS(emplace_back)(ret, d, (*this))); } return ret; @@ -1127,13 +1222,13 @@ declaration::declaration(declaration const& that) [[nodiscard]] auto type_declaration::query_declared_value_set_functions() const& -> query_declared_value_set_functions_ret -#line 483 "reflect.h2" +#line 552 "reflect.h2" { cpp2::deferred_init out_this_in_that; cpp2::deferred_init out_this_move_that; cpp2::deferred_init inout_this_in_that; cpp2::deferred_init inout_this_move_that; -#line 484 "reflect.h2" +#line 553 "reflect.h2" auto declared {CPP2_UFCS(find_declared_value_set_functions)((*cpp2::assert_not_null(n)))}; out_this_in_that.construct(declared.out_this_in_that != nullptr); out_this_move_that.construct(declared.out_this_move_that != nullptr); @@ -1144,9 +1239,15 @@ declaration::declaration(declaration const& that) auto type_declaration::add_member(cpp2::in source) & -> void { auto decl {parse_statement(source)}; - if (!(decl) || !(CPP2_UFCS(add_type_member)((*cpp2::assert_not_null(n)), std::move(decl)))) { - error(std::string("error attempting to add member:\n") + source); + if (!((cpp2::as_(decl)))) { + error("the provided source string is not a valid statement"); + return ; + } + if (!(CPP2_UFCS(is_declaration)((*cpp2::assert_not_null(decl))))) { + error("cannot add a member that is not a declaration"); } + require(CPP2_UFCS(add_type_member)((*cpp2::assert_not_null(n)), std::move(decl)), + std::string("unexpected error while attempting to add member:\n") + source); } auto type_declaration::remove_marked_members() & -> void { CPP2_UFCS(type_remove_marked_members)((*cpp2::assert_not_null(n))); } @@ -1157,14 +1258,14 @@ declaration::declaration(declaration const& that) type_declaration::type_declaration(type_declaration const& that) : declaration{ static_cast(that) }{} -#line 513 "reflect.h2" +#line 588 "reflect.h2" alias_declaration::alias_declaration( declaration_node* n_, cpp2::in s ) : declaration{ n_, s } -#line 518 "reflect.h2" +#line 593 "reflect.h2" { cpp2::Default.expects(CPP2_UFCS(is_alias)((*cpp2::assert_not_null(n))), ""); @@ -1173,13 +1274,13 @@ declaration::declaration(declaration const& that) alias_declaration::alias_declaration(alias_declaration const& that) : declaration{ static_cast(that) }{} -#line 537 "reflect.h2" +#line 612 "reflect.h2" auto add_virtual_destructor(meta::type_declaration& t) -> void { CPP2_UFCS(add_member)(t, "operator=: (virtual move this) = { }"); } -#line 555 "reflect.h2" +#line 630 "reflect.h2" auto interface(meta::type_declaration& t) -> void { auto has_dtor {false}; @@ -1206,7 +1307,7 @@ auto interface(meta::type_declaration& t) -> void } } -#line 601 "reflect.h2" +#line 676 "reflect.h2" auto polymorphic_base(meta::type_declaration& t) -> void { auto has_dtor {false}; @@ -1231,7 +1332,7 @@ auto polymorphic_base(meta::type_declaration& t) -> void } } -#line 646 "reflect.h2" +#line 721 "reflect.h2" auto ordered_impl( meta::type_declaration& t, cpp2::in ordering @@ -1256,25 +1357,25 @@ auto ordered_impl( } } -#line 675 "reflect.h2" +#line 750 "reflect.h2" auto ordered(meta::type_declaration& t) -> void { ordered_impl(t, "strong_ordering"); } -#line 683 "reflect.h2" +#line 758 "reflect.h2" auto weakly_ordered(meta::type_declaration& t) -> void { ordered_impl(t, "weak_ordering"); } -#line 691 "reflect.h2" +#line 766 "reflect.h2" auto partially_ordered(meta::type_declaration& t) -> void { ordered_impl(t, "partial_ordering"); } -#line 713 "reflect.h2" +#line 788 "reflect.h2" auto copyable(meta::type_declaration& t) -> void { // If the user explicitly wrote any of the copy/move functions, @@ -1296,7 +1397,7 @@ auto copyable(meta::type_declaration& t) -> void }} } -#line 741 "reflect.h2" +#line 816 "reflect.h2" auto basic_value(meta::type_declaration& t) -> void { CPP2_UFCS(copyable)(t); @@ -1315,7 +1416,7 @@ auto basic_value(meta::type_declaration& t) -> void } } -#line 769 "reflect.h2" +#line 844 "reflect.h2" auto value(meta::type_declaration& t) -> void { CPP2_UFCS(ordered)(t); @@ -1334,7 +1435,7 @@ auto partially_ordered_value(meta::type_declaration& t) -> void CPP2_UFCS(basic_value)(t); } -#line 813 "reflect.h2" +#line 888 "reflect.h2" auto cpp2_struct(meta::type_declaration& t) -> void { for ( auto& m : CPP2_UFCS(get_members)(t) ) @@ -1352,7 +1453,7 @@ auto cpp2_struct(meta::type_declaration& t) -> void CPP2_UFCS(disable_member_function_generation)(t); } -#line 854 "reflect.h2" +#line 929 "reflect.h2" auto basic_enum( meta::type_declaration& t, auto const& nextval, @@ -1377,7 +1478,7 @@ auto basic_enum( { std::string value = "-1"; -#line 877 "reflect.h2" +#line 952 "reflect.h2" for ( auto const& m : CPP2_UFCS(get_members)(t) ) if ( CPP2_UFCS(is_member_object)(m)) @@ -1415,7 +1516,7 @@ std::string value = "-1"; } } -#line 913 "reflect.h2" +#line 988 "reflect.h2" CPP2_UFCS(require)(t, !(CPP2_UFCS(empty)(enumerators)), "an enumeration must contain at least one enumerator value"); @@ -1459,7 +1560,7 @@ std::string value = "-1"; } } -#line 957 "reflect.h2" +#line 1032 "reflect.h2" // 2. Replace: Erase the contents and replace with modified contents // // Note that most values and functions are declared as '==' compile-time values, i.e. Cpp1 'constexpr' @@ -1507,7 +1608,7 @@ std::string to_string = " to_string: (this) -> std::string = { \n"; // Provide a 'to_string' function to print enumerator name(s) -#line 1002 "reflect.h2" +#line 1077 "reflect.h2" { if (bitwise) { to_string += " _ret : std::string = \"(\";\n"; @@ -1539,10 +1640,10 @@ std::string to_string = " to_string: (this) -> std::string = { \n"; CPP2_UFCS(add_member)(t, std::move(to_string)); } } -#line 1032 "reflect.h2" +#line 1107 "reflect.h2" } -#line 1044 "reflect.h2" +#line 1119 "reflect.h2" auto cpp2_enum(meta::type_declaration& t) -> void { // Let basic_enum do its thing, with an incrementing value generator @@ -1559,7 +1660,7 @@ auto cpp2_enum(meta::type_declaration& t) -> void ); } -#line 1071 "reflect.h2" +#line 1146 "reflect.h2" auto flag_enum(meta::type_declaration& t) -> void { // Let basic_enum do its thing, with a power-of-two value generator @@ -1581,7 +1682,7 @@ auto flag_enum(meta::type_declaration& t) -> void ); } -#line 1117 "reflect.h2" +#line 1192 "reflect.h2" auto cpp2_union(meta::type_declaration& t) -> void { std::vector alternatives {}; @@ -1590,7 +1691,7 @@ auto value = 0; // 1. Gather: All the user-written members, and find/compute the max size -#line 1124 "reflect.h2" +#line 1199 "reflect.h2" for ( auto const& m : CPP2_UFCS(get_members)(t) ) { do @@ -1615,7 +1716,7 @@ auto value = 0; } while (false); ++value; } } -#line 1147 "reflect.h2" +#line 1222 "reflect.h2" std::string discriminator_type {}; if (cpp2::cmp_less(CPP2_UFCS(ssize)(alternatives),std::numeric_limits::max())) { discriminator_type = "i8"; @@ -1630,7 +1731,7 @@ auto value = 0; discriminator_type = "i64"; }}} -#line 1162 "reflect.h2" +#line 1237 "reflect.h2" // 2. Replace: Erase the contents and replace with modified contents CPP2_UFCS(remove_marked_members)(t); @@ -1639,12 +1740,12 @@ std::string storage = " _storage: cpp2::aligned_storage t) -> void { std::cout << CPP2_UFCS(print)(t) << "\n"; } -#line 1263 "reflect.h2" +#line 1338 "reflect.h2" [[nodiscard]] auto apply_metafunctions( declaration_node& n, type_declaration& rtype, @@ -1847,7 +1948,7 @@ auto print(cpp2::in t) -> void return true; } -#line 1363 "reflect.h2" +#line 1438 "reflect.h2" } } diff --git a/source/reflect.h2 b/source/reflect.h2 index 4cec03827..93d96a585 100644 --- a/source/reflect.h2 +++ b/source/reflect.h2 @@ -31,6 +31,8 @@ meta: namespace = { compiler_services: @polymorphic_base @copyable type = { + // Common data members + // errors : *std::vector; errors_original_size : int; generated_tokens : *std::deque; @@ -39,6 +41,8 @@ compiler_services: @polymorphic_base @copyable type = metafunction_args : std::vector = (); metafunctions_used : bool = false; + // Constructor + // operator=: ( out this, errors_ : *std::vector, @@ -51,6 +55,8 @@ compiler_services: @polymorphic_base @copyable type = parser = errors*; } + // Common API + // set_metafunction_name: (inout this, name: std::string_view, args: std::vector) = { metafunction_name = name; metafunction_args = args; @@ -67,14 +73,21 @@ compiler_services: @polymorphic_base @copyable type = return ""; } + get_arguments: (inout this) -> std::vector = { + metafunctions_used = true; + return metafunction_args; + } + arguments_were_used: (this) -> bool = metafunctions_used; protected parse_statement: ( inout this, copy source: std::string_view ) - -> std::unique_ptr + -> (ret: std::unique_ptr) = { + original_source := source; + generated_lines.push_back( std::vector() ); lines := generated_lines.back()&; @@ -84,7 +97,7 @@ compiler_services: @polymorphic_base @copyable type = // First split this string into source_lines // - (copy newline_pos := source.find('\n')) + (copy newline_pos := source.find('\n')) if source.ssize() > 1 && newline_pos != source.npos { @@ -111,10 +124,13 @@ compiler_services: @polymorphic_base @copyable type = // Now parse this single declaration from // the lexed tokens - return parser.parse_one_declaration( - tokens*.get_map().begin()*.second, - generated_tokens* - ); + ret = parser.parse_one_declaration( + tokens*.get_map().begin()*.second, + generated_tokens* + ); + if !ret { + error( "parse failed - the source string is not a valid statement:\n(original_source)$"); + } } position: (virtual this) @@ -123,10 +139,12 @@ compiler_services: @polymorphic_base @copyable type = return (); } + // Error diagnosis and handling, integrated with compiler output + // require:( this, - b: bool, - msg: std::string_view + b : bool, + msg : std::string_view ) = { if !b { @@ -138,10 +156,17 @@ compiler_services: @polymorphic_base @copyable type = = { message := msg as std::string; if !metafunction_name.empty() { - message = "while applying @" + metafunction_name + " - " + message; + message = "while applying @(metafunction_name)$ - (message)$"; } _ = errors*.emplace_back( position(), message); } + + // Enable custom contracts on this object + // + expects:(this, b, msg) = { + require(b, msg); + if !b { throw( std::runtime_error(" ==> programming bug found in metafunction @(metafunction_name)$ - precondition violation - see previous errors") ); } + } } /* @@ -272,7 +297,7 @@ declaration: @polymorphic_base @copyable type = as_type : (this) -> type_declaration = type_declaration(n, this); as_alias : (this) -> alias_declaration = alias_declaration(n, this); - get_parent : (this) -> declaration = declaration(n, this); + get_parent : (this) -> declaration = declaration(n*.parent_declaration, this); parent_is_function : (this) -> bool = n*.parent_is_function(); parent_is_object : (this) -> bool = n*.parent_is_object(); @@ -286,7 +311,7 @@ declaration: @polymorphic_base @copyable type = parent_is_polymorphic: (this) -> bool = n*.parent_is_polymorphic(); - mark_for_removal_from_enclosing_type: (inout this) + mark_for_removal_from_enclosing_type: (inout this) pre( parent_is_type() ) // this precondition should be sufficient ... = { test := n*.type_member_mark_for_removal(); @@ -346,11 +371,39 @@ function_declaration: @copyable type = unnamed_return_type : (this) -> std::string = n*.unnamed_return_type_to_string(); + get_parameters: (this) + -> std::vector + = { + ret: std::vector = (); + for n*.get_function_parameters() do (param) { + _ = ret.emplace_back( param*.declaration*&, this ); + } + return ret; + } + is_binary_comparison_function: (this) -> bool = n*.is_binary_comparison_function(); default_to_virtual : (inout this) = _ = n*.make_function_virtual(); make_virtual : (inout this) -> bool = n*.make_function_virtual(); + + add_initializer: (inout this, source: std::string_view) + pre (!has_initializer(), "cannot add an initializer to a function that already has one") + pre (parent_is_type(), "cannot add an initializer to a function that isn't in a type scope") + = { + //require( !has_initializer(), + // "cannot add an initializer to a function that already has one"); + //require( parent_is_type(), + // "cannot add an initializer to a function that isn't in a type scope"); + + stmt := parse_statement(source); + if !(stmt as bool) { + error( "cannot add an initializer that is not a valid statement"); + return; + } + require (n*.add_function_initializer(stmt), + std::string("unexpected error while attempting to add initializer")); + } } @@ -407,7 +460,7 @@ type_declaration: @copyable type = assert( n*.is_type() ); } - reserve_names: (this, name: std::string_view, forward etc...) = + reserve_names: (this, name: std::string_view, forward etc...) = { // etc is not declared ':string_view' for compatibility with GCC 10.x for get_members() do (m) { @@ -427,7 +480,23 @@ type_declaration: @copyable type = -> std::vector = { ret: std::vector = (); - for n*.get_type_scope_declarations(declaration_node::functions) do (d) { + for n*.get_type_scope_declarations(declaration_node::functions) + do (d) { + _ = ret.emplace_back( d, this ); + } + return ret; + } + + get_member_functions_needing_initializer: (this) + -> std::vector + = { + ret: std::vector = (); + for n*.get_type_scope_declarations(declaration_node::functions) + do (d) + if !d*.has_initializer() + && !d*.is_virtual_function() + && !d*.is_defaultable_function() + { _ = ret.emplace_back( d, this ); } return ret; @@ -491,9 +560,15 @@ type_declaration: @copyable type = add_member: (inout this, source: std::string_view) = { decl := parse_statement(source); - if !decl || !n*.add_type_member(decl) { - error( std::string("error attempting to add member:\n") + source ); + if !(decl as bool) { + error("the provided source string is not a valid statement"); + return; } + if !decl*.is_declaration() { + error("cannot add a member that is not a declaration"); + } + require( n*.add_type_member(decl), + std::string("unexpected error while attempting to add member:\n") + source ); } remove_marked_members: (inout this) = n*.type_remove_marked_members(); @@ -759,7 +834,7 @@ basic_value: (inout t: meta::type_declaration) = //----------------------------------------------------------------------- // // "A 'value' is a totally ordered basic_value..." -// +// // -- P0707R4, section 3 // // value - a value type that is totally ordered @@ -914,7 +989,7 @@ basic_enum: ( "an enumeration must contain at least one enumerator value"); // Compute the default underlying type, if it wasn't explicitly specified - if underlying_type == "" + if underlying_type == "" { t.require( !found_non_numeric, "if you write an enumerator with a non-numeric-literal value, you must specify the enumeration's underlying type"); @@ -1006,7 +1081,7 @@ basic_enum: ( to_string += " if this == none { return \"(none)\"; }\n"; } - for enumerators + for enumerators do (e) { if e.name != "_" { // ignore unnamed values if bitwise { @@ -1038,7 +1113,7 @@ basic_enum: ( // value of its enumerators's type, and otherwise has only public // member variables of its enumerator's type, all of which are // naturally scoped because they are members of a type." -// +// // -- P0707R4, section 3 // enum: (inout t: meta::type_declaration) = @@ -1060,12 +1135,12 @@ enum: (inout t: meta::type_declaration) = //----------------------------------------------------------------------- // -// "flag_enum expresses an enumeration that stores values +// "flag_enum expresses an enumeration that stores values // corresponding to bitwise-or'd enumerators. The enumerators must // be powers of two, and are automatically generated [...] A none // value is provided [...] Operators | and & are provided to // combine and extract values." -// +// // -- P0707R4, section 3 // flag_enum: (inout t: meta::type_declaration) = @@ -1098,10 +1173,10 @@ flag_enum: (inout t: meta::type_declaration) = // // -- Stroustrup (The Design and Evolution of C++, 14.3.4.1) // -// "C++17 needs a type-safe union... The implications of the -// consensus `variant` design are well understood and have been -// explored over several LEWG discussions, over a thousand emails, -// a joint LEWG/EWG session, and not to mention 12 years of +// "C++17 needs a type-safe union... The implications of the +// consensus `variant` design are well understood and have been +// explored over several LEWG discussions, over a thousand emails, +// a joint LEWG/EWG session, and not to mention 12 years of // experience with Boost and other libraries." // // -- Axel Naumann, in P0088 (wg21.link/p0088), @@ -1110,9 +1185,9 @@ flag_enum: (inout t: meta::type_declaration) = //----------------------------------------------------------------------- // // union -// +// // a type that contains exactly one of a fixed set of values at a time -// +// union: (inout t : meta::type_declaration) = { @@ -1167,8 +1242,8 @@ union: (inout t : meta::type_declaration) (copy storage: std::string = " _storage: cpp2::aligned_storage bool = _discriminator == (a.value)$;\n"); @@ -1288,7 +1363,7 @@ apply_metafunctions: ( args: std::vector = (); for meta*.template_arguments() - do (arg) + do (arg) args.push_back( arg.to_string() ); rtype.set_metafunction_name( name, args ); @@ -1347,9 +1422,9 @@ apply_metafunctions: ( } if ( - !args.empty() + !args.empty() && !rtype.arguments_were_used() - ) + ) { error( name + " did not use its template arguments - did you mean to write '" + name + " <" + args[0] + "> type' (with the spaces)?"); return false;