diff options
author | John Hodge <tpg@mutabah.net> | 2016-10-03 11:38:22 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-10-03 11:38:22 +0800 |
commit | 2a7cda10dd855d433b5d2bb2d87d736201a27499 (patch) | |
tree | 24916a7d5bf866aea4acb29b691d86b222f1e055 /src/expand/derive.cpp | |
parent | 9b7486b16d271e08d2cf41b62e376970c6b8d03f (diff) | |
download | mrust-2a7cda10dd855d433b5d2bb2d87d736201a27499.tar.gz |
Expand/derive - Ord
Diffstat (limited to 'src/expand/derive.cpp')
-rw-r--r-- | src/expand/derive.cpp | 259 |
1 files changed, 258 insertions, 1 deletions
diff --git a/src/expand/derive.cpp b/src/expand/derive.cpp index 7bb7533f..a74c8780 100644 --- a/src/expand/derive.cpp +++ b/src/expand/derive.cpp @@ -1,4 +1,10 @@ - +/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * expand/derive.cpp + * - Support for the `#[derive]` attribute + */ #include <synext.hpp> #include "../common.hpp" #include "../ast/ast.hpp" @@ -976,6 +982,255 @@ public: } } g_derive_eq; +class Deriver_Ord: + public Deriver +{ + + AST::Path get_path(const ::std::string core_name, ::std::string c1, ::std::string c2) const + { + return AST::Path(core_name, { AST::PathNode(c1, {}), AST::PathNode(c2, {}) }); + } + AST::Path get_path(const ::std::string core_name, ::std::string c1, ::std::string c2, ::std::string c3) const + { + return AST::Path(core_name, { AST::PathNode(c1, {}), AST::PathNode(c2, {}), AST::PathNode(c3, {}) }); + } + + AST::Impl make_ret(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, ::std::vector<TypeRef> types_to_bound, AST::ExprNodeP node) const + { + const AST::Path trait_path(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Ord", {}) }); + const AST::Path path_ordering(core_name, { AST::PathNode("cmp", {}), AST::PathNode("Ordering", {}) }); + + AST::Function fcn( + sp, + AST::GenericParams(), + "rust", false, false, false, + TypeRef(sp, path_ordering), + vec$( + ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), sp, false, TypeRef("Self", 0xFFFF)) ), + ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "v"), TypeRef(TypeRef::TagReference(), sp, false, TypeRef("Self", 0xFFFF)) ) + ) + ); + fcn.set_code( NEWNODE(Block, vec$(mv$(node))) ); + + AST::GenericParams params = get_params_with_bounds(p, trait_path, mv$(types_to_bound)); + + AST::Impl rv( AST::ImplDef( sp, AST::MetaItems(), mv$(params), make_spanned(sp, trait_path), type ) ); + rv.add_function(false, false, "cmp", mv$(fcn)); + return mv$(rv); + } + + AST::ExprNodeP make_compare_and_ret(Span sp, const ::std::string& core_name, AST::ExprNodeP v1, AST::ExprNodeP v2) const + { + return NEWNODE(Match, + NEWNODE(CallPath, this->get_path(core_name, "cmp", "Ord", "cmp"), + // TODO: Optional Ref? + ::make_vec2( + NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(v1)), + NEWNODE(UniOp, AST::ExprNode_UniOp::REF, mv$(v2)) + ) + ), + ::make_vec2( + ::AST::ExprNode_Match_Arm( + ::make_vec1( AST::Pattern(AST::Pattern::TagValue(), this->get_path(core_name, "cmp", "Ordering", "Equal")) ), + nullptr, + NEWNODE(Tuple, ::std::vector<AST::ExprNodeP>()) + ), + ::AST::ExprNode_Match_Arm( + ::make_vec1( AST::Pattern(AST::Pattern::TagBind(), "res") ), + nullptr, + NEWNODE(Flow, AST::ExprNode_Flow::RETURN, "", NEWNODE(NamedValue, AST::Path("res"))) + ) + ) + ); + } + AST::ExprNodeP make_ret_equal(const ::std::string& core_name) const + { + return NEWNODE(NamedValue, this->get_path(core_name, "cmp", "Ordering", "Equal")); + } +public: + AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Struct& str) const override + { + ::std::vector<AST::ExprNodeP> nodes; + + TU_MATCH(AST::StructData, (str.m_data), (e), + (Struct, + for( const auto& fld : e.ents ) + { + nodes.push_back(this->make_compare_and_ret( sp, core_name, + NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), fld.m_name), + NEWNODE(Field, NEWNODE(NamedValue, AST::Path("v" )), fld.m_name) + )); + } + ), + (Tuple, + for( unsigned int idx = 0; idx < e.ents.size(); idx ++ ) + { + auto fld_name = FMT(idx); + nodes.push_back(this->make_compare_and_ret( sp, core_name, + NEWNODE(Field, NEWNODE(NamedValue, AST::Path("self")), fld_name), + NEWNODE(Field, NEWNODE(NamedValue, AST::Path("v" )), fld_name) + )); + } + ) + ) + nodes.push_back( this->make_ret_equal(core_name) ); + + return this->make_ret(sp, core_name, p, type, this->get_field_bounds(str), NEWNODE(Block, mv$(nodes))); + } + + AST::Impl handle_item(Span sp, const ::std::string& core_name, const AST::GenericParams& p, const TypeRef& type, const AST::Enum& enm) const override + { + 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; + AST::Pattern pat_b; + + TU_MATCH(::AST::EnumVariantData, (v.m_data), (e), + (Value, + code = this->make_ret_equal(core_name); + pat_a = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name)); + pat_b = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name)); + ), + (Tuple, + if( e.m_sub_types.size() == 0 ) + { + code = this->make_ret_equal(core_name); + pat_a = AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(base_path + v.m_name)); + pat_b = 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::Pattern> pats_b; + ::std::vector<AST::ExprNodeP> nodes; + + for( unsigned int idx = 0; idx < e.m_sub_types.size(); idx ++ ) + { + auto name_a = FMT("a" << idx); + auto name_b = FMT("b" << idx); + pats_a.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF) ); + pats_b.push_back( ::AST::Pattern(::AST::Pattern::TagBind(), name_b, ::AST::PatternBinding::Type::REF) ); + + nodes.push_back(this->make_compare_and_ret( sp, core_name, + NEWNODE(NamedValue, AST::Path(name_a)), + NEWNODE(NamedValue, AST::Path(name_b)) + )); + } + + nodes.push_back( this->make_ret_equal(core_name) ); + pat_a = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_a)); + pat_b = AST::Pattern(AST::Pattern::TagNamedTuple(), base_path + v.m_name, mv$(pats_b)); + code = NEWNODE(Block, mv$(nodes)); + } + ), + (Struct, + ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_a; + ::std::vector< ::std::pair<std::string, AST::Pattern> > pats_b; + ::std::vector<AST::ExprNodeP> nodes; + + for( const auto& fld : e.m_fields ) + { + auto name_a = FMT("a" << fld.m_name); + auto name_b = FMT("b" << fld.m_name); + pats_a.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_a, ::AST::PatternBinding::Type::REF)) ); + pats_b.push_back( ::std::make_pair(fld.m_name, ::AST::Pattern(::AST::Pattern::TagBind(), name_b, ::AST::PatternBinding::Type::REF)) ); + + nodes.push_back(this->make_compare_and_ret( sp, core_name, + NEWNODE(NamedValue, AST::Path(name_a)), + NEWNODE(NamedValue, AST::Path(name_b)) + )); + } + + nodes.push_back( this->make_ret_equal(core_name) ); + pat_a = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_a), true); + pat_b = AST::Pattern(AST::Pattern::TagStruct(), base_path + v.m_name, mv$(pats_b), true); + code = NEWNODE(Block, mv$(nodes)); + ) + ) + + ::std::vector< AST::Pattern> pats; + { + ::std::vector< AST::Pattern> tuple_pats; + tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_a)) ); + tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_b)) ); + pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), mv$(tuple_pats)) ); + } + + arms.push_back(AST::ExprNode_Match_Arm( + mv$(pats), + nullptr, + mv$(code) + )); + } + + for(unsigned int a = 0; a < enm.variants().size(); a ++ ) + { + for(unsigned int b = 0; b < enm.variants().size(); b ++ ) + { + if( a == b ) + continue ; + + struct H { + static ::AST::Pattern get_pat_nc(const AST::Path& base_path, const AST::EnumVariant& v) { + AST::Path var_path = base_path + v.m_name; + + TU_MATCH(::AST::EnumVariantData, (v.m_data), (e), + (Value, + return AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(var_path)); + ), + (Tuple, + if( e.m_sub_types.size() == 0 ) + { + return AST::Pattern(AST::Pattern::TagValue(), AST::Pattern::Value::make_Named(var_path)); + } + else + { + return AST::Pattern(AST::Pattern::TagNamedTuple(), var_path, AST::Pattern::TuplePat { {}, true, {} }); + } + ), + (Struct, + return AST::Pattern(AST::Pattern::TagStruct(), var_path, {}, false); + ) + ) + throw ""; + } + }; + ::AST::Pattern pat_a = H::get_pat_nc(base_path, enm.variants()[a]); + ::AST::Pattern pat_b = H::get_pat_nc(base_path, enm.variants()[b]); + + ::std::vector< AST::Pattern> pats; + { + ::std::vector< AST::Pattern> tuple_pats; + tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_a)) ); + tuple_pats.push_back( AST::Pattern(AST::Pattern::TagReference(), false, mv$(pat_b)) ); + pats.push_back( AST::Pattern(AST::Pattern::TagTuple(), mv$(tuple_pats)) ); + } + + auto code = NEWNODE(NamedValue, this->get_path(core_name, "cmp", "Ordering", (a < b ? "Less" : "Greater"))); + + arms.push_back(AST::ExprNode_Match_Arm( + mv$(pats), + nullptr, + mv$(code) + )); + } + } + + ::std::vector<AST::ExprNodeP> vals; + vals.push_back( NEWNODE(NamedValue, AST::Path("self")) ); + vals.push_back( NEWNODE(NamedValue, AST::Path("v")) ); + return this->make_ret(sp, core_name, p, type, this->get_field_bounds(enm), NEWNODE(Match, + NEWNODE(Tuple, mv$(vals)), + mv$(arms) + )); + } +} g_derive_ord; + class Deriver_Clone: public Deriver { @@ -1173,6 +1428,8 @@ static const Deriver* find_impl(const ::std::string& trait_name) return &g_derive_partialord; else if( trait_name == "Eq" ) return &g_derive_eq; + else if( trait_name == "Ord" ) + return &g_derive_ord; else if( trait_name == "Clone" ) return &g_derive_clone; else if( trait_name == "Copy" ) |