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) | 
