summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ast/ast.cpp106
-rw-r--r--src/ast/ast.hpp89
-rw-r--r--src/common.hpp19
-rw-r--r--src/convert/ast_iterate.cpp30
-rw-r--r--src/convert/resolve.cpp93
-rw-r--r--src/convert/typecheck_bounds.cpp36
-rw-r--r--src/convert/typecheck_expr.cpp4
-rw-r--r--src/convert/typecheck_params.cpp23
-rw-r--r--src/dump_as_rust.cpp29
-rw-r--r--src/include/rustic.hpp10
-rw-r--r--src/include/tagged_union.hpp66
-rw-r--r--src/parse/root.cpp71
12 files changed, 384 insertions, 192 deletions
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<TypeRef>& 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<TypeRef>& 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<GenericBound> 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<TypeParam>& 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<typename T>
+struct Join {
+ const char *sep;
+ const ::std::vector<T>& 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<typename T>
+inline Join<T> join(const char *sep, const ::std::vector<T> v) {
+ return Join<T>({ sep, v });
+}
+
+
namespace std {
template <typename T>
@@ -113,6 +131,7 @@ inline ::std::ostream& operator<<(::std::ostream& os, const ::std::vector<T*>& v
return os;
}
+
template <typename T>
inline ::std::ostream& operator<<(::std::ostream& os, const ::std::vector<T>& 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<TypeRef> 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 '<Self as _>::...'");
}
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<AST::Function>& 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<AST::Function>& 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<AST::TypeAlias>& 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<AST::TypeAlias>& 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<T: Trait2> 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 "<<trait<<" for "<<bound_type));
}
- }
+ )
}
}
diff --git a/src/dump_as_rust.cpp b/src/dump_as_rust.cpp
index 1c1ae2a0..cbd0eaac 100644
--- a/src/dump_as_rust.cpp
+++ b/src/dump_as_rust.cpp
@@ -684,11 +684,30 @@ void RustPrinter::print_bounds(const AST::TypeParams& params)
m_os << ",\n";
is_first = false;
- m_os << indent() << b.test() << ": ";
- if( b.is_trait() )
- m_os << b.bound();
- else
- m_os << b.lifetime();
+ m_os << indent();
+ TU_MATCH(AST::GenericBound, (b), (ent),
+ (Lifetime,
+ m_os << "'" << ent.test << ": '" << ent.bound;
+ ),
+ (TypeLifetime,
+ m_os << ent.type << ": '" << ent.bound;
+ ),
+ (IsTrait,
+ if( ent.hrls.size() > 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<void (const T&)> f) const {
+ if( m_set ) {
+ return f(m_data);
+ }
+ }
//template<typename U/*, class FcnSome, class FcnNone*/>
//U match(::std::function<U(const T&)> if_some, ::Std::function<U()> if_none) const {
// if( m_set ) {
@@ -97,6 +102,11 @@ public:
assert(is_some());
return *m_ptr;
}
+ void if_set(::std::function<void (const T&)> f) const {
+ if( m_ptr ) {
+ return f(*m_ptr);
+ }
+ }
//template<typename U/*, class FcnSome, class FcnNone*/>
//U match(::std::function<U(const T&)> if_some, ::Std::function<U()> 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<const __type&>(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<const __type&>(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<AST::Module*> *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
{