summaryrefslogtreecommitdiff
path: root/src/ast/path.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ast/path.cpp')
-rw-r--r--src/ast/path.cpp407
1 files changed, 251 insertions, 156 deletions
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
}