diff options
author | John Hodge <tpg@mutabah.net> | 2015-11-03 12:01:01 +1100 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2015-11-03 12:01:01 +1100 |
commit | 01ec57f596f89d4b52b378975f941e2ed8d2e563 (patch) | |
tree | 58e17f12b09b1be1dc37d0143ea2e4cf0dcaa9c2 /src | |
parent | f56b813d42ebb4629345f63e6ea2c4704bb28e0a (diff) | |
download | mrust-01ec57f596f89d4b52b378975f941e2ed8d2e563.tar.gz |
Move path binding logic into Resolve path to simplify
Diffstat (limited to 'src')
-rw-r--r-- | src/ast/ast.cpp | 4 | ||||
-rw-r--r-- | src/ast/ast.hpp | 45 | ||||
-rw-r--r-- | src/ast/path.cpp | 370 | ||||
-rw-r--r-- | src/ast/path.hpp | 22 | ||||
-rw-r--r-- | src/convert/resolve.cpp | 385 | ||||
-rw-r--r-- | src/include/tagged_union.hpp | 2 |
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) |