From 802c2c5d616d537ed8becea81c2ee6b48ae8f078 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 23 Mar 2015 15:00:02 +0800 Subject: Move item lookup from AST::Path to AST::Module --- src/ast/ast.cpp | 124 +++++++++++++++++++ src/ast/ast.hpp | 38 ++++++ src/ast/path.cpp | 322 ++++++++++++++++++++---------------------------- src/convert/resolve.cpp | 4 +- 4 files changed, 297 insertions(+), 191 deletions(-) (limited to 'src') diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 42052c5e..a695c6f5 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -491,6 +491,130 @@ void Module::iterate_functions(fcn_visitor_t *visitor, const Crate& crate) } } +template +typename ::std::vector >::const_iterator find_named(const ::std::vector >& vec, const ::std::string& name) +{ + return ::std::find_if(vec.begin(), vec.end(), [&name](const Item& x) { + return x.name == name; + }); +} + +Module::ItemRef Module::find_item(const ::std::string& needle) const +{ + TRACE_FUNCTION_F("needle = " << needle); + // Sub-modules + { + auto& sms = submods(); + auto it = ::std::find_if(sms.begin(), sms.end(), [&needle](const ::std::pair& x) { + return x.first.name() == needle; + }); + if( it != sms.end() ) { + return ItemRef(it->first); + } + } + + // External crates + { + auto& crates = this->extern_crates(); + auto it = find_named(crates, needle); + if( it != crates.end() ) { + return ItemRef(it->data); + } + } + + // Type Aliases + { + auto& items = this->type_aliases(); + auto it = find_named(items, needle); + if( it != items.end() ) { + return ItemRef(it->data); + } + } + + // Functions + { + auto& items = this->functions(); + auto it = find_named(items, needle); + if( it != items.end() ) { + return ItemRef(it->data); + } + } + + // Traits + { + auto& items = this->traits(); + auto it = find_named(items, needle); + if( it != items.end() ) { + return ItemRef(it->data); + } + } + + // Structs + { + auto& items = this->structs(); + auto it = find_named(items, needle); + if( it != items.end() ) { + return ItemRef(it->data); + } + } + + // Enums + { + auto& items = this->enums(); + auto it = find_named(items, needle); + if( it != items.end() ) { + return ItemRef(it->data); + } + } + + // Statics + { + auto& items = this->statics(); + auto it = find_named(items, needle); + if( it != items.end() ) { + return ItemRef(it->data); + } + } + + // - Re-exports + // > Comes last, as it's a potentially expensive operation + { + for( const auto& imp : this->imports() ) + { + if( !imp.is_pub ) + { + // not public, ignore + } + else if( imp.name == needle ) + { + return ItemRef(imp); + } + else if( imp.name == "" ) + { + // Loop avoidance, don't check this + //if( &imp.data == this ) + // continue ; + // + //if( !imp.data.is_bound() ) + //{ + // // 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("Path::resolve() wildcard re-export"); + } + else + { + // Can't match, ignore + } + } + } + + return Module::ItemRef(); +} + SERIALISE_TYPE(TypeAlias::, "AST_TypeAlias", { s << m_params; s << m_type; diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index ece9704f..60621036 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -596,6 +596,44 @@ public: void iterate_functions(fcn_visitor_t* visitor, const Crate& crate); const ::std::string& name() const { return m_name; } + class ItemRef + { + public: + enum Type + { + ITEM_none, + ITEM_Module, + ITEM_Crate, + ITEM_TypeAlias, + ITEM_Function, + ITEM_Trait, + ITEM_Struct, + ITEM_Enum, + ITEM_Static, + ITEM_Use, + }; + private: + Type m_type; + const void* m_ref; + public: + ItemRef(): m_type(ITEM_none) {} + + Type type() { return m_type; } + #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) + _(::std::string, Crate) + _(TypeAlias, TypeAlias) + _(Function, Function) + _(Trait, Trait) + _(Struct, Struct) + _(Enum, Enum) + _(Static, Static) + _(Item, Use) + #undef _ + }; + ItemRef find_item(const ::std::string& needle) const; ::std::vector& attrs() { return m_attrs; } itemlist_fcn_t& functions() { return m_functions; } diff --git a/src/ast/path.cpp b/src/ast/path.cpp index 7eab20dd..3e93e888 100644 --- a/src/ast/path.cpp +++ b/src/ast/path.cpp @@ -100,207 +100,151 @@ void Path::resolve(const Crate& root_crate) continue ; } - // Sub-modules + auto item = mod->find_item(node.name()); + switch( item.type() ) { - auto& sms = mod->submods(); - auto it = ::std::find_if(sms.begin(), sms.end(), [&node](const ::std::pair& x) { - return x.first.name() == node.name(); - }); - if( it != sms.end() ) - { - DEBUG("Sub-module '" << node.name() << "'"); - if( node.args().size() ) - throw ParseError::Generic("Generic params applied to module"); - mod = &it->first; - continue; + // Not found + case AST::Module::ItemRef::ITEM_none: + // TODO: If parent node is anon, backtrack and try again + throw ParseError::Generic("Unable to find component '" + node.name() + "'"); + break; + + // 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.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 ) { + m_binding_type = ALIAS; + m_binding.alias_ = &ta; + goto ret; } - } - // External crates - { - auto& crates = mod->extern_crates(); - auto it = find_named(crates, node.name()); - if( it != crates.end() ) - { - DEBUG("Extern crate '" << node.name() << "' = '" << it->data << "'"); - if( node.args().size() ) - throw ParseError::Generic("Generic params applied to extern crate"); - m_crate = it->data; - slice_from = i+1; - mod = &root_crate.get_root_module(it->data); - continue; + else { + throw ParseError::Todo("Path::resolve() type method"); } - } - - // Type Aliases - { - auto& items = mod->type_aliases(); - auto it = find_named(items, node.name()); - if( it != items.end() ) - { - DEBUG("Type alias <"<data.params()<<"> " << it->data.type()); - //if( node.args().size() != it->data.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 ) { - m_binding_type = ALIAS; - m_binding.alias_ = &it->data; - 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 ) { + m_binding_type = FUNCTION; + m_binding.func_ = &fn; + goto ret; } - } - - // - Functions - { - auto& items = mod->functions(); - auto it = find_named(items, node.name()); - if( it != items.end() ) - { - DEBUG("Found function"); - if( is_last ) { - m_binding_type = FUNCTION; - m_binding.func_ = &it->data; - goto ret; - } - else { - throw ParseError::Generic("Import of function, too many extra nodes"); - } + else { + throw ParseError::Generic("Import of function, too many extra nodes"); } - } - - // - Traits - { - auto& items = mod->traits(); - auto it = find_named(items, node.name()); - if( it != items.end() ) - { - DEBUG("Found trait"); - if( is_last ) { - m_binding_type = TRAIT; - m_binding.trait_ = &it->data; - goto ret; - } - else if( is_sec_last ) { - m_binding_type = TRAIT_METHOD; - m_binding.trait_ = &it->data; - goto ret; - } - else { - throw ParseError::Generic("Import of trait, too many extra nodes"); - } + break; } + + // Trait + case AST::Module::ItemRef::ITEM_Trait: { + const auto& t = item.unwrap_Trait(); + DEBUG("Found trait"); + if( is_last ) { + m_binding_type = TRAIT; + m_binding.trait_ = &t; + goto ret; } - } - // - Structs - { - auto& items = mod->structs(); - auto it = find_named(items, node.name()); - if( it != items.end() ) - { - DEBUG("Found struct"); - if( is_last ) { - bind_struct(it->data, node.args()); - goto ret; - } - else if( is_sec_last ) { - throw ParseError::Todo("Path::resolve() struct method"); - } - else { - throw ParseError::Generic("Import of struct, too many extra nodes"); - } + else if( is_sec_last ) { + m_binding_type = TRAIT_METHOD; + m_binding.trait_ = &t; + goto ret; } - } - // - Enums (and variants) - { - auto& enums = mod->enums(); - auto it = find_named(enums, node.name()); - if( it != enums.end() ) - { - DEBUG("Found enum"); - if( is_last ) { - bind_enum(it->data, node.args()); - goto ret; - } - else if( is_sec_last ) { - bind_enum_var(it->data, m_nodes[i+1].name(), node.args()); - goto ret; - } - else { - throw ParseError::Generic("Binding path to enum, too many extra nodes"); - } + else { + throw ParseError::Generic("Import of trait, too many extra nodes"); } - } - // - Constants / statics - { - auto& items = mod->statics(); - auto it = find_named(items, node.name()); - if( it != items.end() ) - { - DEBUG("Found static/const"); - if( is_last ) { - if( node.args().size() ) - throw ParseError::Generic("Unexpected generic params on static/const"); - bind_static(it->data); - goto ret; - } - else { - throw ParseError::Generic("Binding path to static, trailing nodes"); - } + break; } + + // Struct + case AST::Module::ItemRef::ITEM_Struct: { + const auto& str = item.unwrap_Struct(); + DEBUG("Found struct"); + if( is_last ) { + bind_struct(str, node.args()); + goto ret; } - } + else if( is_sec_last ) { + throw ParseError::Todo("Path::resolve() struct method"); + } + else { + throw ParseError::Generic("Import of struct, too many extra nodes"); + } + break; } - // - Re-exports - // > Comes last, as it's a potentially expensive operation - { - for( const auto& imp : mod->imports() ) + // Enum / enum variant + case AST::Module::ItemRef::ITEM_Enum: { + const auto& enm = item.unwrap_Enum(); + DEBUG("Found enum"); + if( is_last ) { + bind_enum(enm, node.args()); + goto ret; + } + else if( is_sec_last ) { + bind_enum_var(enm, m_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; } + + // + case AST::Module::ItemRef::ITEM_Use: { + const auto& imp = item.unwrap_Use(); + // 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 ++ ) { - if( !imp.is_pub ) - { - // not public, ignore - } - else if( imp.name == node.name() ) - { - // 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 ++ ) - { - newpath.m_nodes.push_back( m_nodes[j] ); - } - DEBUG("- newpath = " << newpath); - // TODO: This should check for recursion somehow - newpath.resolve(root_crate); - - *this = newpath; - DEBUG("Alias resolved, *this = " << *this); - return ; - } - else if( imp.name == "" ) - { - // Loop avoidance, don't check this - if( &imp.data == this ) - continue ; - - if( !imp.data.is_bound() ) - { - // 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("Path::resolve() wildcard re-export"); - } - else - { - // Can't match, ignore - } + newpath.m_nodes.push_back( m_nodes[j] ); } + DEBUG("- newpath = " << newpath); + // TODO: This should check for recursion somehow + newpath.resolve(root_crate); + + *this = newpath; + DEBUG("Alias resolved, *this = " << *this); + break; } } - throw ParseError::Generic("Unable to find component '" + node.name() + "'"); } // We only reach here if the path points to a module @@ -465,7 +409,8 @@ void Path::print_pretty(::std::ostream& os) const { case Path::RELATIVE: s << "RELATIVE"; break; case Path::ABSOLUTE: s << "ABSOLUTE"; break; - case Path::LOCAL: s << "LOCAL"; break; + case Path::LOCAL: s << "LOCAL"; break; + case Path::UFCS: s << "UFCS"; break; } return s; } @@ -476,6 +421,7 @@ void operator>>(Deserialiser& s, Path::Class& pc) if(n == "RELATIVE") pc = Path::RELATIVE; else if(n == "ABSOLUTE") pc = Path::ABSOLUTE; else if(n == "LOCAL") pc = Path::LOCAL; + else if(n == "UFCS") pc = Path::UFCS; else throw ::std::runtime_error("Unknown path class : " + n); } SERIALISE_TYPE(Path::, "AST_Path", { diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp index 9439297f..2de4ae44 100644 --- a/src/convert/resolve.cpp +++ b/src/convert/resolve.cpp @@ -450,9 +450,6 @@ void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& mod ::std::vector new_imports; for( auto& imp : mod.imports() ) { - // TODO: Handle 'super' and 'self' imports - // - Any other type of import will be absolute - if( !imp.data.is_absolute() ) { if( imp.data[0].name() == "super" ) { @@ -466,6 +463,7 @@ void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& mod } else { auto newpath = modpath + imp.data; + // TODO: Undo anon modules until item is found DEBUG("Absolutised path " << imp.data << " into " << newpath); imp.data = ::std::move(newpath); } -- cgit v1.2.3