summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2015-06-04 14:41:34 +0800
committerJohn Hodge <tpg@mutabah.net>2015-06-04 14:41:34 +0800
commitf15fcf3c440e3c9c40fa606b0904fb85a8510464 (patch)
treea477b63bf9d9141b170292aedb6df9cf8eeb2580
parent029bf073a1ec77a06d6c64ab7166c74f13486926 (diff)
downloadmrust-f15fcf3c440e3c9c40fa606b0904fb85a8510464.tar.gz
Rework path handling and resolve to better handle Self
-rw-r--r--src/ast/ast.cpp4
-rw-r--r--src/ast/path.cpp107
-rw-r--r--src/ast/path.hpp95
-rw-r--r--src/convert/ast_iterate.cpp20
-rw-r--r--src/convert/resolve.cpp366
-rw-r--r--src/main.cpp2
-rw-r--r--src/parse/expr.cpp2
-rw-r--r--src/parse/paths.cpp5
-rw-r--r--src/parse/root.cpp21
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;