summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2015-11-03 12:01:01 +1100
committerJohn Hodge <tpg@mutabah.net>2015-11-03 12:01:01 +1100
commit01ec57f596f89d4b52b378975f941e2ed8d2e563 (patch)
tree58e17f12b09b1be1dc37d0143ea2e4cf0dcaa9c2 /src
parentf56b813d42ebb4629345f63e6ea2c4704bb28e0a (diff)
downloadmrust-01ec57f596f89d4b52b378975f941e2ed8d2e563.tar.gz
Move path binding logic into Resolve path to simplify
Diffstat (limited to 'src')
-rw-r--r--src/ast/ast.cpp4
-rw-r--r--src/ast/ast.hpp45
-rw-r--r--src/ast/path.cpp370
-rw-r--r--src/ast/path.hpp22
-rw-r--r--src/convert/resolve.cpp385
-rw-r--r--src/include/tagged_union.hpp2
6 files changed, 379 insertions, 449 deletions
diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp
index aa8a17e0..10a7d68a 100644
--- a/src/ast/ast.cpp
+++ b/src/ast/ast.cpp
@@ -715,7 +715,7 @@ Module::ItemRef Module::find_item(const ::std::string& needle, bool allow_leaves
// not yet bound, so run resolution (recursion)
DEBUG("Recursively resolving pub wildcard use " << imp.data);
//imp.data.resolve(root_crate);
- throw ParseError::Todo("Path::resolve() wildcard re-export call resolve");
+ throw ParseError::Todo("AST::Module::find_item() - Wildcard `use` not bound, call resolve here?");
}
TU_MATCH_DEF(AST::PathBinding, (binding), (info),
@@ -730,7 +730,7 @@ Module::ItemRef Module::find_item(const ::std::string& needle, bool allow_leaves
// - If it's a module, recurse
(Module,
auto rv = info.module_->find_item(needle);
- if( rv.type() != Module::ItemRef::ITEM_none ) {
+ if( rv.tag() != Module::ItemRef::None ) {
// Don't return RV, return the import (so caller can rewrite path if need be)
return ItemRef(imp);
//return rv;
diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp
index 94b217d1..f4f2b474 100644
--- a/src/ast/ast.hpp
+++ b/src/ast/ast.hpp
@@ -724,36 +724,37 @@ public:
public:
enum Type
{
- ITEM_none,
- ITEM_Module,
- ITEM_Crate,
- ITEM_TypeAlias,
- ITEM_Function,
- ITEM_Trait,
- ITEM_Struct,
- ITEM_Enum,
- ITEM_Static,
- ITEM_Use,
+ None,
+ Module,
+ Crate,
+ TypeAlias,
+ Function,
+ Trait,
+ Struct,
+ Enum,
+ Static,
+ Use,
};
private:
Type m_type;
const void* m_ref;
public:
- ItemRef(): m_type(ITEM_none) {}
+ ItemRef(): m_type(None) {}
- Type type() { return m_type; }
+ Type tag() const { return m_type; }
+ const Type& as_None() const { return m_type; } // HACK: Returns &Type in place of &void
#define _(ty,ident) \
- ItemRef(const ty& ref): m_type(ITEM_##ident), m_ref(&ref) {} \
- const ty& unwrap_##ident() { assert(m_type == ITEM_##ident); m_type = ITEM_none; return *(const ty*)m_ref; }
- _(Module, Module)
+ ItemRef(const ty& ref): m_type(ident), m_ref(&ref) {} \
+ const ty& as_##ident() const { assert(m_type == ident); return *(const ty*)m_ref; }
+ _(AST::Module, Module)
_(::std::string, Crate)
- _(TypeAlias, TypeAlias)
- _(Function, Function)
- _(Trait, Trait)
- _(Struct, Struct)
- _(Enum, Enum)
- _(Static, Static)
- _(Item<Path>, Use)
+ _(AST::TypeAlias, TypeAlias)
+ _(AST::Function, Function)
+ _(AST::Trait, Trait)
+ _(AST::Struct, Struct)
+ _(AST::Enum, Enum)
+ _(AST::Static, Static)
+ _(AST::Item<Path>, Use)
#undef _
};
ItemRef find_item(const ::std::string& needle, bool allow_leaves = true, bool ignore_private_wildcard = true) const;
diff --git a/src/ast/path.cpp b/src/ast/path.cpp
index 8fe42527..8668c386 100644
--- a/src/ast/path.cpp
+++ b/src/ast/path.cpp
@@ -136,367 +136,7 @@ AST::Path::Path(const Path& x):
DEBUG("clone, x = " << x << ", this = " << *this );
}
-/// 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_binding.is_Unbound() )
- {
- if( m_class.is_Absolute() ) {
- resolve_absolute(root_crate, expect_params);
- }
- 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 < nodes.size(); i ++ )
- {
- mod_stack.push_back(mod);
- 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] == '#' )
- {
- // HACK - Compiler-provided functions/types live in the special '#' module
- if( node.name() == "#" ) {
- if( i != 0 )
- throw ParseError::BugCheck("# module not at path root");
- mod = &g_compiler_module;
- continue ;
- }
-
- // Hacky special case - Anon modules are indexed
- // - Darn you C++ and no string views
- unsigned int index = ::std::strtoul(node.name().c_str()+1, nullptr, 10); // Parse the number at +1
- DEBUG(" index = " << index);
- if( index >= mod->anon_mods().size() )
- throw ParseError::Generic("Anon module index out of range");
- mod = mod->anon_mods().at(index);
- continue ;
- }
-
- auto item = mod->find_item(node.name(), is_last); // Only allow leaf nodes (functions and statics) if this is the last node
- switch( item.type() )
- {
- // Not found
- 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 && nodes[i-1].name()[0] == '#' && nodes[i-1].name().size() > 1 )
- {
- i --;
- mod_stack.pop_back();
- mod = mod_stack.back();
- mod_stack.pop_back();
- nodes.erase(nodes.begin()+i);
- i --;
- DEBUG("Failed to locate item in nested, look upwards - " << *this);
-
- continue ;
- }
- throw ParseError::Generic("Unable to find component '" + node.name() + "'");
-
- // Sub-module
- case AST::Module::ItemRef::ITEM_Module:
- DEBUG("Sub-module : " << node.name());
- if( node.args().size() )
- throw ParseError::Generic("Generic params applied to module");
- mod = &item.unwrap_Module();
- break;
-
- // Crate
- case AST::Module::ItemRef::ITEM_Crate: {
- const ::std::string& crate_name = item.unwrap_Crate();
- DEBUG("Extern crate '" << node.name() << "' = '" << crate_name << "'");
- if( node.args().size() )
- throw ParseError::Generic("Generic params applied to extern crate");
- m_crate = crate_name;
- slice_from = i+1;
- mod = &root_crate.get_root_module(crate_name);
- break; }
-
- // Type Alias
- case AST::Module::ItemRef::ITEM_TypeAlias: {
- const auto& ta = item.unwrap_TypeAlias();
- DEBUG("Type alias <"<<ta.params()<<"> " << ta.type());
- //if( node.args().size() != ta.params().size() )
- // throw ParseError::Generic("Param count mismatch when referencing type alias");
- // 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, nodes[i]);
- m_binding = PathBinding::make_TypeAlias( {&ta} );
- goto ret;
- }
- else {
- throw ParseError::Todo("Path::resolve() type method");
- }
- break; }
-
- // Function
- case AST::Module::ItemRef::ITEM_Function: {
- const auto& fn = item.unwrap_Function();
- DEBUG("Found function");
- if( is_last ) {
- check_param_counts(fn.params(), expect_params, nodes[i]);
- m_binding = PathBinding::make_Function({&fn});
- goto ret;
- }
- else {
- throw ParseError::Generic("Import of function, too many extra nodes");
- }
- break; }
-
- // Trait
- case AST::Module::ItemRef::ITEM_Trait: {
- const auto& t = item.unwrap_Trait();
- DEBUG("Found trait");
- if( is_last ) {
- check_param_counts(t.params(), expect_params, nodes[i]);
- m_binding = PathBinding::make_Trait({&t});
- goto ret;
- }
- else if( is_sec_last ) {
- check_param_counts(t.params(), expect_params, nodes[i]);
- // TODO: Also check params on item
- m_binding = PathBinding::make_TraitMethod( {&t, nodes[i+1].name()} );
- goto ret;
- }
- else {
- throw ParseError::Generic("Import of trait, too many extra nodes");
- }
- break; }
-
- // Struct
- case AST::Module::ItemRef::ITEM_Struct: {
- const auto& str = item.unwrap_Struct();
- DEBUG("Found struct");
- if( is_last ) {
- 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, nodes[i]);
- bind_struct_member(str, node.args(), nodes[i+1]);
- goto ret;
- }
- else {
- throw ParseError::Generic("Import of struct, too many extra nodes");
- }
- break; }
-
- // Enum / enum variant
- case AST::Module::ItemRef::ITEM_Enum: {
- const auto& enm = item.unwrap_Enum();
- DEBUG("Found enum");
- if( is_last ) {
- 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, nodes[i]);
- bind_enum_var(enm, nodes[i+1].name(), node.args());
- goto ret;
- }
- else {
- throw ParseError::Generic("Binding path to enum, too many extra nodes");
- }
- break; }
-
- case AST::Module::ItemRef::ITEM_Static: {
- const auto& st = item.unwrap_Static();
- DEBUG("Found static/const");
- if( is_last ) {
- if( node.args().size() )
- throw ParseError::Generic("Unexpected generic params on static/const");
- bind_static(st);
- goto ret;
- }
- else {
- throw ParseError::Generic("Binding path to static, trailing nodes");
- }
- break; }
-
- // 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
- for( unsigned int j = i; j < nodes.size(); j ++ )
- {
- newnodes.push_back( nodes[j] );
- }
- }
- else
- {
- // replace nodes 0:i with the source path
- for( unsigned int j = i+1; j < nodes.size(); j ++ )
- {
- newnodes.push_back( nodes[j] );
- }
- }
-
- 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; }
- }
-
- }
-
- // We only reach here if the path points to a module
- m_binding = PathBinding::make_Module({mod});
-ret:
- if( slice_from > 0 )
- {
- DEBUG("Removing " << slice_from << " nodes to rebase path to crate root");
- nodes.erase(nodes.begin(), nodes.begin()+slice_from);
- }
- return ;
-}
-
-void Path::resolve_ufcs(const Crate& root_crate, bool expect_params)
-{
- 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(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() )
- {
- // - _ as _ = BUG
- if( !trait.is_path() )
- {
- // Wait, what about <T as _>, is that valid?
- throw CompileError::BugCheck( FMT("Path::resolve_ufcs - Path invalid : " << *this) );
- }
- // - /*arg*/T as Trait = Type parameter
- else if( type.is_type_param() )
- {
- // Check that the param is bound on that trait?
- //if( !type.type_params_ptr() )
- // throw CompileError::BugCheck( FMT("Path::resolve_ufcs - No bound params on arg") );
-
- //const auto& tps = *type.type_params_ptr();
- //for( const auto& bound : tps.bounds() )
- //{
- // // TODO: Check if this type impls the trait
- // // - Not needed to do the bind, so ignore for now
- //}
-
- // Search trait for an impl
- //throw ParseError::Todo("Path::resolve_ufcs - Arg");
- resolve_ufcs_trait(trait.path(), node);
- //throw ParseError::Todo("Path::resolve_ufcs - Arg2");
- }
- // - _ as Trait = Inferred type (unknown at the moment)
- else
- {
- throw ParseError::Todo("Path::resolve_ufcs - Handle binding when type is unknown");
- }
- }
- else
- {
- // - Type as _ = ? Infer the trait from any matching impls
- if( trait.is_wildcard() )
- {
- // Search inherent impl first, then (somehow) search in-scope traits
- // - TODO: Shouldn't this be the job of CPathResolver?
- throw ParseError::Todo("Path::resolve_ufcs - Unknown trait (resolve)");
- }
- // - Type as Trait = Obtain from relevant impl
- else if( trait.is_path() )
- {
- // Locate in the trait, but store Self type somehow?
- trait.path().resolve(root_crate, true);
- resolve_ufcs_trait(trait.path(), node);
- }
- // - Type as ! = Item from the inherent impl (similar to above)
- else if( trait == TypeRef(TypeRef::TagInvalid()) )
- {
- // TODO: Handle case where 'type' is a trait object
- // 1. Obtain the impl
- AST::Impl* impl_ptr;
- if( ! root_crate.find_impl(AST::Path(), type, &impl_ptr) )
- throw ParseError::Generic("Path::resolve_ufcs - No impl block for type");
- assert( impl_ptr );
-
- for( const auto& it : impl_ptr->functions() )
- {
- if( it.name == node.name() ) {
- check_param_counts(it.data.params(), expect_params, node);
- m_binding = PathBinding::make_Function( {&it.data} );
- goto _impl_item_bound;
- }
- }
- throw ParseError::Generic( FMT("Path::resolve_ufcs - No item named '"<<node.name()<<"' in inherent"));
- _impl_item_bound:
- DEBUG("UFCS inherent bound to " << m_binding);
- }
- // - Type as * = Bug
- else
- {
- throw CompileError::BugCheck( FMT("Path::resolve_ufcs - Path invalid : " << *this) );
- }
- }
-}
-
-void Path::resolve_ufcs_trait(const AST::Path& trait_path, AST::PathNode& node)
-{
- if( !trait_path.m_binding.is_Trait() )
- ERROR(trait_path.span(), E0000, "Trait in UFCS path is not a trait");
- const auto& trait_def = *trait_path.m_binding.as_Trait().trait_;
-
- // Check that the requested item exists within the trait, and bind to that item
- for( const auto& fn : trait_def.functions() )
- {
- if( fn.name == node.name() ) {
- check_param_counts(fn.data.params(), true, node);
- m_binding = PathBinding::make_Function( {&fn.data} );
- goto _trait_item_bound;
- }
- }
- for( const auto& it : trait_def.types() )
- {
- if( it.name == node.name() ) {
- check_param_counts(it.data.params(), true, node);
- m_binding = PathBinding::make_TypeAlias( {&it.data} );
- goto _trait_item_bound;
- }
- }
- throw ParseError::Todo("Path::resolve_ufcs - Fully known");
-_trait_item_bound:
- DEBUG("UFCS trait bound to " << m_binding);
-}
-
+/*
void Path::check_param_counts(const TypeParams& params, bool expect_params, PathNode& node)
{
if( !expect_params )
@@ -530,11 +170,15 @@ void Path::check_param_counts(const TypeParams& params, bool expect_params, Path
}
}
}
+*/
void Path::bind_variable(unsigned int slot)
{
m_binding = PathBinding::make_Variable({slot});
}
+void Path::bind_module(const Module& mod) {
+ m_binding = PathBinding::make_Module({&mod});
+}
void Path::bind_enum(const Enum& ent, const ::std::vector<TypeRef>& args)
{
DEBUG("Bound to enum");
@@ -585,6 +229,10 @@ void Path::bind_static(const Static& ent)
{
m_binding = PathBinding::make_Static({&ent});
}
+void Path::bind_trait(const Trait& ent, const ::std::vector<TypeRef>& args)
+{
+ m_binding = PathBinding::make_Trait({&ent});
+}
void Path::resolve_args(::std::function<TypeRef(const char*)> fcn)
{
diff --git a/src/ast/path.hpp b/src/ast/path.hpp
index d0cc5648..fd1cf5dc 100644
--- a/src/ast/path.hpp
+++ b/src/ast/path.hpp
@@ -250,15 +250,7 @@ public:
nodes().push_back(node);
m_binding = PathBinding();
}
-
- /// Resolve the path, and set up binding
- ///
- /// expect_params enables checking of param counts (clear for handling 'use')
- void resolve(const Crate& crate, bool expect_params=true);
- void resolve_absolute(const Crate& root_crate, bool expect_params);
- void resolve_ufcs(const Crate& root_crate, bool expect_params);
- void resolve_ufcs_trait(const AST::Path& trait_path, AST::PathNode& node);
-
+
/// Resolve generic arguments within the path
void resolve_args(::std::function<TypeRef(const char*)> fcn);
@@ -281,6 +273,7 @@ public:
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(); }
+ const ::std::string& crate() const { return m_crate; }
bool is_concrete() const;
@@ -326,12 +319,17 @@ private:
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);
+public:
void bind_module(const Module& mod);
- void bind_enum(const Enum& ent, const ::std::vector<TypeRef>& args);
- void bind_enum_var(const Enum& ent, const ::std::string& name, const ::std::vector<TypeRef>& args);
- void bind_struct(const Struct& ent, const ::std::vector<TypeRef>& args);
+ void bind_enum(const Enum& ent, const ::std::vector<TypeRef>& args={});
+ void bind_enum_var(const Enum& ent, const ::std::string& name, const ::std::vector<TypeRef>& args={});
+ void bind_struct(const Struct& ent, const ::std::vector<TypeRef>& args={});
void bind_struct_member(const Struct& ent, const ::std::vector<TypeRef>& args, const PathNode& member_node);
void bind_static(const Static& ent);
+ void bind_trait(const Trait& ent, const ::std::vector<TypeRef>& args={});
+ void bind_function(const Function& ent, const ::std::vector<TypeRef>& args={}) {
+ m_binding = PathBinding::make_Function({&ent});
+ }
};
} // namespace AST
diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp
index ca5d8e4e..70bfc080 100644
--- a/src/convert/resolve.cpp
+++ b/src/convert/resolve.cpp
@@ -4,6 +4,8 @@
*
* convert/resolve.cpp
* - Resolve names into absolute format
+ *
+ * - Converts all paths into a canonical format (absolute, local, or UFCS)
*/
#include "../common.hpp"
#include "../ast/ast.hpp"
@@ -82,6 +84,7 @@ public:
void handle_params(AST::TypeParams& params) override;
virtual void handle_path(AST::Path& path, CASTIterator::PathMode mode) override;
+ void handle_path_abs(AST::Path& path, CASTIterator::PathMode mode);
void handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mode);
bool find_trait_item(const AST::Path& path, AST::Trait& trait, const ::std::string& item_name, bool& out_is_method, AST::Path& out_trait_path);
virtual void handle_type(TypeRef& type) override;
@@ -381,39 +384,43 @@ bool lookup_path_in_module(const AST::Crate& crate, const AST::Module& module, c
TRACE_FUNCTION_F("mod_path="<<mod_path);
// - Allow leaf nodes if path is a single node, don't skip private wildcard imports
auto item = module.find_item(name, is_leaf, false);
- switch(item.type())
- {
- case AST::Module::ItemRef::ITEM_none:
+ TU_MATCH_DEF(AST::Module::ItemRef, (item), (i),
+ (
+ path = mod_path + path;
+ //path.resolve( crate );
+ return true;
+ ),
+ (None,
return false;
- case AST::Module::ItemRef::ITEM_Use: {
- const auto& imp = item.unwrap_Use();
+ ),
+ (Use,
+ const auto& imp = i;
if( imp.name == "" )
{
DEBUG("Wildcard import found, " << imp.data << " + " << path);
// Wildcard path, prefix entirely with the path
path = imp.data + path;
- path.resolve( crate );
+ //path.resolve( crate );
return true;
}
else
{
DEBUG("Named import found, " << imp.data << " + " << path << " [1..]");
path = AST::Path::add_tailing(imp.data, path);
- path.resolve( crate );
+ //path.resolve( crate );
return true;
}
- return false; }
- case AST::Module::ItemRef::ITEM_Module:
+ return false;
+ ),
+ (Module,
// Check name down?
// Add current module path
path = mod_path + path;
- path.resolve( crate );
+ //path.resolve( crate );
return true;
- default:
- path = mod_path + path;
- path.resolve( crate );
- return true;
- }
+ )
+ )
+ assert(!"");
}
bool lookup_path_in_module(const AST::Crate& crate, const AST::Module& module, const AST::Path& mod_path, AST::Path& path) {
return lookup_path_in_module(crate, module, mod_path, path, path[0].name(), path.size() == 1);
@@ -484,19 +491,13 @@ void CPathResolver::handle_path(AST::Path& path, CASTIterator::PathMode mode)
(Invalid),
(Local),
(Relative,
- for( auto& ent : info.nodes )
- for( auto& arg : ent.args() )
- handle_type(arg);
+ assert( !"Relative path after handle_path_int");
),
(Self,
- for( auto& ent : info.nodes )
- for( auto& arg : ent.args() )
- handle_type(arg);
+ assert( !"Relative (self) path after handle_path_int");
),
(Super,
- for( auto& ent : info.nodes )
- for( auto& arg : ent.args() )
- handle_type(arg);
+ assert( !"Relative (super) path after handle_path_int");
),
(Absolute,
for( auto& ent : info.nodes )
@@ -512,6 +513,7 @@ void CPathResolver::handle_path(AST::Path& path, CASTIterator::PathMode mode)
)
)
}
+
void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode)
{
// Convert to absolute
@@ -519,6 +521,7 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode
switch( path.class_tag() )
{
case AST::Path::Class::Invalid:
+ // TODO: Throw an error
assert( !path.m_class.is_Invalid() );
return;
// --- Already absolute forms
@@ -526,22 +529,24 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode
case AST::Path::Class::Absolute:
DEBUG("Absolute - binding");
INDENT();
+ handle_path_abs(path, mode);
+ // TODO: Move Path::resolve() to this file
// Already absolute, our job is done
// - However, if the path isn't bound, bind it
if( path.binding().is_Unbound() ) {
- path.resolve(m_crate);
+ //path.resolve(m_crate);
}
else {
DEBUG("- Path " << path << " already bound");
}
UNINDENT();
break;
- // > UFCS: Expand the types
+ // > UFCS: Resolve the type and trait
case AST::Path::Class::UFCS:
handle_path_ufcs(path, mode);
break;
// > Variable: (wait, how is this known already?)
- // - 'self'
+ // - 'self', 'Self'
case AST::Path::Class::Local:
if( !path.binding().is_Unbound() )
{
@@ -552,7 +557,7 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode
const auto& info = path.m_class.as_Local();
// 1. Check for local items
if( this->find_local_item(path, info.name, (mode == CASTIterator::MODE_EXPR)) ) {
- path.resolve(m_crate);
+ //path.resolve(m_crate);
break ;
}
else {
@@ -564,7 +569,7 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode
}
// 3. Module items
if( this->find_mod_item(path, info.name) ) {
- path.resolve(m_crate);
+ //path.resolve(m_crate);
break;
}
else {
@@ -583,7 +588,7 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode
{
bool allow_variables = (mode == CASTIterator::MODE_EXPR && path.is_trivial());
if( this->find_local_item(path, path[0].name(), allow_variables) ) {
- path.resolve(m_crate);
+ //path.resolve(m_crate);
break ;
}
else {
@@ -623,7 +628,7 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode
// 3. current module
{
if( this->find_mod_item(path, path[0].name()) ) {
- path.resolve(m_crate);
+ //path.resolve(m_crate);
break;
}
else {
@@ -663,6 +668,215 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode
// TODO: Are there any reasons not to be bound at this point?
//assert( !path.binding().is_Unbound() );
}
+void CPathResolver::handle_path_abs(AST::Path& path, CASTIterator::PathMode mode)
+{
+ //bool expect_params = false;
+
+ assert( path.m_class.is_Absolute() );
+
+ auto& nodes = path.m_class.as_Absolute().nodes;
+
+ unsigned int slice_from = 0; // Used when rewriting the path to be relative to its crate root
+
+ // Iterate through nodes, starting at the root module of the specified crate
+ // - Locate the referenced item, and fail if the
+ ::std::vector<const AST::Module*> mod_stack;
+ const AST::Module* mod = &this->m_crate.get_root_module(path.crate());
+ for(unsigned int i = 0; i < nodes.size(); i ++ )
+ {
+ mod_stack.push_back(mod);
+ const bool is_last = (i+1 == nodes.size());
+ const AST::PathNode& node = nodes[i];
+ DEBUG("[" << i << "/"<<nodes.size()<<"]: " << node);
+
+ if( node.name()[0] == '#' )
+ {
+ // HACK - Compiler-provided functions/types live in the special '#' module
+ if( node.name() == "#" ) {
+ if( i != 0 )
+ throw ParseError::BugCheck("# module not at path root");
+ mod = &g_compiler_module;
+ continue ;
+ }
+
+ // Hacky special case - Anon modules are indexed
+ // - Darn you C++ and no string views
+ unsigned int index = ::std::strtoul(node.name().c_str()+1, nullptr, 10); // Parse the number at +1
+ DEBUG(" index = " << index);
+ if( index >= mod->anon_mods().size() )
+ throw ParseError::Generic("Anon module index out of range");
+ mod = mod->anon_mods().at(index);
+ continue ;
+ }
+
+ auto item_ref = mod->find_item(node.name(), is_last); // Only allow leaf nodes (functions and statics) if this is the last node
+ TU_MATCH( AST::Module::ItemRef, (item_ref), (item),
+ // Not found
+ (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 && nodes[i-1].name()[0] == '#' && nodes[i-1].name().size() > 1 )
+ {
+ i --;
+ mod_stack.pop_back();
+ mod = mod_stack.back();
+ mod_stack.pop_back();
+ nodes.erase(nodes.begin()+i);
+ i --;
+ DEBUG("Failed to locate item in nested, look upwards");
+
+ continue ;
+ }
+ throw ParseError::Generic("Unable to find component '" + node.name() + "'");
+ ),
+ // Sub-module
+ (Module,
+ DEBUG("Sub-module : " << node.name());
+ if( node.args().size() )
+ throw ParseError::Generic("Generic params applied to module");
+ mod = &item;
+ ),
+ // Crate
+ (Crate,
+ const ::std::string& crate_name = item;
+ DEBUG("Extern crate '" << node.name() << "' = '" << crate_name << "'");
+ if( node.args().size() )
+ throw ParseError::Generic("Generic params applied to extern crate");
+ path.set_crate( crate_name );
+ slice_from = i+1;
+ mod = &this->m_crate.get_root_module(crate_name);
+ ),
+
+ // Type Alias
+ (TypeAlias,
+ const auto& ta = item;
+ DEBUG("Type alias <"<<ta.params()<<"> " << ta.type());
+ //if( node.args().size() != ta.params().size() )
+ // throw ParseError::Generic("Param count mismatch when referencing type alias");
+ // 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, nodes[i]);
+ goto ret;
+ }
+ else {
+ throw ParseError::Todo("Path::resolve() type method");
+ }
+ ),
+
+ // Function
+ (Function,
+ //const auto& fn = item;
+ DEBUG("Found function");
+ if( is_last ) {
+ //check_param_counts(fn.params(), expect_params, nodes[i]);
+ goto ret;
+ }
+ else {
+ throw ParseError::Generic("Import of function, too many extra nodes");
+ }
+ ),
+
+ // Trait
+ (Trait,
+ //const auto& t = item;
+ DEBUG("Found trait");
+ if( is_last ) {
+ //check_param_counts(t.params(), expect_params, nodes[i]);
+ goto ret;
+ }
+ else {
+ throw ParseError::Todo("CPathResolver::handle_path_abs - Trait into UFCS");
+ }
+ ),
+
+ // Struct
+ (Struct,
+ const auto& str = item;
+ DEBUG("Found struct");
+ if( is_last ) {
+ //check_param_counts(str.params(), expect_params, nodes[i]);
+ path.bind_struct(str, node.args());
+ goto ret;
+ }
+ else {
+ throw ParseError::Todo("CPathResolver::handle_path_abs - Struct into UFCS");
+ }
+ ),
+
+ // Enum / enum variant
+ (Enum,
+ const auto& enm = item;
+ DEBUG("Found enum");
+ if( is_last ) {
+ //check_param_counts(enm.params(), expect_params, nodes[i]);
+ path.bind_enum(enm, node.args());
+ goto ret;
+ }
+ else {
+ // TODO: Should enum variants be converted into UFCS, or left as is?
+ // - UFCS is actually valid... oddly enough, except in use statements
+ throw ParseError::Todo("CPathResolver::handle_path_abs - Enum into UFCS");
+ }
+ ),
+
+ (Static,
+ const auto& st = item;
+ DEBUG("Found static/const");
+ if( is_last ) {
+ if( node.args().size() )
+ throw ParseError::Generic("Unexpected generic params on static/const");
+ path.bind_static(st);
+ goto ret;
+ }
+ else {
+ throw ParseError::Generic("Binding path to static, trailing nodes");
+ }
+ ),
+
+ // Re-export
+ (Use,
+ const auto& imp = item;
+ 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
+ for( unsigned int j = i; j < nodes.size(); j ++ )
+ {
+ newnodes.push_back( nodes[j] );
+ }
+ }
+ else
+ {
+ // replace nodes 0:i with the source path
+ for( unsigned int j = i+1; j < nodes.size(); j ++ )
+ {
+ newnodes.push_back( nodes[j] );
+ }
+ }
+
+ DEBUG("- newpath = " << newpath);
+ // TODO: This should check for recursion somehow
+ this->handle_path_abs(newpath, mode);
+
+ path = mv$(newpath);
+ return;
+ )
+ )
+ }
+
+ // We only reach here if the path points to a module
+ path.bind_module( *mod );
+ret:
+ if( slice_from > 0 )
+ {
+ DEBUG("Removing " << slice_from << " nodes to rebase path to crate root");
+ nodes.erase(nodes.begin(), nodes.begin()+slice_from);
+ }
+ return ;
+}
void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mode)
{
assert(path.m_class.is_UFCS());
@@ -768,8 +982,6 @@ void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mod
IF_OPTION_SOME(item, impl.find_named_item(item_name), {
DEBUG("Found matching inherent impl");
*info.trait = TypeRef(TypeRef::TagInvalid());
- //path.set_binding(item);
- path.resolve(m_crate);
return ;
})
}
@@ -783,9 +995,6 @@ void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mod
if( trait.has_named_item(item_name, is_fcn) ) {
IF_OPTION_SOME(impl, m_crate.find_impl( trait_p, *info.type ), {
*info.trait = TypeRef( trait_p );
- //auto item = impl.find_named_item(item_name).unwrap();
- //path.set_binding(item);
- path.resolve(m_crate);
return ;
})
}
@@ -793,13 +1002,9 @@ void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mod
throw ParseError::Todo("CPathResolver::handle_path_ufcs - UFCS, find trait");
}
-
- path.resolve(m_crate);
}
}
else {
- // 3. Call resolve to attempt binding
- path.resolve(m_crate);
}
}
@@ -910,7 +1115,7 @@ bool CPathResolver::find_super_mod_item(AST::Path& path, const ::std::string& na
if( super_path.nodes().back().name()[0] == '#' )
throw ParseError::Todo("Correct handling of 'super' in anon modules (parent is anon)");
// 2. Resolve that path
- super_path.resolve(m_crate);
+ //super_path.resolve(m_crate);
// 3. Call lookup_path_in_module
return lookup_path_in_module(m_crate, *super_path.binding().as_Module().module_, super_path, path, name, path.size()==1);
}
@@ -953,7 +1158,7 @@ void CPathResolver::handle_type(TypeRef& type)
else {
TU_MATCH(SelfType, (this->m_self_type.back()), (ent),
(None,
- assert(!"");
+ assert(!"SelfType is None in CPathResolver::handle_type");
),
(Type,
type = ent.type;
@@ -1072,7 +1277,7 @@ void CPathResolver::handle_module(AST::Path path, AST::Module& mod)
}
void CPathResolver::handle_trait(AST::Path path, AST::Trait& trait)
{
- path.resolve(m_crate);
+ //path.resolve(m_crate);
// Handle local
m_scope_stack.back().traits.push_back( ::std::pair<AST::Path, const AST::Trait&>(path, trait) );
@@ -1100,6 +1305,7 @@ void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& mod
break;
// 'super' - Add parent path
// - TODO: Handle nested modules correctly.
+ // - TODO: Chaining 'super' is valid
case AST::Path::Class::Super: {
if( modpath.size() < 1 )
throw ParseError::Generic("Encountered 'super' at crate root");
@@ -1125,7 +1331,84 @@ void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& mod
}
// Run resolution on import
- imp.data.resolve(crate, false);
+ // TODO: Need to truely absolutise?
+ {
+ const AST::Module* mod = &crate.root_module();
+ for(const auto& node : p.nodes() ) {
+ if( node.args().size() > 0 ) {
+ throw ParseError::Generic("Unexpected generic params in use path");
+ }
+ if( mod == nullptr ) {
+ if( p.binding().is_Enum() ) {
+ auto& enm = *p.binding().as_Enum().enum_;
+ for(const auto& variant : enm.variants()) {
+ if( variant.m_name == node.name() ) {
+ p.bind_enum_var(enm, node.name());
+ break;
+ }
+ }
+ if( p.binding().is_Enum() ) {
+ throw ParseError::Generic( FMT("Unable to find component '" << node.name() << "' of import " << p) );
+ }
+ break;
+ }
+ else {
+ throw ParseError::Generic("Extra path components after final item");
+ }
+ }
+ auto item = mod->find_item(node.name());
+ // HACK: Not actually a normal TU, but it fits the same pattern
+ TU_MATCH(AST::Module::ItemRef, (item), (i),
+ (None,
+ throw ParseError::Generic( FMT("Unable to find component '" << node.name() << "' of import " << p) );
+ ),
+ (Module,
+ mod = &i;
+ ),
+ (Crate,
+ mod = &crate.get_root_module(i);
+ ),
+ (TypeAlias,
+ throw ParseError::Todo("Bind to type alias in use resolution");
+ //p.bind_type_alias(i);
+ mod = nullptr;
+ ),
+ (Function,
+ p.bind_function(i);
+ mod = nullptr;
+ ),
+ (Trait,
+ p.bind_trait(i);
+ mod = nullptr;
+ ),
+ (Struct,
+ p.bind_struct(i);
+ mod = nullptr;
+ ),
+ (Enum,
+ // - Importing an enum item will be handled in the nullptr check above
+ p.bind_enum(i);
+ mod = nullptr;
+ ),
+ (Static,
+ p.bind_static(i);
+ mod = nullptr;
+ ),
+ (Use,
+ if(i.name == "") {
+ throw ParseError::Todo("Handle resolving to wildcard use in use resolution");
+ }
+ else {
+ // Restart lookup using new path
+ }
+ )
+ )
+ }
+ if( mod != nullptr ) {
+ p.bind_module(*mod);
+ }
+ }
+ //imp.data.resolve(crate, false);
DEBUG("Resolved import : " << imp.data);
// If wildcard, make sure it's sane
@@ -1136,7 +1419,7 @@ void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& mod
throw ParseError::Generic("Wildcard imports are only allowed on modules and enums");
),
(Unbound,
- throw ParseError::BugCheck("path unbound after calling .resolve()");
+ throw ParseError::BugCheck("Wildcard import path unbound after calling .resolve()");
),
(Module, (void)0;),
(Enum, (void)0;)
@@ -1146,9 +1429,9 @@ void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& mod
for( auto& new_imp : new_imports )
{
- if( new_imp.binding().is_Unbound() ) {
- new_imp.resolve(crate, false);
- }
+ //if( new_imp.binding().is_Unbound() ) {
+ // new_imp.resolve(crate, false);
+ //}
mod.add_alias(false, new_imp, new_imp[new_imp.size()-1].name());
}
@@ -1163,7 +1446,7 @@ void SetCrateName_Type(const AST::Crate& crate, ::std::string name, TypeRef& typ
if( type.is_path() )
{
type.path().set_crate(name);
- type.path().resolve(crate);
+ //type.path().resolve(crate);
}
}
@@ -1176,7 +1459,7 @@ void SetCrateName_Mod(const AST::Crate& crate, ::std::string name, AST::Module&
{
imp.data.set_crate(name);
// - Disable expectation of type parameters
- imp.data.resolve(crate, false);
+ //imp.data.resolve(crate, false);
}
// TODO: All other types
@@ -1209,7 +1492,7 @@ void ResolvePaths(AST::Crate& crate)
UNINDENT();
// Then do path resolution on all other items
- CPathResolver pr(crate);
+ CPathResolver pr(crate);
DEBUG(" ---");
pr.handle_module(AST::Path("", {}), crate.root_module());
DEBUG(" <<<");
diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp
index 34657ff5..208e15ea 100644
--- a/src/include/tagged_union.hpp
+++ b/src/include/tagged_union.hpp
@@ -45,7 +45,7 @@
#define TU_DISPA7(n, a, a1,a2,a3, b1,b2, c1,c2) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA2(n,a, b1,b2) TU_DISPA2(n,a, c1,c2)
#define TU_DISPA8(n, a, a1,a2,a3, b1,b2,b3, c1,c2) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA3(n,a, b1,b2,b3) TU_DISPA2(n,a, c1,c2)
#define TU_DISPA9(n, a, a1,a2,a3, b1,b2,b3, c1,c2,c3) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA3(n,a, b1,b2,b3) TU_DISPA3(n,a, c1,c2,c3)
-#define TU_DISPA10(n, a, a1,a2,a3, b1,b2,b3, c1,c2,c3, d1) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA3(n,a, b1,b2,b3) TU_DISPA3(n,a, c1,c2,c3) TU_DISPA(n,a, d1)
+#define TU_DISPA10(n, a, a1,a2,a3, b1,b2,b3, c1,c2,c3, d1) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA3(n,a, b1,b2,b3) TU_DISPA3(n,a, c1,c2,c3) TU_DISPA(n, (TU_EXP a, TU_EXP d1))
#define TU_DISPA11(n, a, a1,a2,a3, b1,b2,b3, c1,c2,c3, d1,d2) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA3(n,a, b1,b2,b3) TU_DISPA3(n,a, c1,c2,c3) TU_DISPA2(n,a, d1,d2)
#define TU_DISPA12(n, a, a1,a2,a3, b1,b2,b3, c1,c2,c3, d1,d2,d3) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA3(n,a, b1,b2,b3) TU_DISPA3(n,a, c1,c2,c3) TU_DISPA3(n,a, d1,d2,d3)
#define TU_DISPA13(n, a, a1,a2,a3,a4, b1,b2,b3, c1,c2,c3, d1,d2,d3) TU_DISPA4(n,a, a1,a2,a3,a4) TU_DISPA3(n,a, b1,b2,b3) TU_DISPA3(n,a, c1,c2,c3) TU_DISPA3(n,a, d1,d2,d3)