diff options
author | John Hodge <tpg@mutabah.net> | 2015-08-28 16:14:00 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2015-08-28 16:14:00 +0800 |
commit | 261f2aea278e1185f69b06e65501c1ca718df47c (patch) | |
tree | 8a8e54c4fd85f238ebdddb01f33693eadc194934 /src/ast | |
parent | aaa9780a3b5a1c78b6f5e0eb1c46405ee044b750 (diff) | |
download | mrust-261f2aea278e1185f69b06e65501c1ca718df47c.tar.gz |
Tagged union for Path
Diffstat (limited to 'src/ast')
-rw-r--r-- | src/ast/ast.hpp | 8 | ||||
-rw-r--r-- | src/ast/path.cpp | 407 | ||||
-rw-r--r-- | src/ast/path.hpp | 185 |
3 files changed, 358 insertions, 242 deletions
diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 2376b054..b913e334 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -215,7 +215,7 @@ struct ItemNS ItemNS():
is_pub(false)
{}
- ItemNS(ItemNS&&) = default;
+ ItemNS(ItemNS&&) noexcept = default;
ItemNS(const ItemNS&) = default;
ItemNS(::std::string name, T data, bool is_pub):
name( ::std::move(name) ),
@@ -237,7 +237,7 @@ struct Item: Item():
ItemNS<T>()
{}
- Item(Item&&) = default;
+ Item(Item&&) noexcept = default;
Item(const Item&) = default;
Item(::std::string name, T data, bool is_pub):
ItemNS<T>( ::std::move(name), ::std::move(data), is_pub )
@@ -343,7 +343,7 @@ public: m_fcn_class(CLASS_UNBOUND)
{}
Function(const Function&) = delete;
- Function(Function&&) = default;
+ Function(Function&&) noexcept = default;
Function(MetaItems attrs, TypeParams params, Class fcn_class, TypeRef ret_type, Arglist args):
m_attrs( move(attrs) ),
m_fcn_class(fcn_class),
@@ -501,6 +501,7 @@ class ImplDef: TypeRef m_type;
public:
ImplDef() {}
+ ImplDef(ImplDef&&) noexcept = default;
ImplDef(MetaItems attrs, TypeParams params, Path trait_type, TypeRef impl_type):
m_attrs( move(attrs) ),
m_params( move(params) ),
@@ -536,6 +537,7 @@ class Impl: ::std::vector< ::std::pair< ::std::vector<TypeRef>, Impl > > m_concrete_impls;
public:
Impl() {}
+ Impl(Impl&&) noexcept = default;
Impl(MetaItems attrs, TypeParams params, TypeRef impl_type, Path trait_type):
m_def( move(attrs), move(params), move(trait_type), move(impl_type) )
{}
diff --git a/src/ast/path.cpp b/src/ast/path.cpp index 9757e576..b3b3ab56 100644 --- a/src/ast/path.cpp +++ b/src/ast/path.cpp @@ -63,37 +63,64 @@ typename ::std::vector<Item<T> >::const_iterator find_named(const ::std::vector< // --- AST::Path AST::Path::Path(TagUfcs, TypeRef type, TypeRef trait): - m_class(UFCS), - m_ufcs({::std::move(type), ::std::move(trait)} ) + m_class( AST::Path::Class::make_UFCS({box$(type), box$(trait), {}}) ) { } +AST::Path::Path(const Path& x): + m_class() +{ + TU_MATCH(Class, (x.m_class), (ent), + (Invalid, m_class = Class::make_Invalid({});), + (Local, + m_class = Class::make_Local({name: ent.name}); + ), + (Relative, + m_class = Class::make_Relative({nodes: ent.nodes}); + ), + (Self, + m_class = Class::make_Self({nodes: ent.nodes}); + ), + (Super, + m_class = Class::make_Super({nodes: ent.nodes}); + ), + (Absolute, + m_class = Class::make_Absolute({nodes: ent.nodes}); + ), + (UFCS, + m_class = Class::make_UFCS({ box$(TypeRef(*ent.type)), box$(TypeRef(*ent.trait)), ent.nodes }); + ) + ) +} /// Resolve a path into a canonical form, and bind it to the target value void Path::resolve(const Crate& root_crate, bool expect_params) { TRACE_FUNCTION_F("*this = "<< *this); - if(m_class == ABSOLUTE) + if( m_class.is_Absolute() ) { resolve_absolute(root_crate, expect_params); - else if(m_class == UFCS) + } + else if(m_class.is_UFCS()) { resolve_ufcs(root_crate, expect_params); + } else throw ParseError::BugCheck("Calling Path::resolve on non-absolute path"); } void Path::resolve_absolute(const Crate& root_crate, bool expect_params) { + auto& nodes = m_class.as_Absolute().nodes; DEBUG("m_crate = '" << m_crate << "'"); unsigned int slice_from = 0; // Used when rewriting the path to be relative to its crate root ::std::vector<const Module*> mod_stack; const Module* mod = &root_crate.get_root_module(m_crate); - for(unsigned int i = 0; i < m_nodes.size(); i ++ ) + for(unsigned int i = 0; i < nodes.size(); i ++ ) { mod_stack.push_back(mod); - const bool is_last = (i+1 == m_nodes.size()); - const bool is_sec_last = (i+2 == m_nodes.size()); - const PathNode& node = m_nodes[i]; - DEBUG("[" << i << "/"<<m_nodes.size()<<"]: " << node); + const bool is_last = (i+1 == nodes.size()); + const bool is_sec_last = (i+2 == nodes.size()); + const PathNode& node = nodes[i]; + DEBUG("[" << i << "/"<<nodes.size()<<"]: " << node); if( node.name()[0] == '#' ) { @@ -122,13 +149,13 @@ void Path::resolve_absolute(const Crate& root_crate, bool expect_params) case AST::Module::ItemRef::ITEM_none: // If parent node is anon, backtrack and try again // TODO: I feel like this shouldn't be done here, instead perform this when absolutising (now that find_item is reusable) - if( i > 0 && m_nodes[i-1].name()[0] == '#' && m_nodes[i-1].name().size() > 1 ) + if( i > 0 && nodes[i-1].name()[0] == '#' && nodes[i-1].name().size() > 1 ) { i --; mod_stack.pop_back(); mod = mod_stack.back(); mod_stack.pop_back(); - m_nodes.erase(m_nodes.begin()+i); + nodes.erase(nodes.begin()+i); i --; DEBUG("Failed to locate item in nested, look upwards - " << *this); @@ -164,7 +191,7 @@ void Path::resolve_absolute(const Crate& root_crate, bool expect_params) // Make a copy of the path, replace params with it, then replace *this? // - Maybe leave that up to other code? if( is_last ) { - check_param_counts(ta.params(), expect_params, m_nodes[i]); + check_param_counts(ta.params(), expect_params, nodes[i]); m_binding = PathBinding(&ta); goto ret; } @@ -178,7 +205,7 @@ void Path::resolve_absolute(const Crate& root_crate, bool expect_params) const auto& fn = item.unwrap_Function(); DEBUG("Found function"); if( is_last ) { - check_param_counts(fn.params(), expect_params, m_nodes[i]); + check_param_counts(fn.params(), expect_params, nodes[i]); m_binding = PathBinding(&fn); goto ret; } @@ -192,12 +219,12 @@ void Path::resolve_absolute(const Crate& root_crate, bool expect_params) const auto& t = item.unwrap_Trait(); DEBUG("Found trait"); if( is_last ) { - check_param_counts(t.params(), expect_params, m_nodes[i]); + check_param_counts(t.params(), expect_params, nodes[i]); m_binding = PathBinding(&t); goto ret; } else if( is_sec_last ) { - check_param_counts(t.params(), expect_params, m_nodes[i]); + check_param_counts(t.params(), expect_params, nodes[i]); // TODO: Also check params on item m_binding = PathBinding(PathBinding::TagItem(), &t); goto ret; @@ -212,13 +239,13 @@ void Path::resolve_absolute(const Crate& root_crate, bool expect_params) const auto& str = item.unwrap_Struct(); DEBUG("Found struct"); if( is_last ) { - check_param_counts(str.params(), expect_params, m_nodes[i]); + check_param_counts(str.params(), expect_params, nodes[i]); bind_struct(str, node.args()); goto ret; } else if( is_sec_last ) { - check_param_counts(str.params(), expect_params, m_nodes[i]); - bind_struct_member(str, node.args(), m_nodes[i+1]); + check_param_counts(str.params(), expect_params, nodes[i]); + bind_struct_member(str, node.args(), nodes[i+1]); goto ret; } else { @@ -231,13 +258,13 @@ void Path::resolve_absolute(const Crate& root_crate, bool expect_params) const auto& enm = item.unwrap_Enum(); DEBUG("Found enum"); if( is_last ) { - check_param_counts(enm.params(), expect_params, m_nodes[i]); + check_param_counts(enm.params(), expect_params, nodes[i]); bind_enum(enm, node.args()); goto ret; } else if( is_sec_last ) { - check_param_counts(enm.params(), expect_params, m_nodes[i]); - bind_enum_var(enm, m_nodes[i+1].name(), node.args()); + check_param_counts(enm.params(), expect_params, nodes[i]); + bind_enum_var(enm, nodes[i+1].name(), node.args()); goto ret; } else { @@ -262,41 +289,33 @@ void Path::resolve_absolute(const Crate& root_crate, bool expect_params) // Re-export case AST::Module::ItemRef::ITEM_Use: { const auto& imp = item.unwrap_Use(); + AST::Path newpath = imp.data; + auto& newnodes = newpath.m_class.as_Absolute().nodes; + DEBUG("Re-exported path " << imp.data); if( imp.name == "" ) { // Replace nodes 0:i-1 with source path, then recurse - AST::Path newpath = imp.data; - for( unsigned int j = i; j < m_nodes.size(); j ++ ) + for( unsigned int j = i; j < nodes.size(); j ++ ) { - newpath.m_nodes.push_back( m_nodes[j] ); + newnodes.push_back( nodes[j] ); } - - DEBUG("- newpath = " << newpath); - // TODO: This should check for recursion somehow - newpath.resolve(root_crate, expect_params); - - *this = newpath; - DEBUG("Alias resolved, *this = " << *this); - return; } else { // replace nodes 0:i with the source path - DEBUG("Re-exported path " << imp.data); - AST::Path newpath = imp.data; - for( unsigned int j = i+1; j < m_nodes.size(); j ++ ) + for( unsigned int j = i+1; j < nodes.size(); j ++ ) { - newpath.m_nodes.push_back( m_nodes[j] ); + newnodes.push_back( nodes[j] ); } - DEBUG("- newpath = " << newpath); - // TODO: This should check for recursion somehow - newpath.resolve(root_crate, expect_params); - - *this = newpath; - DEBUG("Alias resolved, *this = " << *this); - return; } - break; } + + DEBUG("- newpath = " << newpath); + // TODO: This should check for recursion somehow + newpath.resolve(root_crate, expect_params); + + *this = mv$(newpath); + DEBUG("Alias resolved, *this = " << *this); + return; } } } @@ -307,20 +326,21 @@ ret: if( slice_from > 0 ) { DEBUG("Removing " << slice_from << " nodes to rebase path to crate root"); - m_nodes.erase(m_nodes.begin(), m_nodes.begin()+slice_from); + nodes.erase(nodes.begin(), nodes.begin()+slice_from); } return ; } void Path::resolve_ufcs(const Crate& root_crate, bool expect_params) { - auto& type = m_ufcs.at(0); - auto& trait = m_ufcs.at(1); + auto& data = m_class.as_UFCS(); + auto& type = *data.type; + auto& trait = *data.trait; // TODO: I can forsee <T>::Assoc::Item desugaring into < <T>::Assoc >::Item, but that will be messy to code - assert(m_nodes.size()); - if(m_nodes.size() != 1) throw ParseError::Todo("Path::resolve_ufcs - Are multi-node UFCS paths valid?"); - auto& node = m_nodes.at(0); + assert(data.nodes.size()); + if(data.nodes.size() != 1) throw ParseError::Todo("Path::resolve_ufcs - Are multi-node UFCS paths valid?"); + auto& node = data.nodes.at(0); // If the type is unknown (at this time) if( type.is_wildcard() || type.is_type_param() ) @@ -517,26 +537,34 @@ void Path::bind_static(const Static& ent) void Path::resolve_args(::std::function<TypeRef(const char*)> fcn) { TRACE_FUNCTION_F(*this); - for(auto& n : nodes()) + + TU_MATCH(Path::Class, (m_class), (ent), + (Invalid), + (Local, ), + + (Relative, Path::resolve_args_nl(ent.nodes, fcn); ), + (Absolute, Path::resolve_args_nl(ent.nodes, fcn); ), + (Self , Path::resolve_args_nl(ent.nodes, fcn); ), + (Super , Path::resolve_args_nl(ent.nodes, fcn); ), + (UFCS, + ent.type->resolve_args(fcn); + ent.trait->resolve_args(fcn); + Path::resolve_args_nl(ent.nodes, fcn); + ) + ) +} +void Path::resolve_args_nl(::std::vector<PathNode>& nodes, ::std::function<TypeRef(const char*)> fcn) +{ + for(auto& n : nodes) { for(auto& p : n.args()) p.resolve_args(fcn); } - - switch(m_class) - { - case Path::UFCS: - m_ufcs[0].resolve_args(fcn); - m_ufcs[1].resolve_args(fcn); - break; - default: - break; - } } Path& Path::operator+=(const Path& other) { - for(auto& node : other.m_nodes) + for(auto& node : other.nodes()) append(node); // If the path is modified, clear the binding m_binding = PathBinding(); @@ -547,15 +575,32 @@ Path& Path::operator+=(const Path& other) void Path::match_args(const Path& other, ::std::function<void(const char*,const TypeRef&)> fcn) const { // TODO: Ensure that the two paths are of a compatible class (same class?) - if( m_nodes.size() != other.m_nodes.size() ) + // - This will crash atm if they aren't the same + TU_MATCH(Path::Class, (m_class, other.m_class), (ent, x_ent), + (Invalid), + (Local, ), + + (Relative, Path::match_args_nl(ent.nodes, x_ent.nodes, fcn); ), + (Absolute, Path::match_args_nl(ent.nodes, x_ent.nodes, fcn); ), + (Self , Path::match_args_nl(ent.nodes, x_ent.nodes, fcn); ), + (Super , Path::match_args_nl(ent.nodes, x_ent.nodes, fcn); ), + (UFCS, + Path::match_args_nl(ent.nodes, x_ent.nodes, fcn); + throw ::std::runtime_error("TODO: UFCS Path::match_args"); + ) + ) +} + +void Path::match_args_nl(const ::std::vector<PathNode>& nodes_a, const ::std::vector<PathNode>& nodes_b, ::std::function<void(const char*,const TypeRef&)> fcn) +{ + if( nodes_a.size() != nodes_b.size() ) throw ::std::runtime_error("Type mismatch (path size)"); - for( unsigned int i = 0; i < m_nodes.size(); i++ ) + for( unsigned int i = 0; i < nodes_a.size(); i++ ) { - auto& pn1 = m_nodes[i]; - auto& pn2 = other.m_nodes[i]; + auto& pn1 = nodes_a[i]; + auto& pn2 = nodes_b[i]; if( pn1.name() != pn2.name() ) throw ::std::runtime_error("Type mismatch (path component)"); - if( pn1.args().size() != pn2.args().size() ) throw ::std::runtime_error("Type mismatch (path component param count)"); @@ -585,18 +630,38 @@ bool Path::is_concrete() const /// cause two different paths to look the same. int Path::equal_no_generic(const Path& x) const { - if( m_class != x.m_class ) + if( m_class.tag() != x.m_class.tag() ) return -1; if( m_crate != x.m_crate ) return -1; + TU_MATCH(Path::Class, (m_class, x.m_class), (ent, x_ent), + (Invalid, return 0; ), + (Local, return (ent.name == x_ent.name ? 0 : 1); ), + + (Relative, return Path::node_lists_equal_no_generic(ent.nodes, x_ent.nodes); ), + (Absolute, return Path::node_lists_equal_no_generic(ent.nodes, x_ent.nodes); ), + (Self , return Path::node_lists_equal_no_generic(ent.nodes, x_ent.nodes); ), + (Super , return Path::node_lists_equal_no_generic(ent.nodes, x_ent.nodes); ), + (UFCS, + throw ::std::runtime_error("TODO: UFCS Path::equal_no_generic"); + return Path::node_lists_equal_no_generic(ent.nodes, x_ent.nodes); + ) + ) + throw ::std::runtime_error("Path::equal_no_generic - fell off"); +} + +int Path::node_lists_equal_no_generic(const ::std::vector<PathNode>& nodes_a, const ::std::vector<PathNode>& nodes_b) +{ + if( nodes_a.size() != nodes_b.size() ) { + return -1; + } + bool conditional_match = false; unsigned int i = 0; - for( const auto &e : m_nodes ) + for( const auto &e : nodes_a ) { - if( i >= x.m_nodes.size() ) - return -1; - const auto& xe = x.m_nodes[i]; + const auto& xe = nodes_b[i]; if( e.name() != xe.name() ) return -1; @@ -623,96 +688,121 @@ Ordering Path::ord(const Path& x) const { Ordering rv; - rv = ::ord( (unsigned)m_class, (unsigned)x.m_class ); + rv = ::ord( (unsigned)m_class.tag(), (unsigned)x.m_class.tag() ); if( rv != OrdEqual ) return rv; rv = ::ord( m_crate, x.m_crate ); if( rv != OrdEqual ) return rv; - rv = ::ord( m_nodes, x.m_nodes ); - if( rv != OrdEqual ) return rv; + TU_MATCH(Path::Class, (m_class, x.m_class), (ent, x_ent), + (Invalid, + return OrdEqual; + ), + (Local, + return ::ord(ent.name, x_ent.name); + ), + (Relative, + return ::ord(ent.nodes, x_ent.nodes); + ), + (Self, + return ::ord(ent.nodes, x_ent.nodes); + ), + (Super, + return ::ord(ent.nodes, x_ent.nodes); + ), + (Absolute, + return ::ord(ent.nodes, x_ent.nodes); + ), + (UFCS, + rv = ent.type->ord( *x_ent.type ); + if( rv != OrdEqual ) return rv; + rv = ent.trait->ord( *x_ent.trait ); + if( rv != OrdEqual ) return rv; + return ::ord(ent.nodes, x_ent.nodes); + ) + ) return OrdEqual; } void Path::print_pretty(::std::ostream& os) const { - switch(m_class) - { - case Path::INVALID: os << "/* inv */"; break; - case Path::VARIABLE:os << m_nodes[0].name(); break; - case Path::RELATIVE: - for(const auto& n : m_nodes) { - if( &n != &m_nodes[0] ) os << "::"; - os << "::" << n; - } - break; - case Path::SELF: + TU_MATCH(Path::Class, (m_class), (ent), + (Invalid, os << "/* inv */"; ), + (Local, os << ent.name;), + (Relative, + for(const auto& n : ent.nodes) os << "::" << n; + ), + (Self, os << "self"; - for(const auto& n : m_nodes) os << "::" << n; - break; - case Path::SUPER: + for(const auto& n : ent.nodes) os << "::" << n; + ), + (Super, os << "super"; - for(const auto& n : m_nodes) os << "::" << n; - break; - case Path::ABSOLUTE: + for(const auto& n : ent.nodes) os << "::" << n; + ), + (Absolute, if( m_crate != "" ) - os << "::" << m_crate; - for(const auto& n : m_nodes) + os << "::\"" << m_crate << "\""; + for(const auto& n : ent.nodes) os << "::" << n; - break; - case Path::UFCS: + ), + (UFCS, throw ParseError::Todo("Path::print_pretty - UFCS"); - } + ) + ) } ::std::ostream& operator<<(::std::ostream& os, const Path& path) { - if( path.m_nodes.size() == 0 && path.m_class == Path::RELATIVE ) - { - os << "/* null path */"; - return os; - } + //if( path.m_nodes.size() == 0 && path.m_class == Path::RELATIVE ) + //{ + // os << "/* null path */"; + // return os; + //} #if PRETTY_PATH_PRINT - switch(path.m_class) - { - case Path::INVALID: os << "/*inv*/"; break; - case Path::VARIABLE: os << "/*var*/" << path.m_nodes[0].name(); break; - case Path::RELATIVE: - for(const auto& n : path.m_nodes) + TU_MATCH(Path::Class, (path.m_class), (ent), + (Invalid, + os << "/*inv*/"; + ), + (Local, + os << "/*var*/" << ent.name; + ), + (Relative, + for(const auto& n : ent.nodes) { #if PRETTY_PATH_PRINT - if( &n != &path.m_nodes[0] ) { + if( &n != &ent.nodes[0] ) { os << "::"; } #endif os << n; } - break; - case Path::SELF: + ), + (Self, os << "self"; - for(const auto& n : path.m_nodes) + for(const auto& n : ent.nodes) { #if PRETTY_PATH_PRINT os << "::"; #endif os << n; } - break; - case Path::SUPER: + ), + (Super, os << "super"; - for(const auto& n : path.m_nodes) + for(const auto& n : ent.nodes) { #if PRETTY_PATH_PRINT os << "::"; #endif os << n; } - break; - case Path::ABSOLUTE: + ), + (Absolute, if( path.m_crate != "" ) os << "::\""<<path.m_crate<<"\""; - for(const auto& n : path.m_nodes) + for(const auto& n : ent.nodes) { #if PRETTY_PATH_PRINT os << "::"; @@ -720,12 +810,13 @@ void Path::print_pretty(::std::ostream& os) const os << n; } os << "/*" << path.m_binding << "*/"; - break; - case Path::UFCS: - os << "/*ufcs*/<" << path.m_ufcs[0] << " as " << path.m_ufcs[1] << ">"; - for(const auto& n : path.m_nodes) + ), + (UFCS, + os << "/*ufcs*/<" << *ent.type << " as " << *ent.trait << ">"; + for(const auto& n : ent.nodes) os << "::" << n; - } + ) + ) #else switch(path.m_class) { @@ -739,45 +830,49 @@ void Path::print_pretty(::std::ostream& os) const #endif return os; } -::Serialiser& operator<<(Serialiser& s, Path::Class pc) -{ - #define _(v) case Path::v: s << #v; break; - switch(pc) - { - _(INVALID ) - _(VARIABLE) - _(RELATIVE) - _(SELF ) - _(SUPER ) - _(ABSOLUTE) - _(UFCS ) - } - #undef _ - return s; +void operator%(Serialiser& s, Path::Class::Tag c) { + s << Path::Class::tag_to_str(c); } -void operator>>(Deserialiser& s, Path::Class& pc) -{ +void operator%(::Deserialiser& s, Path::Class::Tag& c) { ::std::string n; s.item(n); - #define _(v) if(n == #v) pc = Path::v; else - _(INVALID ) - _(VARIABLE) - _(RELATIVE) - _(SELF ) - _(SUPER ) - _(ABSOLUTE) - _(UFCS ) - throw ::std::runtime_error("Unknown path class : " + n); - #undef _ + c = Path::Class::tag_from_str(n); } +#define _D(VAR, ...) case Class::VAR: { m_class = Class::make_null_##VAR(); auto& ent = m_class.as_##VAR(); (void)&ent; __VA_ARGS__ } break; SERIALISE_TYPE(Path::, "AST_Path", { - s << m_class; - s << m_crate; - s << m_nodes; + s % m_class.tag(); + TU_MATCH(Path::Class, (m_class), (ent), + (Invalid), + (Local, s << ent.name; ), + (Relative, s.item(ent.nodes); ), + (Absolute, s.item(ent.nodes); ), + (Self , s.item(ent.nodes); ), + (Super , s.item(ent.nodes); ), + (UFCS, + s.item( ent.type ); + s.item( ent.trait ); + s.item( ent.nodes ); + ) + ) },{ - s >> m_class; - s.item(m_crate); - s.item(m_nodes); + Class::Tag tag; + s % tag; + switch(tag) + { + _D(Invalid) + _D(Local , s.item( ent.name ); ) + + _D(Relative, s.item(ent.nodes); ) + _D(Absolute, s.item(ent.nodes); ) + _D(Self , s.item(ent.nodes); ) + _D(Super , s.item(ent.nodes); ) + _D(UFCS, + s.item( ent.type ); + s.item( ent.trait ); + s.item( ent.nodes ); + ) + } }) +#undef _D } diff --git a/src/ast/path.hpp b/src/ast/path.hpp index 7cc4a181..7bb50bee 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -11,6 +11,7 @@ #include <cassert> #include <serialise.hpp> #include <tagged_union.hpp> +#include <string> class TypeRef; @@ -26,17 +27,17 @@ class Trait; class Static; class Function; -//TAGGED_ENUM(Binding, Unbound, -// (BndModule, (const Module* module_; ) ), -// (BndEnum, (const Enum* enum_; ) ), -// (BndStruct, (const Struct* struct_; ) ), -// (BndTrait, (const Trait* trait_; ) ), -// (BndStatic, (const Static* static_; ) ), -// (BndFunction, (const Function* func_; ) ), -// (BndEnumVar, (const Enum* enum_; unsigned int idx; ) ), -// (BndTypeAlias, (const TypeAlias* alias_; ) ), -// (BndStructMethod, (const Struct* struct_; ::std::string name; ) ), -// (BndTraitMethod, (const Trait* struct_; ::std::string name; ) ) +//TAGGED_UNION(PathBinding, Unbound, +// (Module, (const Module* module_; ) ), +// (Enum, (const Enum* enum_; ) ), +// (Struct, (const Struct* struct_; ) ), +// (Trait, (const Trait* trait_; ) ), +// (Static, (const Static* static_; ) ), +// (Function, (const Function* func_; ) ), +// (EnumVar, (const Enum* enum_; unsigned int idx; ) ), +// (TypeAlias, (const TypeAlias* alias_; ) ), +// (StructMethod, (const Struct* struct_; ::std::string name; ) ), +// (TraitMethod, (const Trait* struct_; ::std::string name; ) ) // ); class PathBinding { @@ -143,63 +144,64 @@ public: SERIALISABLE_PROTOTYPES(); }; -//TAGGED_ENUM(Class, Local, -// (Local, (::std:string name) ), -// (Variable, (::std:string name) ), -// (Relative, (::std::vector<PathNode> nodes) ), -// (Self, (::std::vector<PathNode> nodes) ), -// (Super, (::std::vector<PathNode> nodes) ), -// (Absolute, (::std::vector<PathNode> nodes) ), -// (UFCS, (TypeRef type; TypeRef trait; ::std::vector<PathNode> nodes) ), -// ); class Path: public ::Serialisable { public: - enum Class { - INVALID, // An empty path, usually invalid - ABSOLUTE, // root-relative path ("::path") - UFCS, // type-relative path ("<Type>::such") - VARIABLE, // Reference to a local variable - - RELATIVE, // Unadorned relative path (e.g. "path::to::item" or "generic_item::<>") - SELF, // module-relative path ("self::path") - SUPER, // parent-relative path ("super::path") - }; + TAGGED_UNION(Class, Invalid, + (Invalid, ()), + (Local, ( // Variable / Type param (resolved) + ::std::string name; + ) ), + (Relative, ( // General relative + ::std::vector<PathNode> nodes; + ) ), + (Self, ( // Module-relative + ::std::vector<PathNode> nodes; + ) ), + (Super, ( // Parent-relative + ::std::vector<PathNode> nodes; + ) ), + (Absolute, ( // Absolute + ::std::vector<PathNode> nodes; + ) ), + (UFCS, ( // Type-relative + ::std::unique_ptr<TypeRef> type; + ::std::unique_ptr<TypeRef> trait; + ::std::vector<PathNode> nodes; + ) ) + ); private: /// The crate defining the root of this path (used for path resolution) ::std::string m_crate; - /// Path class (absolute, relative, local) - /// - Absolute is "relative" to the crate root - /// - Relative doesn't have a set crate (and can't be resolved) - /// - Local is a special case to handle possible use of local varaibles - /// - UFCS is relative to a type +public: Class m_class; - ::std::vector<TypeRef> m_ufcs; - ::std::vector<PathNode> m_nodes; - + +private: PathBinding m_binding; public: // INVALID Path(): - m_class(INVALID) + m_class() {} + Path(Path&&) noexcept = default; + Path& operator=(AST::Path&&) = default; + + Path(const Path& x); // ABSOLUTE struct TagAbsolute {}; Path(TagAbsolute): - m_class(ABSOLUTE) + m_class( Class::make_Absolute({}) ) {} Path(::std::initializer_list<PathNode> l): - m_class(ABSOLUTE), - m_nodes(l) + Path("", l) {} Path(::std::string crate, ::std::vector<PathNode> nodes): m_crate( ::std::move(crate) ), - m_class(ABSOLUTE), - m_nodes( ::std::move(nodes) ) + m_class( Class::make_Absolute({nodes: mv$(nodes)}) ) {} // UFCS @@ -207,33 +209,28 @@ public: Path(TagUfcs, TypeRef type, TypeRef trait); // VARIABLE - struct TagVariable {}; - Path(TagVariable, ::std::string name): - m_class(VARIABLE), - m_nodes( {PathNode( ::std::move(name), {} )} ) + struct TagLocal {}; + Path(TagLocal, ::std::string name): + m_class( Class::make_Local({ mv$(name) }) ) + {} + Path(::std::string name): + m_class( Class::make_Local({name: mv$(name)}) ) {} // RELATIVE struct TagRelative {}; Path(TagRelative): - m_class(RELATIVE), - m_nodes({}) - {} - Path(::std::string name): - m_class(RELATIVE), - m_nodes( {PathNode( ::std::move(name), {} )} ) + m_class( Class::make_Relative({}) ) {} // SELF struct TagSelf {}; Path(TagSelf): - m_class(SELF), - m_nodes({}) + m_class( Class::make_Self({}) ) {} // SUPER struct TagSuper {}; Path(TagSuper): - m_class(SUPER), - m_nodes({}) + m_class( Class::make_Super({}) ) {} void set_crate(::std::string crate) { @@ -242,8 +239,10 @@ public: DEBUG("crate set to " << m_crate); } } - void set_local() { - assert(m_class == RELATIVE); + + + Class::Tag class_tag() const { + return m_class.tag(); } /// Add the all nodes except the first from 'b' to 'a' and return @@ -253,19 +252,21 @@ public: return ret; } /// Grab the args from the first node of b, and add the rest to the end of the path + // TODO: Args should probably be moved to the path, not the nodes void add_tailing(const Path& b) { - assert(this->m_class != INVALID); - assert(b.m_class != INVALID); - if( b.m_nodes.size() == 0 ) + assert( !this->m_class.is_Invalid() ); + assert( b.m_class.is_Relative() ); + const auto& b_r = b.m_class.as_Relative(); + if( b_r.nodes.size() == 0 ) ; - else if( m_nodes.size() > 0 ) - m_nodes.back().args() = b[0].args(); + else if( nodes().size() > 0 ) + nodes().back().args() = b[0].args(); else if( b[0].args().size() > 0 ) throw ::std::runtime_error("add_tail to empty path, but generics in source"); else ; - for(unsigned int i = 1; i < b.m_nodes.size(); i ++) - m_nodes.push_back(b.m_nodes[i]); + for(unsigned int i = 1; i < b_r.nodes.size(); i ++) + nodes().push_back(b_r.nodes[i]); m_binding = PathBinding(); } Path operator+(PathNode&& pn) const { @@ -284,9 +285,9 @@ public: Path& operator+=(const Path& x); void append(PathNode node) { - assert(this->m_class != INVALID); - assert(this->m_class != VARIABLE); - m_nodes.push_back(node); + if( m_class.is_Invalid() ) + m_class = Class::make_Relative({}); + nodes().push_back(node); m_binding = PathBinding(); } @@ -305,30 +306,44 @@ public: void match_args(const Path& other, ::std::function<void(const char*,const TypeRef&)> fcn) const; bool is_trivial() const { - switch(m_class) + switch(m_class.tag()) { - case RELATIVE: return m_nodes.size() == 1 && m_nodes[0].args().size() == 0; + case Class::Local: return true; + case Class::Relative: { + auto& e = m_class.as_Relative(); + return e.nodes.size() == 1 && e.nodes[0].args().size() == 0; + } default: return false; } } - bool is_valid() const { return *this != Path(); } - Class type() const { return m_class; } - bool is_absolute() const { return m_class == ABSOLUTE; } - bool is_relative() const { return m_class == RELATIVE; } - size_t size() const { return m_nodes.size(); } + bool is_valid() const { return !m_class.is_Invalid(); } + bool is_absolute() const { return m_class.is_Absolute(); } + bool is_relative() const { return m_class.is_Relative() || m_class.is_Super() || m_class.is_Self(); } + size_t size() const { return nodes().size(); } bool is_concrete() const; const PathBinding& binding() const { return m_binding; } - ::std::vector<TypeRef>& ufcs() { return m_ufcs; } - - ::std::vector<PathNode>& nodes() { return m_nodes; } - const ::std::vector<PathNode>& nodes() const { return m_nodes; } + ::std::vector<PathNode>& nodes() { + TU_MATCH(Class, (m_class), (ent), + (Invalid, assert(!m_class.is_Invalid()); throw ::std::runtime_error("Path::nodes() on Invalid"); ), + (Local, assert(!m_class.is_Local()); throw ::std::runtime_error("Path::nodes() on Local"); ), + (Relative, return ent.nodes;), + (Self, return ent.nodes;), + (Super, return ent.nodes;), + (Absolute, return ent.nodes;), + (UFCS, return ent.nodes;) + ) + throw ::std::runtime_error("Path::nodes() fell off"); + } + const ::std::vector<PathNode>& nodes() const { + return ((Path*)this)->nodes(); + } - PathNode& operator[](int idx) { if(idx>=0) return m_nodes[idx]; else return m_nodes[size()+idx]; } - const PathNode& operator[](int idx) const { if(idx>=0) return m_nodes[idx]; else return m_nodes[size()+idx]; } + PathNode& operator[](int idx) { if(idx>=0) return nodes()[idx]; else return nodes()[size()+idx]; } + const PathNode& operator[](int idx) const { return (*(Path*)this)[idx]; } /// Returns 0 if paths are identical, 1 if TypeRef::TagArg is present in one, and -1 if a node differs int equal_no_generic(const Path& x) const; @@ -344,6 +359,10 @@ public: friend ::Serialiser& operator<<(Serialiser& s, Path::Class pc); friend void operator>>(Deserialiser& s, Path::Class& pc); private: + static void resolve_args_nl(::std::vector<PathNode>& nodes, ::std::function<TypeRef(const char*)> fcn); + static void match_args_nl(const ::std::vector<PathNode>& nodes_a, const ::std::vector<PathNode>& nodes_b, ::std::function<void(const char*,const TypeRef&)> fcn); + static int node_lists_equal_no_generic(const ::std::vector<PathNode>& nodes_a, const ::std::vector<PathNode>& nodes_b); + void check_param_counts(const TypeParams& params, bool expect_params, PathNode& node); void bind_module(const Module& mod); void bind_enum(const Enum& ent, const ::std::vector<TypeRef>& args); |