diff options
author | John Hodge <tpg@mutabah.net> | 2016-07-11 16:52:19 +1000 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-07-11 16:52:19 +1000 |
commit | f81506185270dee9e695ac427c25352a6956139b (patch) | |
tree | 9b8fcc6619c068c930a84f988b17ba49973e0830 | |
parent | 56bb288ca62d4e219b8349e26dbbe531dcc977d2 (diff) | |
download | mrust-f81506185270dee9e695ac427c25352a6956139b.tar.gz |
Expand derive - Eq and Clone
-rw-r--r-- | src/expand/derive.cpp | 296 | ||||
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 2 |
2 files changed, 298 insertions, 0 deletions
diff --git a/src/expand/derive.cpp b/src/expand/derive.cpp index 5df16616..ba4e0292 100644 --- a/src/expand/derive.cpp +++ b/src/expand/derive.cpp @@ -318,6 +318,298 @@ public: } } g_derive_partialeq; +class Deriver_Eq: + public Deriver +{ + AST::Path get_trait_path() const { + return AST::Path("", { AST::PathNode("cmp", {}), AST::PathNode("Eq", {}) }); + } + + AST::Impl make_ret(Span sp, const AST::GenericParams& p, const TypeRef& type, AST::ExprNodeP node) const + { + const AST::Path trait_path = this->get_trait_path(); + + AST::Function fcn( + AST::GenericParams(), + TypeRef(TypeRef::TagUnit(), sp), + vec$( + ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), sp, false, TypeRef("Self", 0xFFFF)) ) + ) + ); + fcn.set_code( NEWNODE(AST::ExprNode_Block, vec$(mv$(node)), ::std::unique_ptr<AST::Module>()) ); + + AST::GenericParams params = p; + for(const auto& typ : params.ty_params()) + { + params.bounds().push_back( ::AST::GenericBound::make_IsTrait({ TypeRef(typ.name()), {}, trait_path }) ); + } + + AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type ) ); + rv.add_function(false, "assert_receiver_is_total_eq", mv$(fcn)); + return mv$(rv); + } + AST::ExprNodeP assert_is_eq(const AST::Path& method_path, AST::ExprNodeP val) const { + return NEWNODE(AST::ExprNode_CallPath, + AST::Path(method_path), + vec$( NEWNODE(AST::ExprNode_UniOp, AST::ExprNode_UniOp::REF, mv$(val) ) ) + ); + } + AST::ExprNodeP field(const ::std::string& name) const { + return NEWNODE(AST::ExprNode_Field, NEWNODE(AST::ExprNode_NamedValue, AST::Path("self")), name); + } + +public: + AST::Impl handle_item(Span sp, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override + { + const AST::Path assert_method_path = this->get_trait_path() + "assert_receiver_is_total_eq"; + ::std::vector<AST::ExprNodeP> nodes; + + TU_MATCH(AST::StructData, (str.m_data), (e), + (Struct, + for( const auto& fld : e.ents ) + { + nodes.push_back( this->assert_is_eq(assert_method_path, this->field(fld.m_name)) ); + } + ), + (Tuple, + for( unsigned int idx = 0; idx < e.ents.size(); idx ++ ) + { + nodes.push_back( this->assert_is_eq(assert_method_path, this->field(FMT("idx"))) ); + } + ) + ) + + return this->make_ret(sp, p, type, NEWNODE(AST::ExprNode_Block, mv$(nodes), nullptr)); + } + + AST::Impl handle_item(Span sp, const AST::GenericParams& p, const TypeRef& type, const AST::Enum& enm) const override + { + const AST::Path assert_method_path = this->get_trait_path() + "assert_receiver_is_total_eq"; + + AST::Path base_path = type.m_data.as_Path().path; + base_path.nodes().back().args() = ::AST::PathParams(); + ::std::vector<AST::ExprNode_Match_Arm> arms; + + for(const auto& v : enm.variants()) + { + AST::ExprNodeP code; + AST::Pattern pat_a; + + TU_MATCH(::AST::EnumVariantData, (v.m_data), (e), + (Value, + code = NEWNODE(AST::ExprNode_Block, {}, nullptr); + pat_a = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name)); + ), + (Tuple, + if( e.m_sub_types.size() == 0 ) + { + code = NEWNODE(AST::ExprNode_Block, {}, nullptr); + pat_a = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name)); + } + else + { + ::std::vector<AST::Pattern> pats_a; + ::std::vector<AST::ExprNodeP> nodes; + + for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) + { + auto name_a = FMT("a" << idx); + pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_a) ); + nodes.push_back( this->assert_is_eq(assert_method_path, NEWNODE(AST::ExprNode_NamedValue, AST::Path(name_a))) ); + } + + pat_a = AST::Pattern(AST::Pattern::TagEnumVariant(), base_path + v.m_name, mv$(pats_a)); + code = NEWNODE(AST::ExprNode_Block, mv$(nodes), nullptr); + } + ), + (Struct, + ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a; + ::std::vector<AST::ExprNodeP> nodes; + + for( const auto& fld : e.m_fields ) + { + auto name_a = FMT("a" << fld.m_name); + pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_a)) ); + nodes.push_back( this->assert_is_eq(assert_method_path, NEWNODE(AST::ExprNode_NamedValue, AST::Path(name_a))) ); + } + + pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true); + code = NEWNODE(AST::ExprNode_Block, mv$(nodes), nullptr); + ) + ) + + ::std::vector< AST::Pattern> pats; + { + ::std::vector< AST::Pattern> tuple_pats; + tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), mv$(pat_a)) ); + pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), mv$(tuple_pats)) ); + } + + arms.push_back(AST::ExprNode_Match_Arm( + mv$(pats), + nullptr, + mv$(code) + )); + } + + return this->make_ret(sp, p, type, NEWNODE(AST::ExprNode_Match, + NEWNODE(AST::ExprNode_Deref, NEWNODE(AST::ExprNode_NamedValue, AST::Path("self"))), + mv$(arms) + )); + } +} g_derive_eq; + +class Deriver_Clone: + public Deriver +{ + AST::Path get_trait_path() const { + return AST::Path("", { AST::PathNode("clone", {}), AST::PathNode("Clone", {}) }); + } + AST::Path get_method_path() const { + return get_trait_path() + "clone"; + } + + AST::Impl make_ret(Span sp, const AST::GenericParams& p, const TypeRef& type, AST::ExprNodeP node) const + { + const AST::Path trait_path = this->get_trait_path(); + + AST::Function fcn( + AST::GenericParams(), + TypeRef("Self", 0xFFFF), + vec$( + ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), sp, false, TypeRef("Self", 0xFFFF)) ) + ) + ); + fcn.set_code( NEWNODE(AST::ExprNode_Block, vec$(mv$(node)), ::std::unique_ptr<AST::Module>()) ); + + AST::GenericParams params = p; + for(const auto& typ : params.ty_params()) + { + params.bounds().push_back( ::AST::GenericBound::make_IsTrait({ TypeRef(typ.name()), {}, trait_path }) ); + } + + AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type ) ); + rv.add_function(false, "clone", mv$(fcn)); + return mv$(rv); + } + AST::ExprNodeP clone_val(AST::ExprNodeP val) const { + return NEWNODE(AST::ExprNode_CallPath, + this->get_method_path(), + vec$( NEWNODE(AST::ExprNode_UniOp, AST::ExprNode_UniOp::REF, mv$(val) ) ) + ); + } + AST::ExprNodeP field(const ::std::string& name) const { + return NEWNODE(AST::ExprNode_Field, NEWNODE(AST::ExprNode_NamedValue, AST::Path("self")), name); + } + +public: + AST::Impl handle_item(Span sp, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override + { + const AST::Path& ty_path = type.m_data.as_Path().path; + ::std::vector<AST::ExprNodeP> nodes; + + TU_MATCH(AST::StructData, (str.m_data), (e), + (Struct, + ::std::vector< ::std::pair< ::std::string, AST::ExprNodeP> > vals; + for( const auto& fld : e.ents ) + { + vals.push_back( ::std::make_pair(fld.m_name, this->clone_val(this->field(fld.m_name)) ) ); + } + nodes.push_back( NEWNODE(AST::ExprNode_StructLiteral, ty_path, nullptr, mv$(vals)) ); + ), + (Tuple, + if( e.ents.size() == 0 ) + { + nodes.push_back( NEWNODE(AST::ExprNode_NamedValue, AST::Path(ty_path)) ); + } + else + { + ::std::vector<AST::ExprNodeP> vals; + for( unsigned int idx = 0; idx < e.ents.size(); idx ++ ) + { + vals.push_back( this->clone_val(this->field(FMT(idx))) ); + } + nodes.push_back( NEWNODE(AST::ExprNode_CallPath, AST::Path(ty_path), mv$(vals)) ); + } + ) + ) + + return this->make_ret(sp, p, type, NEWNODE(AST::ExprNode_Block, mv$(nodes), nullptr)); + } + + AST::Impl handle_item(Span sp, const AST::GenericParams& p, const TypeRef& type, const AST::Enum& enm) const override + { + const AST::Path assert_method_path = this->get_trait_path() + "assert_receiver_is_total_eq"; + + AST::Path base_path = type.m_data.as_Path().path; + base_path.nodes().back().args() = ::AST::PathParams(); + ::std::vector<AST::ExprNode_Match_Arm> arms; + + for(const auto& v : enm.variants()) + { + AST::ExprNodeP code; + AST::Pattern pat_a; + + TU_MATCH(::AST::EnumVariantData, (v.m_data), (e), + (Value, + code = NEWNODE(AST::ExprNode_NamedValue, base_path + v.m_name); + pat_a = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name)); + ), + (Tuple, + if( e.m_sub_types.size() == 0 ) + { + code = NEWNODE(AST::ExprNode_NamedValue, base_path + v.m_name); + pat_a = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name)); + } + else + { + ::std::vector<AST::Pattern> pats_a; + ::std::vector<AST::ExprNodeP> nodes; + + for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) + { + auto name_a = FMT("a" << idx); + pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_a) ); + nodes.push_back( this->clone_val(NEWNODE(AST::ExprNode_NamedValue, AST::Path(name_a))) ); + } + + pat_a = AST::Pattern(AST::Pattern::TagEnumVariant(), base_path + v.m_name, mv$(pats_a)); + code = NEWNODE(AST::ExprNode_CallPath, base_path + v.m_name, mv$(nodes)); + } + ), + (Struct, + ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a; + ::std::vector< ::std::pair<std::string, AST::ExprNodeP> > vals; + + for( const auto& fld : e.m_fields ) + { + auto name_a = FMT("a" << fld.m_name); + pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_a)) ); + vals.push_back( ::std::make_pair( fld.m_name, this->clone_val(NEWNODE(AST::ExprNode_NamedValue, AST::Path(name_a))) ) ); + } + + pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true); + code = NEWNODE(AST::ExprNode_StructLiteral, base_path + v.m_name, nullptr, mv$(vals)); + ) + ) + + ::std::vector< AST::Pattern> pats; + pats.push_back( AST::Pattern(AST::Pattern::TagReference(), mv$(pat_a)) ); + + arms.push_back(AST::ExprNode_Match_Arm( + mv$(pats), + nullptr, + mv$(code) + )); + } + + return this->make_ret(sp, p, type, NEWNODE(AST::ExprNode_Match, + NEWNODE(AST::ExprNode_NamedValue, AST::Path("self")), + mv$(arms) + )); + } +} g_derive_clone; + // -------------------------------------------------------------------- // Select and dispatch the correct derive() handler // -------------------------------------------------------------------- @@ -327,6 +619,10 @@ static const Deriver* find_impl(const ::std::string& trait_name) return &g_derive_debug; else if( trait_name == "PartialEq" ) return &g_derive_partialeq; + else if( trait_name == "Eq" ) + return &g_derive_eq; + else if( trait_name == "Clone" ) + return &g_derive_clone; else return nullptr; } diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index f550f9dc..61917b2b 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -719,9 +719,11 @@ namespace { const auto& enm = *e; auto it = ::std::find_if(enm.m_variants.begin(), enm.m_variants.end(), [&](const auto&v)->auto{ return v.first == var_name; }); assert(it != enm.m_variants.end()); + ASSERT_BUG(sp, it->second.is_Tuple(), "Pointed variant of TupleVariant (" << node.m_path << ") isn't a Tuple"); fields_ptr = &it->second.as_Tuple(); ), (Struct, + ASSERT_BUG(sp, e->m_data.is_Tuple(), "Pointed struct in TupleVariant (" << node.m_path << ") isn't a Tuple"); fields_ptr = &e->m_data.as_Tuple(); ) ) |