From 5c61e0955197adb58fdf7911ccf7e05c13f2263d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 22 Mar 2015 18:37:20 +0800 Subject: Clean up local path resolution, add internal 'str' type --- src/ast/ast.hpp | 17 ++++ src/ast/path.cpp | 25 +++++ src/ast/path.hpp | 4 + src/ast/provided_module.cpp | 14 +++ src/convert/resolve.cpp | 228 ++++++++++++++++++++++++-------------------- src/main.cpp | 2 + src/parse/types.cpp | 5 + src/types.hpp | 5 + 8 files changed, 198 insertions(+), 102 deletions(-) create mode 100644 src/ast/provided_module.cpp (limited to 'src') diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 6ef0d85a..ece9704f 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -7,6 +7,7 @@ #include "../coretypes.hpp" #include #include +#include #include "../parse/tokentree.hpp" #include "../types.hpp" @@ -520,6 +521,7 @@ class Module: itemlist_use_t m_imports; ::std::vector > m_type_aliases; itemlist_ext_t m_extern_crates; + ::std::vector m_anon_modules; // TODO: Should this be serialisable? itemlist_macros_t m_macros; macro_imports_t m_macro_imports; // module => macro @@ -583,6 +585,13 @@ public: void add_attr(MetaItem item) { m_attrs.push_back(item); } + unsigned int add_anon_module(Module* mod_ptr) { + auto it = ::std::find(m_anon_modules.begin(), m_anon_modules.end(), mod_ptr); + if( it != m_anon_modules.end() ) + return it - m_anon_modules.begin(); + m_anon_modules.push_back(mod_ptr); + return m_anon_modules.size()-1; + } void iterate_functions(fcn_visitor_t* visitor, const Crate& crate); @@ -599,6 +608,7 @@ public: ItemList& traits() { return m_traits; } itemlist_enum_t& enums () { return m_enums; } itemlist_struct_t& structs() { return m_structs; } + ::std::vector& anon_mods() { return m_anon_modules; } const ::std::vector& attrs() const { return m_attrs; } const itemlist_fcn_t& functions() const { return m_functions; } @@ -611,10 +621,13 @@ public: const ItemList& traits() const { return m_traits; } const itemlist_enum_t& enums () const { return m_enums; } const itemlist_struct_t& structs() const { return m_structs; } + const ::std::vector& anon_mods() const { return m_anon_modules; } + const itemlist_macros_t& macros() const { return m_macros; } const macro_imports_t& macro_imports() const { return m_macro_imports; } const ::std::vector > macro_imports_res() const { return m_macro_import_res; } + SERIALISABLE_PROTOTYPES(); private: void resolve_macro_import(const Crate& crate, const ::std::string& modname, const ::std::string& macro_name); @@ -694,4 +707,8 @@ public: } +extern AST::Module g_compiler_module; +extern void AST_InitProvidedModule(); + + #endif // AST_HPP_INCLUDED diff --git a/src/ast/path.cpp b/src/ast/path.cpp index fae2642e..8e73c095 100644 --- a/src/ast/path.cpp +++ b/src/ast/path.cpp @@ -79,6 +79,26 @@ void Path::resolve(const Crate& root_crate) const bool is_sec_last = (i+2 == m_nodes.size()); const PathNode& node = m_nodes[i]; + 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 ; + } + // Sub-modules { auto& sms = mod->submods(); @@ -389,6 +409,11 @@ void Path::print_pretty(::std::ostream& os) const ::std::ostream& operator<<(::std::ostream& os, const Path& path) { + if( path.m_nodes.size() == 0 ) + { + os << "/* null path */"; + return os; + } #if PRETTY_PATH_PRINT switch(path.m_class) { diff --git a/src/ast/path.hpp b/src/ast/path.hpp index 4701b03a..fdf788a5 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -146,6 +146,10 @@ public: DEBUG("crate set to " << m_crate); } } + void set_local() { + assert(m_class == RELATIVE); + m_class = LOCAL; + } /// Add the all nodes except the first from 'b' to 'a' and return static Path add_tailing(const Path& a, const Path& b) { diff --git a/src/ast/provided_module.cpp b/src/ast/provided_module.cpp new file mode 100644 index 00000000..ea323172 --- /dev/null +++ b/src/ast/provided_module.cpp @@ -0,0 +1,14 @@ +/* + */ +#include "ast.hpp" + +AST::Module g_compiler_module; + +void AST_InitProvidedModule() +{ + // "struct str([u8])" + g_compiler_module.add_struct(true, "str", AST::TypeParams(), ::std::vector { + AST::StructItem("", TypeRef(TypeRef::TagUnsizedArray(), TypeRef(CORETYPE_U8)), false), + }); +} + diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp index e519d485..f28e9d45 100644 --- a/src/convert/resolve.cpp +++ b/src/convert/resolve.cpp @@ -35,11 +35,11 @@ class CPathResolver: {} }; const AST::Crate& m_crate; - const AST::Module* m_module; + AST::Module* m_module; AST::Path m_module_path; ::std::vector< LocalItem > m_locals; // TODO: Maintain a stack of variable scopes - ::std::vector m_module_stack; + ::std::vector< ::std::pair > m_module_stack; friend class CResolvePaths_NodeVisitor; @@ -62,10 +62,6 @@ public: } virtual void end_scope() override; - void add_local_use(::std::string name, AST::Path path) { - throw ParseError::Todo("CPathResolver::add_local_use - Determine type of path (type or value)"); - m_locals.push_back( LocalItem(LocalItem::VAR, ::std::move(name), path) ); - } ::rust::option lookup_local(LocalItem::Type type, const ::std::string& name) const; // TODO: Handle a block and obtain the local module (if any) @@ -103,9 +99,17 @@ public: } void visit(AST::ExprNode_Block& node) { - if( node.m_inner_mod.get() ) - m_res.m_module_stack.push_back( node.m_inner_mod.get() ); + // If there's an inner module on this node + if( node.m_inner_mod.get() ) { + // 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 ); + auto idx = parent_mod.add_anon_module( node.m_inner_mod.get() ); + // Increment the module path to include it? (No - Instead handle that when tracing the stack) + // 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()) ); + } AST::NodeVisitorDef::visit(node); + // Once done, pop the module if( node.m_inner_mod.get() ) m_res.m_module_stack.pop_back(); } @@ -158,6 +162,7 @@ void CPathResolver::end_scope() } m_locals.clear(); } +// Returns the bound path for the local item ::rust::option CPathResolver::lookup_local(LocalItem::Type type, const ::std::string& name) const { for( auto it = m_locals.end(); it -- != m_locals.begin(); ) @@ -169,6 +174,90 @@ void CPathResolver::end_scope() return ::rust::option(); } +// Search relative to current module +// > Search local use definitions (function-level) +// - TODO: Local use statements (scoped) +// > 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) +{ + for( const auto& item_mod : module.submods() ) + { + if( item_mod.first.name() == path[0].name() ) { + // Check name down? + // Add current module path + path = mod_path + path; + path.resolve( crate ); + return true; + } + } + for( const auto& import : module.imports() ) + { + const ::std::string& bind_name = import.name; + const AST::Path& bind_path = import.data; + if( bind_name == "" ) { + throw ParseError::Todo("Handle lookup_path_in_module for wildcard imports"); + } + else if( bind_name == path[0].name() ) { + path = AST::Path::add_tailing(bind_path, path); + path.resolve( crate ); + return true; + } + } + + // Types + for( const auto& item : module.structs() ) + { + if( item.name == path[0].name() ) { + path = mod_path + path; + path.resolve( crate ); + return true; + } + } + for( const auto& item : module.enums() ) + { + if( item.name == path[0].name() ) { + path = mod_path + path; + path.resolve( crate ); + return true; + } + } + for( const auto& item : module.traits() ) + { + if( item.name == path[0].name() ) { + path = mod_path + path; + path.resolve( crate ); + return true; + } + } + for( const auto& item : module.type_aliases() ) + { + if( item.name == path[0].name() ) { + path = mod_path + path; + path.resolve( crate ); + return true; + } + } + + // Values / Functions + for( const auto& item_fcn : module.functions() ) + { + if( item_fcn.name == path[0].name() ) { + path = mod_path + path; + path.resolve( crate ); + return true; + } + } + for( const auto& item : module.statics() ) + { + if( item.name == path[0].name() ) { + path = mod_path + path; + path.resolve( crate ); + return true; + } + } + + return false; +} void CPathResolver::handle_path(AST::Path& path, CASTIterator::PathMode mode) { DEBUG("path = " << path); @@ -200,7 +289,7 @@ void CPathResolver::handle_path(AST::Path& path, CASTIterator::PathMode mode) // 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; + bool is_trivial_path = (path.size() == 1 && path[0].args().size() == 0); LocalItem::Type search_type = (is_trivial_path && mode == MODE_EXPR ? LocalItem::VAR : LocalItem::TYPE); auto local = lookup_local( search_type, path[0].name() ); @@ -209,29 +298,23 @@ void CPathResolver::handle_path(AST::Path& path, CASTIterator::PathMode mode) auto rpath = local.unwrap(); DEBUG("Local hit: " << path[0].name() << " = " << rpath); - // Local import? - if( rpath.size() > 0 ) + switch(mode) { - path = AST::Path::add_tailing(rpath, path); - path.resolve( m_crate ); - return ; - } - // Local variable? // - TODO: What would happen if MODE_EXPR but path isn't a single ident? - if( mode == MODE_EXPR && is_trivial_path ) - { - DEBUG("Local variable " << path[0].name()); - path = AST::Path(AST::Path::TagLocal(), path[0].name()); - return ; - } - - // Type parameter, return verbatim? - // - TODO: Are extra params/entries valid here? - if( mode == MODE_TYPE ) - { - DEBUG("Local type " << path[0].name()); - throw ParseError::BugCheck("Local types should be handled in handle_type"); + case MODE_EXPR: + if( is_trivial_path ) + { + DEBUG("Local variable " << path[0].name()); + path = AST::Path(AST::Path::TagLocal(), path[0].name()); + return ; + } + throw ParseError::Todo("TODO: MODE_EXPR, but not a single identifer, what do?"); + // Type parameter + case MODE_TYPE: + DEBUG("Local type " << path); + // - Switch the path to be a "LOCAL" + path.set_local(); return ; } @@ -239,83 +322,24 @@ void CPathResolver::handle_path(AST::Path& path, CASTIterator::PathMode mode) // - Invalid afaik, instead Trait::method() is used } - // Search relative to current module - // > Search local use definitions (function-level) - // - TODO: Local use statements (scoped) - // > Search module-level definitions - for( const auto& item_mod : m_module->submods() ) - { - if( item_mod.first.name() == path[0].name() ) { - // Check name down? - // Add current module path - path = m_module_path + path; - path.resolve( m_crate ); - return ; - } - } - for( const auto& import : m_module->imports() ) - { - const ::std::string& bind_name = import.name; - const AST::Path& bind_path = import.data; - if( bind_name == "" ) { - } - else if( bind_name == path[0].name() ) { - path = AST::Path::add_tailing(bind_path, path); - path.resolve( m_crate ); - return ; - } - } - - // Types - for( const auto& item : m_module->structs() ) - { - if( item.name == path[0].name() ) { - path = m_module_path + path; - path.resolve( m_crate ); - return ; - } - } - for( const auto& item : m_module->enums() ) - { - if( item.name == path[0].name() ) { - path = m_module_path + path; - path.resolve( m_crate ); - return ; - } - } - for( const auto& item : m_module->traits() ) - { - if( item.name == path[0].name() ) { - path = m_module_path + path; - path.resolve( m_crate ); - return ; - } - } - for( const auto& item : m_module->type_aliases() ) - { - if( item.name == path[0].name() ) { - path = m_module_path + path; - path.resolve( m_crate ); - return ; - } - } - - // Values / Functions - for( const auto& item_fcn : m_module->functions() ) + if( m_module_stack.size() ) { - if( item_fcn.name == path[0].name() ) { - path = m_module_path + path; - path.resolve( m_crate ); - return ; + 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("#"<statics() ) + if( lookup_path_in_module(m_crate, *m_module, m_module_path, path) ) { - if( item.name == path[0].name() ) { - path = m_module_path + path; - path.resolve( m_crate ); - return ; - } + return; } DEBUG("no matches found for path = " << path); diff --git a/src/main.cpp b/src/main.cpp index 760f8566..f7748b14 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,6 +26,8 @@ bool debug_enabled() /// main! int main(int argc, char *argv[]) { + AST_InitProvidedModule(); + const char *infile = NULL; ::std::string outfile; const char *crate_path = "."; diff --git a/src/parse/types.cpp b/src/parse/types.cpp index 57c1bad8..bbbdd4f8 100644 --- a/src/parse/types.cpp +++ b/src/parse/types.cpp @@ -87,6 +87,11 @@ TypeRef Parse_Type(TokenStream& lex) if( tok.str() == CORETYPES[i].name ) return TypeRef(TypeRef::TagPrimitive(), CORETYPES[i].type); } + if( tok.str() == "str" ) + { + // TODO: Create an internal newtype for 'str' + return TypeRef(TypeRef::TagPath(), AST::Path({ AST::PathNode("#",{}), AST::PathNode("str",{}) })); + } // - Fall through to path handling // '::' - Absolute path case TOK_DOUBLE_COLON: { diff --git a/src/types.hpp b/src/types.hpp index 86733ad1..ab4c5250 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -92,6 +92,11 @@ public: m_class(PRIMITIVE), m_core_type(type) {} + TypeRef(enum eCoreType type): + m_class(PRIMITIVE), + m_core_type(type) + {} + struct TagTuple {}; TypeRef(TagTuple _, ::std::vector inner_types): m_class(TUPLE), -- cgit v1.2.3