summaryrefslogtreecommitdiff
path: root/src/resolve/use.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/resolve/use.cpp')
-rw-r--r--src/resolve/use.cpp223
1 files changed, 223 insertions, 0 deletions
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());
+}
+