summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2016-07-11 16:52:19 +1000
committerJohn Hodge <tpg@mutabah.net>2016-07-11 16:52:19 +1000
commitf81506185270dee9e695ac427c25352a6956139b (patch)
tree9b8fcc6619c068c930a84f988b17ba49973e0830
parent56bb288ca62d4e219b8349e26dbbe531dcc977d2 (diff)
downloadmrust-f81506185270dee9e695ac427c25352a6956139b.tar.gz
Expand derive - Eq and Clone
-rw-r--r--src/expand/derive.cpp296
-rw-r--r--src/hir_typeck/expr_cs.cpp2
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();
)
)