summaryrefslogtreecommitdiff
path: root/src/ast/path.cpp
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/ast/path.cpp
parentf56b813d42ebb4629345f63e6ea2c4704bb28e0a (diff)
downloadmrust-01ec57f596f89d4b52b378975f941e2ed8d2e563.tar.gz
Move path binding logic into Resolve path to simplify
Diffstat (limited to 'src/ast/path.cpp')
-rw-r--r--src/ast/path.cpp370
1 files changed, 9 insertions, 361 deletions
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)
{