diff options
author | John Hodge <tpg@mutabah.net> | 2015-06-04 14:41:34 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2015-06-04 14:41:34 +0800 |
commit | f15fcf3c440e3c9c40fa606b0904fb85a8510464 (patch) | |
tree | a477b63bf9d9141b170292aedb6df9cf8eeb2580 | |
parent | 029bf073a1ec77a06d6c64ab7166c74f13486926 (diff) | |
download | mrust-f15fcf3c440e3c9c40fa606b0904fb85a8510464.tar.gz |
Rework path handling and resolve to better handle Self
-rw-r--r-- | src/ast/ast.cpp | 4 | ||||
-rw-r--r-- | src/ast/path.cpp | 107 | ||||
-rw-r--r-- | src/ast/path.hpp | 95 | ||||
-rw-r--r-- | src/convert/ast_iterate.cpp | 20 | ||||
-rw-r--r-- | src/convert/resolve.cpp | 366 | ||||
-rw-r--r-- | src/main.cpp | 2 | ||||
-rw-r--r-- | src/parse/expr.cpp | 2 | ||||
-rw-r--r-- | src/parse/paths.cpp | 5 | ||||
-rw-r--r-- | src/parse/root.cpp | 21 |
9 files changed, 392 insertions, 230 deletions
diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 8515f76e..d712edd3 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -577,7 +577,7 @@ Module::ItemRef Module::find_item(const ::std::string& needle, bool allow_leaves if( allow_leaves )
return ItemRef(it->data);
else
- DEBUG("Skipping static, leaves not allowed");
+ DEBUG("Skipping function, leaves not allowed");
}
}
@@ -634,7 +634,7 @@ Module::ItemRef Module::find_item(const ::std::string& needle, bool allow_leaves }
else if( imp.name == needle )
{
- DEBUG("Match " << needle);
+ DEBUG("Match " << needle << " = " << imp.data);
return ItemRef(imp);
}
else if( imp.name == "" )
diff --git a/src/ast/path.cpp b/src/ast/path.cpp index 328af8d9..519a0b7b 100644 --- a/src/ast/path.cpp +++ b/src/ast/path.cpp @@ -52,13 +52,7 @@ SERIALISE_TYPE(PathNode::, "PathNode", { s.item(m_params); }) -// --- AST::Path -AST::Path::Path(TagUfcs, TypeRef type, TypeRef trait): - m_class(UFCS), - m_ufcs({::std::move(type), ::std::move(trait)} ) -{ -} - +/// Return an iterator to the named item template<typename T> typename ::std::vector<Item<T> >::const_iterator find_named(const ::std::vector<Item<T> >& vec, const ::std::string& name) { @@ -67,6 +61,13 @@ typename ::std::vector<Item<T> >::const_iterator find_named(const ::std::vector< }); } +// --- AST::Path +AST::Path::Path(TagUfcs, TypeRef type, TypeRef trait): + m_class(UFCS), + m_ufcs({::std::move(type), ::std::move(trait)} ) +{ +} + /// Resolve a path into a canonical form, and bind it to the target value void Path::resolve(const Crate& root_crate, bool expect_params) { @@ -524,15 +525,12 @@ void Path::resolve_args(::std::function<TypeRef(const char*)> fcn) switch(m_class) { - case Path::RELATIVE: - case Path::ABSOLUTE: - break; - case Path::LOCAL: - break; case Path::UFCS: m_ufcs[0].resolve_args(fcn); m_ufcs[1].resolve_args(fcn); break; + default: + break; } } @@ -545,8 +543,10 @@ Path& Path::operator+=(const Path& other) return *this; } +/// Match two same-format (i.e. same components) paths together, calling TypeRef::match_args on arguments void Path::match_args(const Path& other, ::std::function<void(const char*,const TypeRef&)> fcn) const { + // TODO: Ensure that the two paths are of a compatible class (same class?) if( m_nodes.size() != other.m_nodes.size() ) throw ::std::runtime_error("Type mismatch (path size)"); for( unsigned int i = 0; i < m_nodes.size(); i++ ) @@ -568,6 +568,10 @@ void Path::match_args(const Path& other, ::std::function<void(const char*,const } } +/// Compare if two paths refer to the same non-generic item +/// +/// - This doesn't handle the (impossible?) case where a generic might +/// cause two different paths to look the same. int Path::equal_no_generic(const Path& x) const { if( m_class != x.m_class ) @@ -624,22 +628,30 @@ void Path::print_pretty(::std::ostream& os) const { switch(m_class) { + case Path::INVALID: os << "/* inv */"; break; + case Path::VARIABLE:os << m_nodes[0].name(); break; case Path::RELATIVE: + for(const auto& n : m_nodes) { + if( &n != &m_nodes[0] ) os << "::"; + os << "::" << n; + } + break; + case Path::SELF: os << "self"; - for(const auto& n : m_nodes) - os << n; + for(const auto& n : m_nodes) os << "::" << n; + break; + case Path::SUPER: + os << "super"; + for(const auto& n : m_nodes) os << "::" << n; break; case Path::ABSOLUTE: if( m_crate != "" ) os << "::" << m_crate; for(const auto& n : m_nodes) - os << n; - break; - case Path::LOCAL: - os << m_nodes[0].name(); + os << "::" << n; break; case Path::UFCS: - throw ParseError::Todo("Path::print_pretty"); + throw ParseError::Todo("Path::print_pretty - UFCS"); } } @@ -653,7 +665,20 @@ void Path::print_pretty(::std::ostream& os) const #if PRETTY_PATH_PRINT switch(path.m_class) { + case Path::INVALID: os << "/*inv*/"; break; + case Path::VARIABLE: os << "/*var*/" << path.m_nodes[0].name(); break; case Path::RELATIVE: + for(const auto& n : path.m_nodes) + { + #if PRETTY_PATH_PRINT + if( &n != &path.m_nodes[0] ) { + os << "::"; + } + #endif + os << n; + } + break; + case Path::SELF: os << "self"; for(const auto& n : path.m_nodes) { @@ -663,6 +688,16 @@ void Path::print_pretty(::std::ostream& os) const os << n; } break; + case Path::SUPER: + os << "super"; + for(const auto& n : path.m_nodes) + { + #if PRETTY_PATH_PRINT + os << "::"; + #endif + os << n; + } + break; case Path::ABSOLUTE: if( path.m_crate != "" ) os << "::\""<<path.m_crate<<"\""; @@ -675,9 +710,6 @@ void Path::print_pretty(::std::ostream& os) const } os << "/*" << path.m_binding << "*/"; break; - case Path::LOCAL: - os << path.m_nodes[0].name(); - break; case Path::UFCS: os << "/*ufcs*/<" << path.m_ufcs[0] << " as " << path.m_ufcs[1] << ">"; for(const auto& n : path.m_nodes) @@ -692,33 +724,40 @@ void Path::print_pretty(::std::ostream& os) const case Path::ABSOLUTE: os << "Path(TagAbsolute, \""<<path.m_crate<<"\", {" << path.m_nodes << "})"; break; - case Path::LOCAL: - os << "Path(TagLocal, " << path.m_nodes[0].name() << ")"; - break; } #endif return os; } ::Serialiser& operator<<(Serialiser& s, Path::Class pc) { + #define _(v) case Path::v: s << #v; break; switch(pc) { - case Path::RELATIVE: s << "RELATIVE"; break; - case Path::ABSOLUTE: s << "ABSOLUTE"; break; - case Path::LOCAL: s << "LOCAL"; break; - case Path::UFCS: s << "UFCS"; break; + _(INVALID ) + _(VARIABLE) + _(RELATIVE) + _(SELF ) + _(SUPER ) + _(ABSOLUTE) + _(UFCS ) } + #undef _ return s; } void operator>>(Deserialiser& s, Path::Class& pc) { ::std::string n; s.item(n); - 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); + #define _(v) if(n == #v) pc = Path::v; else + _(INVALID ) + _(VARIABLE) + _(RELATIVE) + _(SELF ) + _(SUPER ) + _(ABSOLUTE) + _(UFCS ) + throw ::std::runtime_error("Unknown path class : " + n); + #undef _ } SERIALISE_TYPE(Path::, "AST_Path", { s << m_class; diff --git a/src/ast/path.hpp b/src/ast/path.hpp index 5028bebc..f53561fa 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -143,15 +143,28 @@ public: SERIALISABLE_PROTOTYPES(); }; +//TAGGED_ENUM(Class, Local, +// (Local, (::std:string name) ), +// (Variable, (::std:string name) ), +// (Relative, (::std::vector<PathNode> nodes) ), +// (Self, (::std::vector<PathNode> nodes) ), +// (Super, (::std::vector<PathNode> nodes) ), +// (Absolute, (::std::vector<PathNode> nodes) ), +// (UFCS, (TypeRef type; TypeRef trait; ::std::vector<PathNode> nodes) ), +// ); class Path: public ::Serialisable { public: enum Class { - RELATIVE, - ABSOLUTE, - LOCAL, - UFCS, + INVALID, // An empty path, usually invalid + ABSOLUTE, // root-relative path ("::path") + UFCS, // type-relative path ("<Type>::such") + VARIABLE, // Reference to a local variable + + RELATIVE, // Unadorned relative path (e.g. "path::to::item" or "generic_item::<>") + SELF, // module-relative path ("self::path") + SUPER, // parent-relative path ("super::path") }; private: @@ -169,29 +182,16 @@ private: PathBinding m_binding; public: + // INVALID Path(): - m_class(RELATIVE) + m_class(INVALID) {} + + // ABSOLUTE struct TagAbsolute {}; Path(TagAbsolute): m_class(ABSOLUTE) {} - struct TagUfcs {}; - Path(TagUfcs, TypeRef type, TypeRef trait); - struct TagLocal {}; - Path(TagLocal, ::std::string name): - m_class(LOCAL), - m_nodes({PathNode( ::std::move(name), {} )}) - {} - Path(::std::string name): - Path(TagLocal(), ::std::move(name)) - {} - struct TagSuper {}; - Path(TagSuper): - m_class(RELATIVE), - m_nodes({PathNode("super", {})}) - {} - Path(::std::initializer_list<PathNode> l): m_class(ABSOLUTE), m_nodes(l) @@ -202,6 +202,40 @@ public: m_nodes( ::std::move(nodes) ) {} + // UFCS + struct TagUfcs {}; + Path(TagUfcs, TypeRef type, TypeRef trait); + + // VARIABLE + struct TagVariable {}; + Path(TagVariable, ::std::string name): + m_class(VARIABLE), + m_nodes( {PathNode( ::std::move(name), {} )} ) + {} + + // RELATIVE + struct TagRelative {}; + Path(TagRelative): + m_class(RELATIVE), + m_nodes({}) + {} + Path(::std::string name): + m_class(RELATIVE), + m_nodes( {PathNode( ::std::move(name), {} )} ) + {} + // SELF + struct TagSelf {}; + Path(TagSelf): + m_class(SELF), + m_nodes({}) + {} + // SUPER + struct TagSuper {}; + Path(TagSuper): + m_class(SUPER), + m_nodes({}) + {} + void set_crate(::std::string crate) { if( m_crate == "" ) { m_crate = crate; @@ -210,7 +244,6 @@ public: } void set_local() { assert(m_class == RELATIVE); - m_class = LOCAL; } /// Add the all nodes except the first from 'b' to 'a' and return @@ -221,7 +254,11 @@ public: } /// Grab the args from the first node of b, and add the rest to the end of the path void add_tailing(const Path& b) { - if( m_nodes.size() > 0 ) + assert(this->m_class != INVALID); + assert(b.m_class != INVALID); + if( b.m_nodes.size() == 0 ) + ; + else if( m_nodes.size() > 0 ) m_nodes.back().args() = b[0].args(); else if( b[0].args().size() > 0 ) throw ::std::runtime_error("add_tail to empty path, but generics in source"); @@ -232,12 +269,12 @@ public: m_binding = PathBinding(); } Path operator+(PathNode&& pn) const { - Path tmp; + Path tmp = Path(TagRelative()); tmp.append( ::std::move(pn) ); return Path(*this) += tmp; } Path operator+(const ::std::string& s) const { - Path tmp; + Path tmp = Path(TagRelative()); tmp.append(PathNode(s, {})); return Path(*this) += tmp; } @@ -247,6 +284,8 @@ public: Path& operator+=(const Path& x); void append(PathNode node) { + assert(this->m_class != INVALID); + assert(this->m_class != VARIABLE); m_nodes.push_back(node); m_binding = PathBinding(); } @@ -266,7 +305,11 @@ public: void match_args(const Path& other, ::std::function<void(const char*,const TypeRef&)> fcn) const; bool is_trivial() const { - return m_class == RELATIVE && m_nodes.size() == 1 && m_nodes[0].args().size() == 0; + switch(m_class) + { + case RELATIVE: return m_nodes.size() == 1 && m_nodes[0].args().size() == 0; + default: return false; + } } bool is_valid() const { return *this != Path(); } diff --git a/src/convert/ast_iterate.cpp b/src/convert/ast_iterate.cpp index 49aa64c2..24dbf5f0 100644 --- a/src/convert/ast_iterate.cpp +++ b/src/convert/ast_iterate.cpp @@ -258,6 +258,24 @@ void CASTIterator::handle_function(AST::Path path, AST::Function& fcn) DEBUG("ret type"); handle_type(fcn.rettype()); + switch( fcn.fcn_class() ) + { + case AST::Function::CLASS_UNBOUND: + break; + case AST::Function::CLASS_REFMETHOD: + local_variable(false, "self", TypeRef(TypeRef::TagReference(), false, TypeRef(TypeRef::TagArg(), "Self"))); + break; + case AST::Function::CLASS_MUTMETHOD: + local_variable(false, "self", TypeRef(TypeRef::TagReference(), true, TypeRef(TypeRef::TagArg(), "Self"))); + break; + case AST::Function::CLASS_VALMETHOD: + local_variable(false, "self", TypeRef(TypeRef::TagArg(), "Self")); + break; + case AST::Function::CLASS_MUTVALMETHOD: + local_variable(true, "self", TypeRef(TypeRef::TagArg(), "Self")); + break; + } + DEBUG("args"); for( auto& arg : fcn.args() ) { @@ -309,7 +327,7 @@ void CASTIterator::handle_impl(AST::Path modpath, AST::Impl& impl) for( auto& fcn : impl.functions() ) { DEBUG("- Function '" << fcn.name << "'"); - handle_function(AST::Path() + fcn.name, fcn.data); + handle_function(AST::Path(AST::Path::TagRelative()) + fcn.name, fcn.data); } end_scope(); diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp index bb6a15e3..54b0ab39 100644 --- a/src/convert/resolve.cpp +++ b/src/convert/resolve.cpp @@ -47,8 +47,14 @@ class CPathResolver: AST::Module* m_module;
AST::Path m_module_path;
::std::vector< LocalItem > m_locals;
- // TODO: Maintain a stack of variable scopes
- ::std::vector< ::std::pair<unsigned int,AST::Module*> > m_module_stack;
+ struct Scope {
+ unsigned int module_idx;
+ AST::Module *module; // can be NULL
+ AST::Path module_path;
+ ::std::vector< ::std::string > locals;
+ };
+ ::std::vector<Scope> m_scope_stack;
+ ::std::vector< TypeRef > m_self_type;
friend class CResolvePaths_NodeVisitor;
@@ -64,6 +70,7 @@ public: virtual void handle_pattern(AST::Pattern& pat, const TypeRef& type_hint) override;
virtual void handle_module(AST::Path path, AST::Module& mod) override;
+ virtual void handle_function(AST::Path path, AST::Function& fcn) override;
virtual void start_scope() override;
virtual void local_type(::std::string name, TypeRef type) override {
@@ -75,12 +82,18 @@ public: m_locals.push_back( LocalItem(LocalItem::TYPE, ::std::move(name), ::std::move(type)) );
}
virtual void local_variable(bool _is_mut, ::std::string name, const TypeRef& _type) override {
- m_locals.push_back( LocalItem(LocalItem::VAR, ::std::move(name)) );
+ assert(m_scope_stack.size() > 0);
+ m_scope_stack.back().locals.push_back( ::std::move(name) );
}
virtual void end_scope() override;
::rust::option<const LocalItem&> lookup_local(LocalItem::Type type, const ::std::string& name) const;
+ bool find_local_item(AST::Path& path, bool allow_variables);
+ bool find_mod_item(AST::Path& path);
+ bool find_super_mod_item(AST::Path& path);
+ bool find_type_param(const ::std::string& name);
+
// TODO: Handle a block and obtain the local module (if any)
private:
void handle_path_int(AST::Path& path, CASTIterator::PathMode mode);
@@ -124,23 +137,35 @@ public: {
// Add a reference to it to the parent node (add_anon_module will do dedup)
- AST::Module& parent_mod = *( (m_res.m_module_stack.size() > 0) ? m_res.m_module_stack.back().second : m_res.m_module );
+ AST::Module* parent_mod_p = m_res.m_module;
+ for(const auto& e : m_res.m_scope_stack)
+ if(e.module != nullptr)
+ parent_mod_p = e.module;
+ AST::Module& parent_mod = *parent_mod_p;
auto idx = parent_mod.add_anon_module( node.m_inner_mod.get() );
- // And add to the list of modules to use in lookup
- m_res.m_module_stack.push_back( ::std::make_pair(idx, node.m_inner_mod.get()) );
-
- // Do use resolution on this module, then do
+ // Obtain the path
AST::Path local_path = m_res.m_module_path;
- for(unsigned int i = 0; i < m_res.m_module_stack.size(); i ++)
- local_path.nodes().push_back( AST::PathNode( FMT("#" << m_res.m_module_stack[i].first), {} ) );
+ for(const auto& e : m_res.m_scope_stack ) {
+ if( e.module != nullptr ) {
+ local_path.nodes().push_back( AST::PathNode( FMT("#" << e.module_idx), {} ) );
+ }
+ }
+ local_path.nodes().push_back( AST::PathNode(FMT("#" << idx), {}) );
+
+ // And add to the list of modules to use in lookup
+ m_res.m_scope_stack.push_back( {idx, node.m_inner_mod.get(), local_path, {}} );
- ResolvePaths_HandleModule_Use(m_res.m_crate, local_path, *node.m_inner_mod);
+ // Do use resolution on this module
+ // TODO: When is more advanced resolution done?
+ ResolvePaths_HandleModule_Use(m_res.m_crate, m_res.m_scope_stack.back().module_path, *node.m_inner_mod);
+ }
+ else {
+ m_res.m_scope_stack.push_back( {0, nullptr, AST::Path(), {}} );
}
AST::NodeVisitorDef::visit(node);
// Once done, pop the module
- if( node.m_inner_mod.get() )
- m_res.m_module_stack.pop_back();
+ m_res.m_scope_stack.pop_back();
}
void visit(AST::ExprNode_IfLet& node)
@@ -292,6 +317,7 @@ void CPathResolver::end_scope() // > Search module-level definitions
bool lookup_path_in_module(const AST::Crate& crate, const AST::Module& module, const AST::Path& mod_path, AST::Path& path)
{
+ 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(path[0].name(), (path.size() == 1), false);
switch(item.type())
@@ -315,7 +341,7 @@ bool lookup_path_in_module(const AST::Crate& crate, const AST::Module& module, c path.resolve( crate );
return true;
}
- break; }
+ return false; }
case AST::Module::ItemRef::ITEM_Module:
// Check name down?
// Add current module path
@@ -327,62 +353,38 @@ bool lookup_path_in_module(const AST::Crate& crate, const AST::Module& module, c path.resolve( crate );
return true;
}
- #if 0
- for( const auto& import : module.imports() )
- {
- const ::std::string& bind_name = import.name;
- const AST::Path& bind_path = import.data;
- if( bind_name == "" )
- {
- // Check the bind type of this path
- switch(bind_path.binding_type())
- {
- case AST::Path::UNBOUND:
- throw ParseError::BugCheck("Wildcard import path not bound");
- // - If it's a module, recurse
- case AST::Path::MODULE:
- throw ParseError::Todo("Handle lookup_path_in_module for wildcard imports - module");
- break;
- // - If it's an enum, search for this name and then pass to resolve
- case AST::Path::ENUM:
- throw ParseError::Todo("Handle lookup_path_in_module for wildcard imports - enum");
- break;
- // - otherwise, error
- default:
- DEBUG("ERROR: Import of invalid class : " << bind_path);
- throw ParseError::Generic("Wildcard import of non-module/enum");
- }
- }
- else if( bind_name == path[0].name() ) {
- path = AST::Path::add_tailing(bind_path, path);
- path.resolve( crate );
- return true;
- }
- }
- #endif
}
+
+/// Perform path resolution within a generic definition block
void CPathResolver::handle_params(AST::TypeParams& params)
{
+ // Parameters
DEBUG("params");
for( auto& param : params.ty_params() )
{
+ // - Resolve the default type
handle_type(param.get_default());
+ // - Register each param as a type name within this scope
local_type( param.name(), TypeRef(TypeRef::TagArg(), param.name(), params) );
}
DEBUG("Bounds");
for( auto& bound : params.bounds() )
{
+ // Resolve names within the test (i.e. the lefthand side)
handle_type(bound.test());
- // TODO: Will there be a case where within the test there's a Self that isn't the bound?
- local_type("Self", bound.test());
+ // Handle the trait bound
+ // - Clear "Self" to prevent it from being mangled
+ m_self_type.push_back( TypeRef() );
if( !bound.is_trait() )
DEBUG("namecheck lifetime bounds?");
else
handle_path(bound.bound(), CASTIterator::MODE_TYPE);
- m_locals.pop_back();
+ m_self_type.pop_back();
}
}
+
+/// Resolve names within a path
void CPathResolver::handle_path(AST::Path& path, CASTIterator::PathMode mode)
{
TRACE_FUNCTION_F("path = " << path << ", m_module_path = " << m_module_path);
@@ -402,8 +404,13 @@ void CPathResolver::handle_path(AST::Path& path, CASTIterator::PathMode mode) void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode)
{
// Convert to absolute
+ // - This means converting all partial forms (i.e. not UFCS, Variable, or Absolute)
switch( path.type() )
{
+ case AST::Path::INVALID:
+ return;
+ // --- Already absolute forms
+ // > Absolute: Resolve
case AST::Path::ABSOLUTE:
DEBUG("Absolute - binding");
INDENT();
@@ -417,110 +424,90 @@ void CPathResolver::handle_path_int(AST::Path& path, CASTIterator::PathMode mode }
UNINDENT();
break;
- case AST::Path::RELATIVE: {
- assert(path.size() > 0);
- DEBUG("Relative, local");
-
- // If there's a single node, and we're in expresion mode, look for a variable
- // Otherwise, search for a type
- bool is_trivial_path = (path.size() == 1 && path[0].args().size() == 0);
+ // > UFCS: Expand the types
+ case AST::Path::UFCS:
+ handle_path_ufcs(path, mode);
+ break;
+ // > Variable: (wait, how is this known already?)
+ // - 'self'
+ case AST::Path::VARIABLE:
+ break;
+
+ case AST::Path::RELATIVE:
+ // 1. function scopes (variables and local items)
+ // > Return values: name or path
+ {
+ if( this->find_local_item(path, /*allow_variables=*/path.is_trivial()) ) {
+ break ;
+ }
+ else {
+ // No match, fall through
+ }
+ }
- LocalItem::Type search_type = (is_trivial_path && mode == MODE_EXPR ? LocalItem::VAR : LocalItem::TYPE);
- auto local_o = lookup_local( search_type, path[0].name() );
- if( local_o.is_some() )
+ // 2. Type parameters
+ // - Should probably check if this is expression mode, bare types are invalid there
+ // NOTES:
+ // - If the path is bare (i.e. there are no more nodes), then ensure that the mode is TYPE
+ // - If there are more nodes, replace with a UFCS block
{
- auto local = local_o.unwrap();
- DEBUG("Local hit: " << path[0].name() << " = " << local);
-
- switch(mode)
+ auto tp = this->find_type_param(path[0].name());
+ if( tp != false /*nullptr*/ )
{
- // Local variable?
- // - TODO: What would happen if MODE_EXPR but path isn't a single ident?
- case MODE_EXPR:
- if( local.type == LocalItem::VAR )
- {
- if( !is_trivial_path )
- throw ParseError::Todo("TODO: MODE_EXPR, but not a single identifer, what do?");
- DEBUG("Local variable " << path[0].name());
- path = AST::Path(AST::Path::TagLocal(), path[0].name());
- return ;
+ if(path.size() > 1) {
+ // Repalce with UFCS
+ auto newpath = AST::Path(AST::Path::TagUfcs(), TypeRef(TypeRef::TagArg(), path[0].name()), TypeRef());
+ newpath.add_tailing(path);
+ path = newpath;
}
- if( is_trivial_path )
- throw ParseError::Generic("Type used in expression context?");
- // Type parameter
- case MODE_TYPE:
- {
- // Convert to a UFCS path
- DEBUG("Local type");
- // - "<Type as _>::nodes"
- auto np = AST::Path(AST::Path::TagUfcs(), local.tr, TypeRef());
- np.add_tailing(path);
- path = ::std::move(np);
- DEBUG("path = " << path);
- handle_path_ufcs(path, mode);
+ else {
+ // Replace with VARIABLE (not strictly speaking true... but close enough)
+ // - TODO: Not being trivial is an error, not a bug
+ assert( path.is_trivial() );
+ path = AST::Path(AST::Path::TagVariable(), path[0].name());
}
- return ;
- // Binding is valid
- case MODE_BIND:
- //break ;
- throw ParseError::Todo("TODO: MODE_BIND, but local hit, what do?");
+ break;
+ throw ParseError::Todo("Handle type param in RELATIVE");
}
-
- // TODO: What about sub-types and methods on type params?
- // - Invalid afaik, instead Trait::method() is used
}
-
- if( path.nodes()[0].name() == "super" )
- {
- // Unwrap a single named node from the module path, and search that path
- // - Requires resolving that path to a module to pass to lookup_path_in_module
- AST::Path local_path = m_module_path;
- local_path.nodes().pop_back();
- local_path.resolve(m_crate);
- DEBUG("'super' path is relative to " << local_path);
- path.nodes().erase( path.nodes().begin() ); // delete the 'super' node
- const AST::Module& mod = local_path.binding().bound_module();
- if( lookup_path_in_module(m_crate, mod, local_path, path) )
- return ;
- // this should always be an error, as 'super' paths are never MaybeBind
- }
- else
+ // 3. current module
{
- // Search backwards up the stack of anon modules
- if( m_module_stack.size() )
- {
- AST::Path local_path = m_module_path;
- for(unsigned int i = 0; i < m_module_stack.size(); i ++)
- local_path.nodes().push_back( AST::PathNode( FMT("#" << m_module_stack[i].first), {} ) );
-
- for(unsigned int i = m_module_stack.size(); i--; )
- {
- if( lookup_path_in_module(m_crate, *m_module_stack[i].second, local_path, path) ) {
- // Success!
- return ;
- }
- local_path.nodes().pop_back();
- }
+ if( this->find_mod_item(path) ) {
+ break;
}
- // Search current module, if found return with no error
- if( lookup_path_in_module(m_crate, *m_module, m_module_path, path) )
- {
- return;
+ else {
}
}
+ // *. No match? I give up
+ DEBUG("no matches found for path = " << path);
+ if( mode != MODE_BIND )
+ throw ParseError::Generic("CPathResolver::handle_path - Name resolution failed");
+ return ;
+
+ // Module relative
+ case AST::Path::SELF:{
+ if( this->find_mod_item(path) ) {
+ break;
+ }
+ else {
+ }
+ DEBUG("no matches found for path = " << path);
+ if( mode != MODE_BIND )
+ throw ParseError::Generic("CPathResolver::handle_path - Name resolution failed");
+ break; }
+ // Parent module relative
+ case AST::Path::SUPER:{
+ if( this->find_super_mod_item(path) ) {
+ break;
+ }
+ else {
+ }
DEBUG("no matches found for path = " << path);
- assert( path.is_relative() );
if( mode != MODE_BIND )
throw ParseError::Generic("CPathResolver::handle_path - Name resolution failed");
break; }
- case AST::Path::LOCAL:
- // Don't touch locals, they're already known
- break;
- case AST::Path::UFCS:
- handle_path_ufcs(path, mode);
- break;
}
}
void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mode)
@@ -556,6 +543,58 @@ void CPathResolver::handle_path_ufcs(AST::Path& path, CASTIterator::PathMode mod path.resolve(m_crate);
}
+bool CPathResolver::find_local_item(AST::Path& path, bool allow_variables) {
+ TRACE_FUNCTION_F("path="<<path<<", allow_variables="<<allow_variables);
+ // Search current scopes for a name
+ // - This should search both the expression stack
+ // - and the scope's module (if any)
+ for(auto it = m_scope_stack.rbegin(); it != m_scope_stack.rend(); ++it)
+ {
+ const auto& s = *it;
+ if( allow_variables )
+ {
+ for( auto it2 = s.locals.rbegin(); it2 != s.locals.rend(); ++it2 )
+ {
+ if( *it2 == path[0].name() ) {
+ path = AST::Path(AST::Path::TagVariable(), path[0].name());
+ return true;
+ }
+ }
+ }
+ if( s.module != nullptr )
+ {
+ DEBUG("- Looking in sub-module '" << s.module_path << "'");
+ if( lookup_path_in_module(m_crate, *s.module, s.module_path, path) )
+ return true;
+ }
+ }
+ return false;
+}
+bool CPathResolver::find_mod_item(AST::Path& path) {
+ if( m_module->name() == "" )
+ throw ParseError::Todo("Correct handling of 'self' in anon modules");
+
+ return lookup_path_in_module(m_crate, *m_module, m_module_path, path);
+}
+bool CPathResolver::find_super_mod_item(AST::Path& path) {
+ if( m_module->name() == "" )
+ throw ParseError::Todo("Correct handling of 'super' in anon modules");
+ // 1.
+ // TODO: lookup_path_in_module
+ throw ParseError::Todo("Handle 'super'");
+}
+bool CPathResolver::find_type_param(const ::std::string& name) {
+ for( auto it = m_locals.end(); it -- != m_locals.begin(); )
+ {
+ if( it->type == LocalItem::TYPE ) {
+ if( it->name == name ) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
void CPathResolver::handle_type(TypeRef& type)
{
TRACE_FUNCTION_F("type = " << type);
@@ -639,8 +678,7 @@ void CPathResolver::handle_pattern(AST::Pattern& pat, const TypeRef& type_hint) ::std::string name = pat.binding();
// Locate a _constant_ within the current namespace which matches this name
// - Variables don't count
- AST::Path newpath;
- newpath.append( AST::PathNode(name, {}) );
+ AST::Path newpath = AST::Path(name);
handle_path(newpath, CASTIterator::MODE_BIND);
if( newpath.is_relative() )
{
@@ -668,6 +706,12 @@ void CPathResolver::handle_module(AST::Path path, AST::Module& mod) m_module_path = path;
CASTIterator::handle_module(path, mod);
}
+void CPathResolver::handle_function(AST::Path path, AST::Function& fcn)
+{
+ m_scope_stack.push_back( {0, nullptr, AST::Path(), {}} );
+ CASTIterator::handle_function(::std::move(path), fcn);
+ m_scope_stack.pop_back();
+}
void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& modpath, AST::Module& mod)
{
@@ -675,23 +719,35 @@ void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& mod ::std::vector<AST::Path> new_imports;
for( auto& imp : mod.imports() )
{
- if( !imp.data.is_absolute() )
+ AST::Path& p = imp.data;
+ DEBUG("p = " << p);
+ switch( p.type() )
{
- if( imp.data[0].name() == "super" ) {
- if( modpath.size() < 1 )
- throw ParseError::Generic("Encountered 'super' at crate root");
- auto newpath = modpath;
- newpath.nodes().pop_back();
- newpath.add_tailing(imp.data);
- DEBUG("Absolutised path " << imp.data << " into " << newpath);
- imp.data = ::std::move(newpath);
- }
- 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);
- }
+ case AST::Path::ABSOLUTE:
+ // - No action
+ break;
+ // 'super' - Add parent path
+ // - TODO: Handle nested modules correctly.
+ case AST::Path::SUPER: {
+ if( modpath.size() < 1 )
+ throw ParseError::Generic("Encountered 'super' at crate root");
+ auto newpath = modpath;
+ newpath.nodes().pop_back();
+ newpath += p;
+ DEBUG("Absolutised path " << p << " into " << newpath);
+ p = ::std::move(newpath);
+ break; }
+ // 'self' - Add parent path
+ // - TODO: Handle nested modules correctly.
+ case AST::Path::SELF: {
+ auto newpath = modpath + p;
+ // TODO: Undo anon modules until item is found
+ DEBUG("Absolutised path " << p << " into " << newpath);
+ p = ::std::move(newpath);
+ break; }
+ // Any other class is an error
+ default:
+ throw ParseError::Generic( FMT("Invalid path type encounted in 'use' : " << p) );
}
// Run resolution on import
diff --git a/src/main.cpp b/src/main.cpp index 339fdb1e..8f39b78e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -76,7 +76,7 @@ int main(int argc, char *argv[]) // Typecheck / type propagate module (type annotations of all values)
// - Check all generic conditions (ensure referenced trait is valid)
// > Also mark parameter with applicable traits
- #if 1
+ #if 0
g_cur_phase = "TypecheckBounds";
Typecheck_GenericBounds(crate);
// - Check all generic parameters match required conditions
diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index 12aa3d3a..a12eb526 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -1001,7 +1001,7 @@ ExprNodeP Parse_ExprVal(TokenStream& lex) case TOK_RWORD_SELF:
{
if( LOOK_AHEAD(lex) != TOK_DOUBLE_COLON ) {
- return NEWNODE( AST::ExprNode_NamedValue, AST::Path(AST::Path::TagLocal(), "self") );
+ return NEWNODE( AST::ExprNode_NamedValue, AST::Path(AST::Path::TagVariable(), "self") );
}
else
{
diff --git a/src/parse/paths.cpp b/src/parse/paths.cpp index a8c6802d..e3b290d0 100644 --- a/src/parse/paths.cpp +++ b/src/parse/paths.cpp @@ -55,7 +55,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi } } else - return Parse_PathFrom(lex, AST::Path(), generic_mode); + return Parse_PathFrom(lex, AST::Path(AST::Path::TagRelative()), generic_mode); } AST::Path Parse_PathFrom(TokenStream& lex, AST::Path path, eParsePathGenericMode generic_mode) @@ -145,6 +145,9 @@ AST::Path Parse_PathFrom(TokenStream& lex, AST::Path path, eParsePathGenericMode path.append( AST::PathNode(component, params) ); } lex.putback(tok); + if( path.is_trivial() ) { + path = AST::Path(path[0].name()); + } DEBUG("path = " << path); return path; } diff --git a/src/parse/root.cpp b/src/parse/root.cpp index eeeafb0e..2ae39d91 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -894,7 +894,7 @@ void Parse_Use(TokenStream& lex, ::std::function<void(AST::Path, ::std::string)> switch( GET_TOK(tok, lex) )
{
case TOK_RWORD_SELF:
- path = AST::Path( ); // relative path
+ path = AST::Path( AST::Path::TagSelf() ); // relative path
break;
case TOK_RWORD_SUPER:
path = AST::Path( AST::Path::TagSuper() );
@@ -941,21 +941,21 @@ void Parse_Use(TokenStream& lex, ::std::function<void(AST::Path, ::std::string)> }
} while( GET_TOK(tok, lex) == TOK_COMMA );
CHECK_TOK(tok, TOK_BRACE_CLOSE);
- return;
+ break ;
case TOK_STAR:
Parse_Use_Wildcard(path, fcn);
- // early return - can't have anything else after
- return;
+ break ;
default:
throw ParseError::Unexpected(lex, tok);
}
- GET_TOK(tok, lex);
- break;
+ // early return - This branch is either the end of the use statement, or a syntax error
+ return ;
}
}
::std::string name;
- // TODO: This should only be allowed if the last token was an ident
+ // This should only be allowed if the last token was an ident
+ // - Above checks ensure this
if( tok.type() == TOK_RWORD_AS )
{
GET_CHECK_TOK(tok, lex, TOK_IDENT);
@@ -964,7 +964,7 @@ void Parse_Use(TokenStream& lex, ::std::function<void(AST::Path, ::std::string)> else
{
lex.putback(tok);
- name = path[path.size()-1].name();
+ name = path.nodes().back().name();
}
fcn(path, name);
@@ -1289,7 +1289,10 @@ void Parse_ModRoot_Items(TokenStream& lex, AST::Crate& crate, AST::Module& mod, {
case TOK_RWORD_USE:
- Parse_Use(lex, [&mod,is_public](AST::Path p, std::string s) { mod.add_alias(is_public, p, s); });
+ Parse_Use(lex, [&mod,is_public,&path](AST::Path p, std::string s) {
+ DEBUG(path << " - use " << p << " as '" << s << "'");
+ mod.add_alias(is_public, p, s);
+ });
GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
break;
|