diff options
author | John Hodge <tpg@mutabah.net> | 2015-03-23 15:00:02 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2015-03-23 15:00:02 +0800 |
commit | 802c2c5d616d537ed8becea81c2ee6b48ae8f078 (patch) | |
tree | 3af733445b819980c8fa9ed5ec1c2dc4d85e7b20 /src | |
parent | d004d8293e289942a99a2137ce0a0455cf078b0d (diff) | |
download | mrust-802c2c5d616d537ed8becea81c2ee6b48ae8f078.tar.gz |
Move item lookup from AST::Path to AST::Module
Diffstat (limited to 'src')
-rw-r--r-- | src/ast/ast.cpp | 124 | ||||
-rw-r--r-- | src/ast/ast.hpp | 38 | ||||
-rw-r--r-- | src/ast/path.cpp | 322 | ||||
-rw-r--r-- | src/convert/resolve.cpp | 4 |
4 files changed, 297 insertions, 191 deletions
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 T>
+typename ::std::vector<Item<T> >::const_iterator find_named(const ::std::vector<Item<T> >& vec, const ::std::string& name)
+{
+ return ::std::find_if(vec.begin(), vec.end(), [&name](const Item<T>& 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<Module,bool>& 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<Path>, Use)
+ #undef _
+ };
+ ItemRef find_item(const ::std::string& needle) const;
::std::vector<MetaItem>& 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<Module,bool>& 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.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 ) { + 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 <"<<it->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<AST::Path> 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);
}
|