summaryrefslogtreecommitdiff
path: root/src/ast
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2015-08-28 16:14:00 +0800
committerJohn Hodge <tpg@mutabah.net>2015-08-28 16:14:00 +0800
commit261f2aea278e1185f69b06e65501c1ca718df47c (patch)
tree8a8e54c4fd85f238ebdddb01f33693eadc194934 /src/ast
parentaaa9780a3b5a1c78b6f5e0eb1c46405ee044b750 (diff)
downloadmrust-261f2aea278e1185f69b06e65501c1ca718df47c.tar.gz
Tagged union for Path
Diffstat (limited to 'src/ast')
-rw-r--r--src/ast/ast.hpp8
-rw-r--r--src/ast/path.cpp407
-rw-r--r--src/ast/path.hpp185
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);