From db10e8219fefb01415b3a79e973844401d97c1ee Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 1 Sep 2015 14:51:21 +0800 Subject: Large rework to generic bounds (to use a tagged union) --- src/ast/ast.cpp | 106 +++++++++++++++++++++++++++++++-------- src/ast/ast.hpp | 89 ++++++++++++++++---------------- src/common.hpp | 19 +++++++ src/convert/ast_iterate.cpp | 30 +++++++++-- src/convert/resolve.cpp | 93 +++++++++++++++++++++------------- src/convert/typecheck_bounds.cpp | 36 +++++++------ src/convert/typecheck_expr.cpp | 4 +- src/convert/typecheck_params.cpp | 23 +++++---- src/dump_as_rust.cpp | 29 +++++++++-- src/include/rustic.hpp | 10 ++++ src/include/tagged_union.hpp | 66 ++++++++++++------------ src/parse/root.cpp | 71 +++++++++++++++++--------- 12 files changed, 384 insertions(+), 192 deletions(-) (limited to 'src') diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index f7ebaa2b..fb289a20 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -295,13 +295,18 @@ bool Crate::find_impl(const Path& trait, const TypeRef& type, Impl** out_impl, : for( const auto& bound : type.type_params_ptr()->bounds() ) { DEBUG("bound = " << bound); - if( bound.is_trait() && bound.test() == type && bound.bound() == trait ) { - // If found, success! - DEBUG("- Success!"); - // TODO: What should be returned, kinda need to return a boolean - if(out_impl) throw CompileError::BugCheck("find_impl - Asking for a concrete impl, but generic passed"); - return true; - } + TU_MATCH_DEF(GenericBound, (bound), (ent), + (), + (IsTrait, + if(ent.type == type && ent.trait == trait) { + // If found, success! + DEBUG("- Success!"); + // TODO: What should be returned, kinda need to return a boolean + if(out_impl) throw CompileError::BugCheck("find_impl - Asking for a concrete impl, but generic passed"); + return true; + } + ) + ) } // Else, failure DEBUG("- No impl :("); @@ -855,18 +860,75 @@ SERIALISE_TYPE(TypeParam::, "AST_TypeParam", { ::std::ostream& operator<<(::std::ostream& os, const GenericBound& x) { - os << x.m_type << ": "; - if( x.m_lifetime_bound != "" ) - return os << "'" << x.m_lifetime_bound; - else - return os << x.m_trait; + TU_MATCH(GenericBound, (x), (ent), + (Lifetime, + os << "'" << ent.test << ": '" << ent.bound; + ), + (TypeLifetime, + os << ent.type << ": '" << ent.bound; + ), + (IsTrait, + if( ! ent.hrls.empty() ) + { + os << "for<"; + for(const auto& l : ent.hrls) + os << "'" << l; + os << ">"; + } + os << ent.type << ": " << ent.trait; + ), + (MaybeTrait, + os << ent.type << ": ?" << ent.trait; + ), + (NotTrait, + os << ent.type << ": !" << ent.trait; + ), + (Equality, + os << ent.type << " = " << ent.replacement; + ) + ) + return os; } -SERIALISE_TYPE_S(GenericBound, { - s.item(m_lifetime_test); - s.item(m_type); - s.item(m_lifetime_bound); - s.item(m_trait); -}) + + +#define SERIALISE_TU_ARM(CLASS, NAME, TAG, ...) case CLASS::TAG: { *this = CLASS::make_null_##TAG(); auto& NAME = this->as_##TAG(); (void)&NAME; __VA_ARGS__ } break; +#define SERIALISE_TU_ARMS(CLASS, NAME, ...) TU_GMA(__VA_ARGS__)(SERIALISE_TU_ARM, (CLASS, NAME), __VA_ARGS__) +#define SERIALISE_TU(PATH, TAG, NAME, ...) \ + void operator%(::Serialiser& s, PATH::Tag c) { s << PATH::tag_to_str(c); } \ + void operator%(::Deserialiser& s, PATH::Tag& c) { ::std::string n; s.item(n); c = PATH::tag_from_str(n); }\ + SERIALISE_TYPE(PATH::, TAG, {\ + s % this->tag(); TU_MATCH(PATH, ((*this)), (NAME), __VA_ARGS__)\ + }, {\ + PATH::Tag tag; s % tag; switch(tag) { SERIALISE_TU_ARMS(PATH, NAME, __VA_ARGS__) } \ + }) + +SERIALISE_TU(GenericBound, "GenericBound", ent, + (Lifetime, + s.item(ent.test); + s.item(ent.bound); + ), + (TypeLifetime, + s.item(ent.type); + s.item(ent.bound); + ), + (IsTrait, + s.item(ent.type); + s.item(ent.hrls); + s.item(ent.trait); + ), + (MaybeTrait, + s.item(ent.type); + s.item(ent.trait); + ), + (NotTrait, + s.item(ent.type); + s.item(ent.trait); + ), + (Equality, + s.item(ent.type); + s.item(ent.replacement); + ) +) int TypeParams::find_name(const char* name) const { @@ -918,9 +980,9 @@ bool TypeParams::check_params(Crate& crate, ::std::vector& types, bool { for( const auto& bound : m_bounds ) { - if( bound.is_trait() && bound.test() == test ) + if( bound.is_IsTrait() && bound.as_IsTrait().type == test ) { - const auto& trait = bound.bound(); + const auto& trait = bound.as_IsTrait().trait; //const auto& ty_traits = type.traits(); //auto it = ::std::find(ty_traits.begin(), ty_traits.end(), trait); @@ -937,9 +999,9 @@ bool TypeParams::check_params(Crate& crate, ::std::vector& types, bool // Check that the type fits the bounds applied to it for( const auto& bound : m_bounds ) { - if( bound.is_trait() && bound.test() == test ) + if( bound.is_IsTrait() && bound.as_IsTrait().type == test ) { - const auto& trait = bound.bound(); + const auto& trait = bound.as_IsTrait().trait; // Check if 'type' impls 'trait' if( !crate.find_impl(trait, trait) ) { diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index c04a8927..301c94bb 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -54,13 +54,18 @@ public: SERIALISABLE_PROTOTYPES(); }; -#if 0 -TAGGED_UNION( GenericBound, Lifetime, +TAGGED_UNION_EX( GenericBound, (: public Serialisable), Lifetime, + ( // Lifetime bound: 'test must be valid for 'bound (Lifetime, ( ::std::string test; ::std::string bound; )), + // Type lifetime bound + (TypeLifetime, ( + TypeRef type; + ::std::string bound; + )), // Standard trait bound: "Type: [for<'a>] Trait" (IsTrait, ( TypeRef type; @@ -82,50 +87,26 @@ TAGGED_UNION( GenericBound, Lifetime, TypeRef type; TypeRef replacement; )) + ), + ( + public: + SERIALISABLE_PROTOTYPES(); + + GenericBound clone() const { + TU_MATCH(GenericBound, ( (*this) ), (ent), + (Lifetime, return make_Lifetime({ent.test, ent.bound}); ), + (TypeLifetime, return make_TypeLifetime({ent.type, ent.bound}); ), + (IsTrait, return make_IsTrait({ent.type, ent.hrls, ent.trait}); ), + (MaybeTrait, return make_MaybeTrait({ent.type, ent.trait}); ), + (NotTrait, return make_NotTrait({ent.type, ent.trait}); ), + (Equality, return make_Equality({ent.type, ent.replacement}); ) + ) + return GenericBound(); + } + ) ); -#endif -class GenericBound: - public Serialisable -{ - ::std::string m_lifetime_test; // if "", use m_type - TypeRef m_type; - ::std::string m_lifetime_bound; // if "", use m_trait - bool m_optional; - AST::Path m_trait; - ::std::vector< ::std::string> m_hrls; // Higher-ranked lifetimes -public: - - GenericBound() {} - GenericBound(::std::string test, ::std::string bound): - m_lifetime_test( ::std::move(test) ), - m_lifetime_bound( ::std::move(bound) ) - { } - GenericBound(TypeRef type, ::std::string lifetime): - m_type( ::std::move(type) ), - m_lifetime_bound( ::std::move(lifetime) ) - { } - GenericBound(TypeRef type, AST::Path trait, bool optional=false): - m_type( ::std::move(type) ), - m_optional(optional), - m_trait( ::std::move(trait) ) - { } - - void set_higherrank( ::std::vector< ::std::string> hrls ) { - m_hrls = mv$(hrls); - } - - bool is_trait() const { return m_lifetime_bound == ""; } - const ::std::string& lifetime() const { return m_lifetime_bound; } - const TypeRef& test() const { return m_type; } - const AST::Path& bound() const { return m_trait; } - - TypeRef& test() { return m_type; } - AST::Path& bound() { return m_trait; } - - friend ::std::ostream& operator<<(::std::ostream& os, const GenericBound& x); - SERIALISABLE_PROTOTYPES(); -}; +::std::ostream& operator<<(::std::ostream& os, const GenericBound& x); class TypeParams: public Serialisable @@ -135,6 +116,26 @@ class TypeParams: ::std::vector m_bounds; public: TypeParams() {} + TypeParams(TypeParams&& x) noexcept: + m_type_params( mv$(x.m_type_params) ), + m_lifetime_params( mv$(x.m_lifetime_params) ), + m_bounds( mv$(x.m_bounds) ) + {} + TypeParams& operator=(TypeParams&& x) { + m_type_params = mv$(x.m_type_params); + m_lifetime_params = mv$(x.m_lifetime_params); + m_bounds = mv$(x.m_bounds); + return *this; + } + TypeParams(const TypeParams& x): + m_type_params(x.m_type_params), + m_lifetime_params(x.m_lifetime_params), + m_bounds() + { + m_bounds.reserve( x.m_bounds.size() ); + for(auto& e: x.m_bounds) + m_bounds.push_back( e.clone() ); + } const ::std::vector& ty_params() const { return m_type_params; } const ::std::vector< ::std::string>& lft_params() const { return m_lifetime_params; } diff --git a/src/common.hpp b/src/common.hpp index 8fef294a..753d06a6 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -95,6 +95,24 @@ struct LList }; }; +template +struct Join { + const char *sep; + const ::std::vector& v; + friend ::std::ostream& operator<<(::std::ostream& os, const Join& j) { + if( j.v.size() > 0 ) + os << j.v[0]; + for( unsigned int i = 1; i < j.v.size(); i ++ ) + os << j.sep << j.v[i]; + return os; + } +}; +template +inline Join join(const char *sep, const ::std::vector v) { + return Join({ sep, v }); +} + + namespace std { template @@ -113,6 +131,7 @@ inline ::std::ostream& operator<<(::std::ostream& os, const ::std::vector& v return os; } + template inline ::std::ostream& operator<<(::std::ostream& os, const ::std::vector& v) { if( v.size() > 0 ) diff --git a/src/convert/ast_iterate.cpp b/src/convert/ast_iterate.cpp index 10eaf80b..a61dd553 100644 --- a/src/convert/ast_iterate.cpp +++ b/src/convert/ast_iterate.cpp @@ -59,11 +59,33 @@ void CASTIterator::handle_params(AST::TypeParams& params) DEBUG("Bounds"); for( auto& bound : params.bounds() ) { - handle_type(bound.test()); - if( !bound.is_trait() ) + TU_MATCH( AST::GenericBound, (bound), (ent), + (Lifetime, DEBUG("namecheck lifetime bounds?"); - else - handle_path(bound.bound(), CASTIterator::MODE_TYPE); + ), + (TypeLifetime, + handle_type(ent.type); + DEBUG("namecheck lifetime bounds?"); + ), + (IsTrait, + handle_type(ent.type); + // TODO: Define HRLs + handle_path(ent.trait, CASTIterator::MODE_TYPE); + ), + (MaybeTrait, + handle_type(ent.type); + handle_path(ent.trait, CASTIterator::MODE_TYPE); + // TODO: Process trait, ensuring that it's a valid lang item + ), + (NotTrait, + handle_type(ent.type); + handle_path(ent.trait, CASTIterator::MODE_TYPE); + ), + (Equality, + handle_type(ent.type); + handle_type(ent.replacement); + ) + ) } } diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp index 821d4810..360ba852 100644 --- a/src/convert/resolve.cpp +++ b/src/convert/resolve.cpp @@ -379,17 +379,36 @@ void CPathResolver::handle_params(AST::TypeParams& params) DEBUG("Bounds"); for( auto& bound : params.bounds() ) { - // Resolve names within the test (i.e. the lefthand side) - handle_type(bound.test()); - - // Handle the trait bound - // - Clear "Self" to prevent it from being mangled - m_self_type.push_back( TypeRef() ); - if( !bound.is_trait() ) - DEBUG("namecheck lifetime bounds?"); - else - handle_path(bound.bound(), CASTIterator::MODE_TYPE); - m_self_type.pop_back(); + TU_MATCH(AST::GenericBound, (bound), (ent), + (Lifetime, + {} + ), + (TypeLifetime, + handle_type(ent.type); + ), + (IsTrait, + handle_type(ent.type); + m_self_type.push_back( TypeRef() ); + handle_path(ent.trait, MODE_TYPE); + m_self_type.pop_back(); + ), + (MaybeTrait, + handle_type(ent.type); + m_self_type.push_back( TypeRef() ); + handle_path(ent.trait, MODE_TYPE); + m_self_type.pop_back(); + ), + (NotTrait, + handle_type(ent.type); + m_self_type.push_back( TypeRef() ); + handle_path(ent.trait, MODE_TYPE); + m_self_type.pop_back(); + ), + (Equality, + handle_type(ent.type); + handle_type(ent.replacement); + ) + ) } } @@ -604,6 +623,8 @@ void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mod ::std::vector params; if( info.type->is_type_param() && info.type->type_param() == "Self" ) { + // TODO: What is "Self" here? May want to use GenericBound's to replace Self with the actual type when possible. + // In which case, Self will refer to "implementor of this trait" throw ParseError::Todo("CPathResolver::handle_path_ufcs - Handle '::...'"); } else if( info.type->is_type_param() ) @@ -617,32 +638,36 @@ void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mod for( const auto& bound : tp.bounds() ) { DEBUG("bound = " << bound); - if( bound.is_trait() && bound.test() == *info.type ) - { - const auto& t = *bound.bound().binding().as_Trait().trait_; - { - const auto& fcns = t.functions(); - auto it = ::std::find_if( fcns.begin(), fcns.end(), [&](const AST::Item& a) { return a.name == item_name; } ); - if( it != fcns.end() ) { - // Found it. - if( info.nodes.size() != 1 ) - throw ParseError::Generic("CPathResolver::handle_path_ufcs - Multiple arguments"); - *info.trait = bound.bound(); - success = true; - break; + TU_MATCH_DEF(AST::GenericBound, (bound), (ent), + (), + (IsTrait, + if( ent.type == *info.type ) { + const auto& t = *ent.trait.binding().as_Trait().trait_; + { + const auto& fcns = t.functions(); + auto it = ::std::find_if( fcns.begin(), fcns.end(), [&](const AST::Item& a) { return a.name == item_name; } ); + if( it != fcns.end() ) { + // Found it. + if( info.nodes.size() != 1 ) + throw ParseError::Generic("CPathResolver::handle_path_ufcs - Multiple arguments"); + *info.trait = ent.trait; + success = true; + break; + } } - } - { - const auto& types = t.types(); - auto it = ::std::find_if( types.begin(), types.end(), [&](const AST::Item& a) { return a.name == item_name; } ); - if( it != types.end() ) { - // Found it. - *info.trait = bound.bound(); - success = true; - break; + { + const auto& types = t.types(); + auto it = ::std::find_if( types.begin(), types.end(), [&](const AST::Item& a) { return a.name == item_name; } ); + if( it != types.end() ) { + // Found it. + *info.trait = ent.trait; + success = true; + break; + } } } - } + ) + ) } if( !success ) diff --git a/src/convert/typecheck_bounds.cpp b/src/convert/typecheck_bounds.cpp index 1216e959..7b89453d 100644 --- a/src/convert/typecheck_bounds.cpp +++ b/src/convert/typecheck_bounds.cpp @@ -8,6 +8,7 @@ class CGenericBoundChecker: public CASTIterator { + void check_is_trait(const AST::Path& trait) const; public: virtual void handle_expr(AST::ExprNode& root) override; virtual void handle_params(AST::TypeParams& params) override; @@ -18,24 +19,31 @@ void CGenericBoundChecker::handle_expr(AST::ExprNode& root) // Do nothing (this iterator shouldn't recurse into expressions) } +void CGenericBoundChecker::check_is_trait(const AST::Path& trait) const { + assert( !trait.binding().is_Unbound() ); + DEBUG("trait = " << trait); + if( trait.binding().is_Trait() ) + { + //throw CompileError::BoundNotTrait( bound.lex_scope(), bound.param(), trait ); + throw ::std::runtime_error(FMT("TODO - Bound " << trait << " not a trait : " << trait.binding())); + } + else { + DEBUG("Bound is a trait, good"); + } +} + void CGenericBoundChecker::handle_params(AST::TypeParams& params) { for(auto& bound : params.bounds()) { - if( bound.is_trait() ) - { - auto& trait = bound.bound(); - assert( !trait.binding().is_Unbound() ); - DEBUG("trait = " << trait); - if( trait.binding().is_Trait() ) - { - //throw CompileError::BoundNotTrait( bound.lex_scope(), bound.param(), trait ); - throw ::std::runtime_error(FMT("TODO - Bound " << trait << " not a trait : " << trait.binding())); - } - else { - DEBUG("Bound is a trait, good"); - } - } + TU_MATCH(AST::GenericBound, (bound), (ent), + (Lifetime, {}), + (TypeLifetime, {}), + (IsTrait, this->check_is_trait(ent.trait);), + (MaybeTrait, this->check_is_trait(ent.trait);), + (NotTrait, this->check_is_trait(ent.trait);), + (Equality, {}) + ) } } diff --git a/src/convert/typecheck_expr.cpp b/src/convert/typecheck_expr.cpp index e2bd1857..876c8e4f 100644 --- a/src/convert/typecheck_expr.cpp +++ b/src/convert/typecheck_expr.cpp @@ -114,9 +114,9 @@ void CTypeChecker::handle_params(AST::TypeParams& params) for( const auto& bound : params.bounds() ) { - if( bound.is_trait() && bound.test().is_type_param() ) + if( bound.is_IsTrait() && bound.as_IsTrait().type.is_type_param() ) { - const auto& name = bound.test().type_param(); + const auto& name = bound.as_IsTrait().type.type_param(); int i = params.find_name(name.c_str()); assert(i >= 0); // - Just assert that it's valid. diff --git a/src/convert/typecheck_params.cpp b/src/convert/typecheck_params.cpp index e8cbbc05..f195c811 100644 --- a/src/convert/typecheck_params.cpp +++ b/src/convert/typecheck_params.cpp @@ -97,12 +97,14 @@ bool CGenericParamChecker::has_impl_for_param(const ::std::string name, const AS for( const auto& bound : tps->bounds() ) { DEBUG("bound = " << bound); - if( bound.is_trait() && bound.test().is_type_param() && bound.test().type_param() == name ) - { - DEBUG("bound.type() {" << bound.bound() << "} == trait {" << trait << "}"); - if( bound.bound() == trait ) - return true; - } + TU_IFLET( AST::GenericBound, bound, IsTrait, ent, + if( ent.type.is_type_param() && ent.type.type_param() == name ) + { + DEBUG("bound.type() {" << ent.trait << "} == trait {" << trait << "}"); + if( ent.trait == trait ) + return true; + } + ) } // TODO: Search for generic ("impl Trait1 for T") that fits bounds @@ -206,8 +208,7 @@ void CGenericParamChecker::check_generic_params(const AST::TypeParams& info, ::s for( const auto& bound : info.bounds() ) { - if( bound.is_trait() ) - { + TU_IFLET(AST::GenericBound, bound, IsTrait, ent, auto ra_fcn = [&](const char *a){ if( strcmp(a, "Self") == 0 ) { if( self_type == TypeRef(TypeRef::TagInvalid()) ) @@ -216,10 +217,10 @@ void CGenericParamChecker::check_generic_params(const AST::TypeParams& info, ::s } return types.at(info.find_name(a)); }; - auto bound_type = bound.test(); + auto bound_type = ent.type; bound_type.resolve_args(ra_fcn); - auto trait = bound.bound(); + auto trait = ent.trait; trait.resolve_args(ra_fcn); // Check if 'type' impls 'trait' @@ -227,7 +228,7 @@ void CGenericParamChecker::check_generic_params(const AST::TypeParams& info, ::s { throw ::std::runtime_error( FMT("No matching impl of "< 0 ) { + m_os << "for<'" << ::join(", '", ent.hrls) << "> "; + } + m_os << ent.type << ": " << ent.trait; + ), + (MaybeTrait, + m_os << ent.type << ": ?" << ent.trait; + ), + (NotTrait, + m_os << ent.type << ": !" << ent.trait; + ), + (Equality, + m_os << ent.type << ": =" << ent.replacement; + ) + ) } m_os << "\n"; diff --git a/src/include/rustic.hpp b/src/include/rustic.hpp index f986a91d..84e98b31 100644 --- a/src/include/rustic.hpp +++ b/src/include/rustic.hpp @@ -69,6 +69,11 @@ public: return m_data; } + void if_set(::std::function f) const { + if( m_set ) { + return f(m_data); + } + } //template //U match(::std::function if_some, ::Std::function if_none) const { // if( m_set ) { @@ -97,6 +102,11 @@ public: assert(is_some()); return *m_ptr; } + void if_set(::std::function f) const { + if( m_ptr ) { + return f(*m_ptr); + } + } //template //U match(::std::function if_some, ::Std::function if_none) const { diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp index 5ff3bf48..15eb3148 100644 --- a/src/include/tagged_union.hpp +++ b/src/include/tagged_union.hpp @@ -13,25 +13,6 @@ #define TU_CASE(mod, class, var, name,src, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(src,mod,var,name) __VA_ARGS__) #define TU_CASE2(mod, class, var, n1,s1, n2,s2, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(s1,mod,var,n1) TU_CASE_ITEM(s2,mod,var,n2) __VA_ARGS__) - -#define TU_DATANAME(name) Data_##name -// Internals of TU_CONS -#define TU_CONS_I(__tag, __type) \ - static self_t make_null_##__tag() { self_t ret; ret.m_tag = __tag; new (ret.m_data) __type; return ::std::move(ret); } \ - static self_t make_##__tag(__type v) \ - {\ - self_t ret;\ - ret.m_tag = __tag;\ - new (ret.m_data) __type( ::std::move(v) ); \ - return ::std::move(ret); \ - }\ - bool is_##__tag() const { return m_tag == __tag; } \ - const __type& as_##__tag() const { return reinterpret_cast(m_data); } \ - __type& as_##__tag() { return reinterpret_cast<__type&>(m_data); } \ - __type unwrap_##__tag() { return ::std::move(reinterpret_cast<__type&>(m_data)); } \ -// Define a tagged union constructor -#define TU_CONS(name, _) TU_CONS_I(name, TU_DATANAME(name)) - #define TU_FIRST(a, ...) a // Argument iteration @@ -113,6 +94,25 @@ */} break; #define TU_MATCH_ARMS(CLASS, VAR, NAME, ...) TU_GMA(__VA_ARGS__)(TU_MATCH_ARM, (CLASS, VAR, NAME), __VA_ARGS__) +#define TU_IFLET(CLASS, VAR, TAG, NAME, ...) if(VAR.tag() == CLASS::TAG) { auto& NAME = VAR.as_##TAG(); (void)&NAME; __VA_ARGS__ } + + +#define TU_DATANAME(name) Data_##name +// Internals of TU_CONS +#define TU_CONS_I(__name, __tag, __type) \ + __name(__type v): m_tag(__tag) { new (m_data) __type( ::std::move(v) ); } \ + static self_t make_null_##__tag() { self_t ret; ret.m_tag = __tag; new (ret.m_data) __type; return ::std::move(ret); } \ + static self_t make_##__tag(__type v) \ + {\ + return __name( ::std::move(v) );\ + }\ + bool is_##__tag() const { return m_tag == __tag; } \ + const __type& as_##__tag() const { return reinterpret_cast(m_data); } \ + __type& as_##__tag() { return reinterpret_cast<__type&>(m_data); } \ + __type unwrap_##__tag() { return ::std::move(reinterpret_cast<__type&>(m_data)); } \ +// Define a tagged union constructor +#define TU_CONS(__name, name, _) TU_CONS_I(__name, name, TU_DATANAME(name)) + // Type definitions #define TU_EXP(...) __VA_ARGS__ #define TU_TYPEDEF(name, content) struct TU_DATANAME(name) { TU_EXP content; };/* @@ -136,7 +136,7 @@ */ #define MAXS(...) TU_GM(MAXS,__VA_ARGS__)(__VA_ARGS__) -#define TU_CONSS(...) TU_GMX(__VA_ARGS__)(TU_CONS , __VA_ARGS__) +#define TU_CONSS(_name, ...) TU_GMA(__VA_ARGS__)(TU_CONS, (_name), __VA_ARGS__) #define TU_TYPEDEFS(...) TU_GMX(__VA_ARGS__)(TU_TYPEDEF ,__VA_ARGS__) #define TU_TAGS(...) TU_GMX(__VA_ARGS__)(TU_TAG ,__VA_ARGS__) #define TU_DEST_CASES(...) TU_GMX(__VA_ARGS__)(TU_DEST_CASE,__VA_ARGS__) @@ -157,37 +157,39 @@ * ); * ``` */ -#define TAGGED_UNION(_name, _def, ...) \ -class _name { \ +#define TAGGED_UNION(_name, _def, ...) TAGGED_UNION_EX(_name, (), _def, (__VA_ARGS__), ()) +#define TAGGED_UNION_EX(_name, _inherit, _def, _variants, _extra) \ +class _name TU_EXP _inherit { \ typedef _name self_t;/* -*/ TU_TYPEDEFS(__VA_ARGS__)/* +*/ TU_TYPEDEFS _variants/* */public:\ enum Tag { \ - TU_TAGS(__VA_ARGS__)\ + TU_TAGS _variants\ };/* */ private:\ Tag m_tag; \ - char m_data[MAXS(__VA_ARGS__)];/* + char m_data[MAXS _variants];/* */ public:\ - _name(): m_tag(_def) {}\ + _name(): m_tag(_def) { new((void*)m_data) TU_DATANAME(_def); }\ _name(const _name&) = delete; \ - _name(_name&& x) noexcept: m_tag(x.m_tag) { x.m_tag = _def; switch(m_tag) { TU_MOVE_CASES(__VA_ARGS__) } } \ - _name& operator =(_name&& x) { this->~_name(); m_tag = x.m_tag; x.m_tag = _def; switch(m_tag) { TU_MOVE_CASES(__VA_ARGS__) }; return *this; } \ - ~_name() { switch(m_tag) { TU_DEST_CASES(__VA_ARGS__) } } \ + _name(_name&& x) noexcept: m_tag(x.m_tag) { switch(m_tag) { TU_MOVE_CASES _variants } } \ + _name& operator =(_name&& x) { this->~_name(); m_tag = x.m_tag; x.m_tag = _def; switch(m_tag) { TU_MOVE_CASES _variants }; return *this; } \ + ~_name() { switch(m_tag) { TU_DEST_CASES _variants } } \ \ Tag tag() const { return m_tag; }\ - TU_CONSS(__VA_ARGS__) \ + TU_CONSS(_name, TU_EXP _variants) \ /* */ static const char *tag_to_str(Tag tag) { \ switch(tag) {/* -*/ TU_TOSTR_CASES(__VA_ARGS__)/* +*/ TU_TOSTR_CASES _variants/* */ } return ""; \ }/* */ static Tag tag_from_str(const ::std::string& str) { \ if(0); /* -*/ TU_FROMSTR_CASES(__VA_ARGS__)/* +*/ TU_FROMSTR_CASES _variants/* */ else throw ::std::runtime_error("enum "#_name" No conversion"); \ }\ + TU_EXP _extra\ } /* diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 369cc95a..d64005a9 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -18,8 +18,28 @@ AST::MetaItem Parse_MetaItem(TokenStream& lex); void Parse_ModRoot(TokenStream& lex, AST::Crate& crate, AST::Module& mod, LList *prev_modstack, const ::std::string& path); +::std::vector< ::std::string> Parse_HRB(TokenStream& lex) +{ + TRACE_FUNCTION; + Token tok; + + ::std::vector< ::std::string> lifetimes; + GET_CHECK_TOK(tok, lex, TOK_LT); + do { + switch(GET_TOK(tok, lex)) + { + case TOK_LIFETIME: + lifetimes.push_back(tok.str()); + break; + default: + throw ParseError::Unexpected(lex, tok, Token(TOK_LIFETIME)); + } + } while( GET_TOK(tok, lex) == TOK_COMMA ); + CHECK_TOK(tok, TOK_GT); + return lifetimes; +} /// Parse type parameters in a definition -void Parse_TypeBound(TokenStream& lex, AST::TypeParams& ret, TypeRef checked_type) +void Parse_TypeBound(TokenStream& lex, AST::TypeParams& ret, TypeRef checked_type, ::std::vector< ::std::string> lifetimes = {}) { TRACE_FUNCTION; Token tok; @@ -27,14 +47,33 @@ void Parse_TypeBound(TokenStream& lex, AST::TypeParams& ret, TypeRef checked_typ do { if(GET_TOK(tok, lex) == TOK_LIFETIME) { - ret.add_bound( AST::GenericBound(checked_type, tok.str()) ); + ret.add_bound(AST::GenericBound::make_TypeLifetime( {type: checked_type, bound: tok.str()} )); } else if( tok.type() == TOK_QMARK ) { - ret.add_bound( AST::GenericBound(checked_type, Parse_Path(lex, PATH_GENERIC_TYPE), true) ); + ret.add_bound(AST::GenericBound::make_MaybeTrait( {type: checked_type, trait: Parse_Path(lex, PATH_GENERIC_TYPE)} )); } - else { + //else if( tok.type() == TOK_RWORD_FOR ) + //{ + // ::std::vector< ::std::string> lifetimes; + // GET_CHECK_TOK(tok, lex, TOK_LT); + // do { + // switch(GET_TOK(tok, lex)) + // { + // case TOK_LIFETIME: + // lifetimes.push_back(tok.str()); + // break; + // default: + // throw ParseError::Unexpected(lex, tok, Token(TOK_LIFETIME)); + // } + // } while( GET_TOK(tok, lex) == TOK_COMMA ); + // CHECK_TOK(tok, TOK_GT); + // + // ret.add_bound( AST::GenericBound::make_IsTrait( {type: checked_type, hrls: lifetimes, trait: Parse_Path(lex, PATH_GENERIC_TYPE) }) ); + //} + else + { lex.putback(tok); - ret.add_bound( AST::GenericBound(checked_type, Parse_Path(lex, PATH_GENERIC_TYPE)) ); + ret.add_bound( AST::GenericBound::make_IsTrait( {type: checked_type, hrls: lifetimes, trait: Parse_Path(lex, PATH_GENERIC_TYPE) }) ); } } while( GET_TOK(tok, lex) == TOK_PLUS ); lex.putback(tok); @@ -72,7 +111,7 @@ AST::TypeParams Parse_TypeParams(TokenStream& lex) { do { GET_CHECK_TOK(tok, lex, TOK_LIFETIME); - ret.add_bound( AST::GenericBound( param_name, tok.str() ) ); + ret.add_bound(AST::GenericBound::make_Lifetime( {test: param_name, bound: tok.str()} )); } while( GET_TOK(tok, lex) == TOK_PLUS ); } else @@ -112,27 +151,11 @@ void Parse_WhereClause(TokenStream& lex, AST::TypeParams& params) // Higher-ranked types/lifetimes else if( tok.type() == TOK_RWORD_FOR ) { - ::std::vector< ::std::string> lifetimes; - GET_CHECK_TOK(tok, lex, TOK_LT); - do { - switch(GET_TOK(tok, lex)) - { - case TOK_LIFETIME: - lifetimes.push_back(tok.str()); - break; - default: - throw ParseError::Unexpected(lex, tok, Token(TOK_LIFETIME)); - } - } while( GET_TOK(tok, lex) == TOK_COMMA ); - CHECK_TOK(tok, TOK_GT); + ::std::vector< ::std::string> lifetimes = Parse_HRB(lex); - // Parse a bound as normal TypeRef type = Parse_Type(lex); GET_CHECK_TOK(tok, lex, TOK_COLON); - Parse_TypeBound(lex, params, type); - - // And store the higher-ranked lifetime list - params.bounds().back().set_higherrank( mv$(lifetimes) ); + Parse_TypeBound(lex, params, type, lifetimes); } else { -- cgit v1.2.3