summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--src/ast/path.cpp4
-rw-r--r--src/ast/path.hpp12
-rw-r--r--src/expand/mod.cpp2
-rw-r--r--src/hir/from_ast.cpp2
-rw-r--r--src/include/main_bindings.hpp1
-rw-r--r--src/main.cpp5
-rw-r--r--src/resolve/use.cpp223
8 files changed, 246 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index 57f80599..ad44ec68 100644
--- a/Makefile
+++ b/Makefile
@@ -34,6 +34,7 @@ OBJ += expand/format_args.o
OBJ += expand/concat.o expand/stringify.o expand/file_line.o
OBJ += expand/derive.o expand/lang_item.o
OBJ += expand/std_prelude.o
+OBJ += resolve/use.o
OBJ += hir/from_ast.o
OBJ += dump_as_rust.o
OBJ += convert/ast_iterate.o
diff --git a/src/ast/path.cpp b/src/ast/path.cpp
index 032c57b4..60dee881 100644
--- a/src/ast/path.cpp
+++ b/src/ast/path.cpp
@@ -31,6 +31,10 @@ namespace AST {
)
return os;
}
+PathBinding PathBinding::clone() const
+{
+ assert(!"TODO: PathBinding::clone()");
+}
// --- AST::PathNode
PathNode::PathNode(::std::string name, ::std::vector<TypeRef> args):
diff --git a/src/ast/path.hpp b/src/ast/path.hpp
index d2f6302e..bf0ff59a 100644
--- a/src/ast/path.hpp
+++ b/src/ast/path.hpp
@@ -28,7 +28,7 @@ class Trait;
class Static;
class Function;
-TAGGED_UNION(PathBinding, Unbound,
+TAGGED_UNION_EX(PathBinding, (), Unbound, (
(Unbound, struct {
}),
(Module, struct {
@@ -72,6 +72,12 @@ TAGGED_UNION(PathBinding, Unbound,
(Variable, struct {
unsigned int slot;
})
+ ),
+ (), (),
+ (
+ public:
+ PathBinding clone() const;
+ )
);
extern ::std::ostream& operator<<(::std::ostream& os, const PathBinding& x);
@@ -343,6 +349,10 @@ public:
void bind_type_alias(const TypeAlias& ent, const ::std::vector<TypeRef>& args={}) {
m_binding = PathBinding::make_TypeAlias({&ent});
}
+
+ void bind(::AST::PathBinding pb) {
+ m_binding = mv$(pb);
+ }
};
} // namespace AST
diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp
index 1fdf56c1..d62a20db 100644
--- a/src/expand/mod.cpp
+++ b/src/expand/mod.cpp
@@ -482,7 +482,7 @@ void Expand_Mod(bool is_early, ::AST::Crate& crate, LList<const AST::Module*> mo
DEBUG("Items");
for( auto& i : mod.items() )
{
- DEBUG("- " << i.name << " :: " << i.data.attrs);
+ DEBUG("- " << i.name << " (" << ::AST::Item::tag_to_str(i.data.tag()) << ") :: " << i.data.attrs);
::AST::Path path = modpath + i.name;
auto attrs = mv$(i.data.attrs);
diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp
index 7bf0fa74..4da703f9 100644
--- a/src/hir/from_ast.cpp
+++ b/src/hir/from_ast.cpp
@@ -8,7 +8,7 @@
/// \brief Converts the AST into HIR format
///
/// - Removes all possibility for unexpanded macros
-/// - Performs name resolution and partial UFCS conversion? (TODO: This should be done on the AST, as it requires two passes with state)
+/// - Performs name resolution and partial UFCS conversion?
/// - Performs desugaring of for/if-let/while-let/...
::HIR::Crate LowerHIR_FromAST(::AST::Crate crate)
{
diff --git a/src/include/main_bindings.hpp b/src/include/main_bindings.hpp
index 016b2f27..afc6dea5 100644
--- a/src/include/main_bindings.hpp
+++ b/src/include/main_bindings.hpp
@@ -19,6 +19,7 @@ extern void Expand(::AST::Crate& crate);
/// Process #[] decorators
extern void Process_Decorators(AST::Crate& crate);
+extern void Resolve_Use(::AST::Crate& crate);
/// Resolve all in-text paths to absolute variants
extern void ResolvePaths(AST::Crate& crate);
diff --git a/src/main.cpp b/src/main.cpp
index a2a6f26f..38b200d0 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -22,7 +22,7 @@ int g_debug_indent_level = 0;
bool debug_enabled()
{
- return true;
+ return g_cur_phase != "Parse";
}
::std::ostream& debug_output(int indent, const char* function)
{
@@ -116,6 +116,9 @@ int main(int argc, char *argv[])
// - This does name checking on types and free functions.
// - Resolves all identifiers/paths to references
CompilePhaseV("Resolve", [&]() {
+ Resolve_Use(crate);
+ //Resolve_Absolutise(crate);
+ //Resolve_UfcsPaths(crate);
ResolvePaths(crate);
});
diff --git a/src/resolve/use.cpp b/src/resolve/use.cpp
new file mode 100644
index 00000000..254a2374
--- /dev/null
+++ b/src/resolve/use.cpp
@@ -0,0 +1,223 @@
+/*
+ * Absolutise and check all 'use' statements
+ */
+#include <main_bindings.hpp>
+#include <ast/crate.hpp>
+#include <ast/ast.hpp>
+
+void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path path);
+::AST::Path Resolve_Use_AbsolutisePath(const ::AST::Path& base_path, ::AST::Path path);
+::AST::PathBinding Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path);
+
+void Resolve_Use(::AST::Crate& crate)
+{
+ Resolve_Use_Mod(crate, crate.m_root_module, ::AST::Path("", {}));
+}
+
+::AST::Path Resolve_Use_AbsolutisePath(const Span& span, const ::AST::Path& base_path, ::AST::Path path)
+{
+ TU_MATCH(::AST::Path::Class, (path.m_class), (e),
+ (Invalid,
+ // Should never happen
+ BUG(span, "Invalid path class encountered");
+ ),
+ (Local,
+ // Wait, how is this already known?
+ BUG(span, "Local path class in use statement");
+ ),
+ (UFCS,
+ // Wait, how is this already known?
+ BUG(span, "UFCS path class in use statement");
+ ),
+ (Relative,
+ return base_path + path;
+ ),
+ (Self,
+ return base_path + path;
+ ),
+ (Super,
+ assert(e.count >= 1);
+ AST::Path np(base_path.crate(), {});
+ if( e.count > base_path.nodes().size() ) {
+ ERROR(span, E0000, "Too many `super` components");
+ }
+ for( unsigned int i = 0; i < base_path.nodes().size() - e.count; i ++ )
+ np.nodes().push_back( base_path.nodes()[i] );
+ np += path;
+ return np;
+ ),
+ (Absolute,
+ // Leave as is
+ return path;
+ )
+ )
+ throw "BUG: Reached end of Resolve_Use_AbsolutisePath";
+}
+
+void Resolve_Use_Mod(const ::AST::Crate& crate, ::AST::Module& mod, ::AST::Path path)
+{
+ TRACE_FUNCTION_F("path = " << path << ", mod.path() = " << mod.path());
+ for(auto& use_stmt : mod.imports())
+ {
+ const Span span;
+ use_stmt.data = Resolve_Use_AbsolutisePath(span, path, mv$(use_stmt.data));
+ if( !use_stmt.data.m_class.is_Absolute() )
+ BUG(span, "Use path is not absolute after absolutisation");
+
+ // TODO: Is this a valid assertion?
+ if( use_stmt.data.crate() != "" )
+ BUG(span, "Use path crate was set before resolve");
+
+ use_stmt.data.bind( Resolve_Use_GetBinding(span, crate, use_stmt.data) );
+
+ // - If doing a glob, ensure the item type is valid
+ if( use_stmt.name == "" )
+ {
+ TU_MATCH_DEF(::AST::PathBinding, (use_stmt.data.binding()), (e),
+ (
+ ERROR(span, E0000, "Wildcard import of invalid item type");
+ ),
+ (Enum,
+ ),
+ (Module,
+ )
+ )
+ }
+ }
+
+ for(auto& i : mod.items())
+ {
+ if( i.data.is_Module() )
+ {
+ Resolve_Use_Mod(crate, i.data.as_Module(), path + i.name);
+ }
+ }
+}
+
+::AST::PathBinding Resolve_Use_GetBinding_Mod(const Span& span, const ::AST::Crate& crate, const ::AST::Module& mod, const ::std::string& des_item_name)
+{
+ for( const auto& item : mod.items() )
+ {
+ if( item.data.is_None() )
+ continue ;
+
+ if( item.name == des_item_name ) {
+ TU_MATCH(::AST::Item, (item.data), (e),
+ (None,
+ // IMPOSSIBLe - Handled above
+ ),
+ (Crate,
+ //return ::AST::PathBinding::make_Crate({&e});
+ TODO(span, "Handle importing from a crate");
+ ),
+ (Type,
+ return ::AST::PathBinding::make_TypeAlias({&e});
+ ),
+ (Trait,
+ return ::AST::PathBinding::make_Trait({&e});
+ ),
+
+ (Function,
+ return ::AST::PathBinding::make_Function({&e});
+ ),
+ (Static,
+ return ::AST::PathBinding::make_Static({&e});
+ ),
+ (Struct,
+ return ::AST::PathBinding::make_Struct({&e});
+ ),
+ (Enum,
+ return ::AST::PathBinding::make_Enum({&e});
+ ),
+ (Module,
+ return ::AST::PathBinding::make_Module({&e});
+ )
+ )
+ break ;
+ }
+ }
+
+ // Imports
+ for( const auto& imp : mod.imports() )
+ {
+ if( imp.name == des_item_name ) {
+ DEBUG("- Named import " << imp.name << " = " << imp.data);
+ if( imp.data.binding().is_Unbound() ) {
+ DEBUG(" > Needs resolve");
+ const Span sp2;
+ return Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp.data));
+ }
+ else {
+ return imp.data.binding().clone();
+ }
+ }
+ if( imp.is_pub && imp.name == "" ) {
+ const Span sp2;
+ // INEFFICIENT! Resolves and throws away the result (because we can't/shouldn't mutate here)
+ ::AST::PathBinding binding_;
+ const auto* binding = &imp.data.binding();
+ if( binding->is_Unbound() ) {
+ DEBUG("Temp resolving wildcard " << imp.data);
+ binding_ = Resolve_Use_GetBinding(sp2, crate, Resolve_Use_AbsolutisePath(sp2, mod.path(), imp.data));
+ binding = &binding_;
+ }
+
+ TU_MATCH_DEF(::AST::PathBinding, ((*binding)), (e),
+ (
+ BUG(sp2, "Wildcard import expanded to an invalid item class");
+ ),
+ (Module,
+ TODO(span, "Look up wildcard in module");
+ ),
+ (Enum,
+ TODO(span, "Look up wildcard in enum");
+ )
+ )
+ }
+ }
+
+ ERROR(span, E0000, "Could not find node '" << des_item_name << "' in module " << mod.path());
+}
+
+::AST::PathBinding Resolve_Use_GetBinding(const Span& span, const ::AST::Crate& crate, const ::AST::Path& path)
+{
+ const AST::Module* mod = &crate.m_root_module;
+ const auto& nodes = path.nodes();
+ for( unsigned int i = 0; i < nodes.size()-1; i ++ )
+ {
+ auto b = Resolve_Use_GetBinding_Mod(span, crate, *mod, nodes[i].name());
+ TU_MATCH_DEF(::AST::PathBinding, (b), (e),
+ (
+ ERROR(span, E0000, "Unexpected item type in import");
+ ),
+ (Enum,
+ const auto& enum_ = *e.enum_;
+ i += 1;
+ if( i != nodes.size() - 1 ) {
+ ERROR(span, E0000, "Encountered enum at unexpected location in import");
+ }
+
+ const auto& node2 = nodes[i];
+ int variant_index = -1;
+ for( unsigned int j = 0; j < enum_.variants().size(); j ++ )
+ {
+ if( enum_.variants()[j].m_name == node2.name() ) {
+ variant_index = j;
+ break ;
+ }
+ }
+ if( variant_index < 0 ) {
+ ERROR(span, E0000, "Unknown enum variant '" << node2.name() << "'");
+ }
+
+ return ::AST::PathBinding::make_EnumVar({&enum_, static_cast<unsigned int>(variant_index)});
+ ),
+ (Module,
+ mod = e.module_;
+ )
+ )
+ }
+
+ return Resolve_Use_GetBinding_Mod(span, crate, *mod, nodes.back().name());
+}
+