From d9cba0738c5fe7928ea345f510f505fe777fd8ea Mon Sep 17 00:00:00 2001 From: "John Hodge (sonata)" Date: Sun, 11 Jan 2015 12:27:07 +0800 Subject: It broke (working on correct path resolution) --- src/ast/ast.cpp | 194 ++++++++++++++++++++++++++++++++++++++++++------ src/ast/ast.hpp | 77 ++++++++++++++++--- src/ast/path.hpp | 73 ++++++++++++++---- src/convert/render.cpp | 10 ++- src/convert/resolve.cpp | 59 +++++++++++++-- src/parse/root.cpp | 22 +++--- src/types.hpp | 3 + 7 files changed, 371 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index fe6f2add..893810ec 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -25,33 +25,173 @@ const ::std::vector& PathNode::args() const } // --- AST::Path -void Path::resolve(const Crate& crate) +template +typename ::std::vector >::const_iterator find_named(const ::std::vector >& vec, const ::std::string& name) +{ + return ::std::find_if(vec.begin(), vec.end(), [&name](const Item& x) { + return x.name == name; + }); +} + +void Path::resolve() { DEBUG("*this = " << *this); if(m_class != ABSOLUTE) throw ParseError::BugCheck("Calling Path::resolve on non-absolute path"); + if(m_crate == nullptr) + throw ParseError::BugCheck("Calling Path::resolve on path with no crate"); - const Module* mod = &crate.root_module(); - for(int i = 0; i < m_nodes.size(); i ++ ) + const Module* mod = &m_crate->root_module(); + for(unsigned int i = 0; i < m_nodes.size(); i ++ ) { + const bool is_last = (i+1 == m_nodes.size()); + const bool is_sec_last = (i+2 == m_nodes.size()); const PathNode& node = m_nodes[i]; - auto& sms = mod->submods(); + DEBUG("node = " << node); - auto it = ::std::find_if(sms.begin(), sms.end(), [&node](const ::std::pair& x) { - return x.first.name() == node.name(); - }); - if( it != sms.end() ) - continue; + // Sub-modules + { + auto& sms = mod->submods(); + auto it = ::std::find_if(sms.begin(), sms.end(), [&node](const ::std::pair& x) { + return x.first.name() == node.name(); + }); + if( it != sms.end() ) + { + DEBUG("Sub-module '" << node.name() << "'"); + if( node.args().size() ) + throw ParseError::Generic("Generic params applied to module"); + mod = &it->first; + continue; + } + } + // External crates + { + auto& crates = mod->extern_crates(); + auto it = find_named(crates, node.name()); + if( it != crates.end() ) + { + DEBUG("Extern crate '" << node.name() << "'"); + if( node.args().size() ) + throw ParseError::Generic("Generic params applied to extern crate"); + mod = &it->data.root_module(); + continue; + } + } // Start searching for: // - Re-exports + { + auto& imp = mod->imports(); + auto it = find_named(imp, node.name()); + if( it != imp.end() ) + { + DEBUG("Re-exported path " << it->data); + throw ParseError::Todo("Path::resolve() re-export"); + } + } // - Functions + { + auto& items = mod->functions(); + auto it = find_named(items, node.name()); + if( it != items.end() ) + { + DEBUG("Found function"); + if( is_last ) { + throw ParseError::Todo("Path::resolve() bind to function"); + } + else { + throw ParseError::Generic("Import of function, too many extra nodes"); + } + } + } // - Structs + { + auto& items = mod->structs(); + auto it = find_named(items, node.name()); + if( it != items.end() ) + { + DEBUG("Found struct"); + if( is_last ) { + bind_struct(it->data, node.args()); + return; + } + else if( is_sec_last ) { + throw ParseError::Todo("Path::resolve() struct method"); + } + else { + throw ParseError::Generic("Import of struct, too many extra nodes"); + } + } + } // - Enums (and variants) + { + auto& enums = mod->enums(); + auto it = find_named(enums, node.name()); + if( it != enums.end() ) + { + DEBUG("Found enum"); + if( is_last ) { + bind_enum(it->data, node.args()); + return ; + } + else if( is_sec_last ) { + bind_enum_var(it->data, m_nodes[i+1].name(), node.args()); + return ; + } + else { + throw ParseError::Generic("Import of enum, too many extra nodes"); + } + } + } + // - Constants / statics + throw ParseError::Generic("Unable to find component '" + node.name() + "'"); + } + + // We only reach here if the path points to a module + bind_module(*mod); +} +void Path::bind_module(const Module& mod) +{ + m_binding_type = MODULE; + m_binding.module_ = &mod; +} +void Path::bind_enum(const Enum& ent, const ::std::vector& args) +{ + m_binding_type = ENUM; + m_binding.enum_ = &ent; + if( args.size() > 0 ) + { + if( args.size() != ent.params().size() ) + throw ParseError::Generic("Parameter count mismatch"); + throw ParseError::Todo("Bind enum with params passed"); + } +} +void Path::bind_enum_var(const Enum& ent, const ::std::string& name, const ::std::vector& args) +{ + unsigned int idx = 0; + for( idx = 0; idx < ent.variants().size(); idx ++ ) + { + if( ent.variants()[idx].first == name ) { + break; + } } + if( idx == ent.variants().size() ) + throw ParseError::Generic("Enum variant not found"); - throw ParseError::Todo("Path::resolve"); + if( args.size() > 0 ) + { + if( args.size() != ent.params().size() ) + throw ParseError::Generic("Parameter count mismatch"); + throw ParseError::Todo("Bind enum variant with params passed"); + } + + m_binding_type = ENUM_VAR; + m_binding.enumvar = {&ent, idx}; +} +void Path::bind_struct(const Struct& ent, const ::std::vector& args) +{ + throw ParseError::Todo("Path::resolve() bind to struct type"); } Path& Path::operator+=(const Path& other) @@ -106,7 +246,7 @@ Path& Path::operator+=(const Path& other) Impl::Impl(TypeRef impl_type, TypeRef trait_type) { } -void Impl::add_function(bool is_public, Function fcn) +void Impl::add_function(bool is_public, ::std::string name, Function fcn) { } @@ -132,9 +272,29 @@ ExternCrate::ExternCrate(const char *path) ExternCrate ExternCrate_std() { ExternCrate crate; + Module& std_mod = crate.root_module(); // TODO: Add modules + Module option(crate.crate(), "option"); + option.add_enum(true, "Option", Enum( + { + TypeParam(false, "T"), + }, + { + StructItem("None", TypeRef()), + StructItem("Some", TypeRef(TypeRef::TagArg(), "T")), + } + )); + std_mod.add_submod(true, ::std::move(option)); + + Module prelude(crate.crate(), "prelude"); + // Re-exports + #define USE(mod, name, ...) do{ Path p({__VA_ARGS__}); p.set_crate(crate.crate()); p.resolve(); mod.add_alias(true, ::std::move(p), name); } while(0) + USE(prelude, "Option", PathNode("option", {}), PathNode("Option",{}) ); + USE(prelude, "Some", PathNode("option", {}), PathNode("Option",{}), PathNode("Some",{}) ); + USE(prelude, "None", PathNode("option", {}), PathNode("Option",{}), PathNode("None",{}) ); + std_mod.add_submod(true, prelude); return crate; } @@ -163,16 +323,6 @@ void Module::add_global(bool is_public, bool is_mut, ::std::string name, TypeRef void Module::add_struct(bool is_public, ::std::string name, TypeParams params, ::std::vector items) { } -void Module::add_function(bool is_public, Function func) -{ - for( const auto fcn_item : m_functions ) - { - if( fcn_item.first.name() == func.name() ) { - throw ParseError::Todo("duplicate function definition"); - } - } - m_functions.push_back( ::std::make_pair(func, is_public) ); -} void Module::add_impl(Impl impl) { } @@ -181,7 +331,7 @@ void Module::iterate_functions(fcn_visitor_t *visitor, const Crate& crate) { for( auto fcn_item : this->m_functions ) { - visitor(crate, *this, fcn_item.first); + visitor(crate, *this, fcn_item.data); } } diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 25876310..c02840c6 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -15,6 +15,16 @@ namespace AST { using ::std::unique_ptr; using ::std::move; +class TypeParam +{ +public: + TypeParam(bool is_lifetime, ::std::string name); + void addLifetimeBound(::std::string name); + void addTypeBound(TypeRef type); +}; + +typedef ::std::vector TypeParams; + class Crate; class MetaItem @@ -128,6 +138,8 @@ public: friend ::std::ostream& operator<<(::std::ostream& os, const Expr& pat); }; +typedef ::std::pair< ::std::string, TypeRef> StructItem; + class Function { public: @@ -141,15 +153,13 @@ public: typedef ::std::vector Arglist; private: - ::std::string m_name; TypeParams m_generic_params; Class m_fcn_class; Expr m_code; TypeRef m_rettype; Arglist m_args; public: - Function(::std::string name, TypeParams params, Class fcn_class, TypeRef ret_type, Arglist args, Expr code): - m_name(name), + Function(TypeParams params, Class fcn_class, TypeRef ret_type, Arglist args, Expr code): m_generic_params(params), m_fcn_class(fcn_class), m_code(code), @@ -158,8 +168,6 @@ public: { } - const ::std::string& name() const { return m_name; } - TypeParams& generic_params() { return m_generic_params; } const TypeParams& generic_params() const { return m_generic_params; } @@ -173,12 +181,39 @@ public: Arglist& args() { return m_args; } }; +class Enum +{ + ::std::vector m_params; + ::std::vector m_variants; +public: + Enum( ::std::vector params, ::std::vector variants ): + m_params( move(params) ), + m_variants( move(variants) ) + {} + + const ::std::vector params() const { return m_params; } + const ::std::vector variants() const { return m_variants; } +}; + +class Struct +{ + ::std::vector m_params; + ::std::vector m_fields; +public: + Struct( ::std::vector params, ::std::vector fields ): + m_params( move(params) ), + m_fields( move(fields) ) + {} + + const ::std::vector fields() const { return m_fields; } +}; + class Impl { public: Impl(TypeRef impl_type, TypeRef trait_type); - void add_function(bool is_public, Function fcn); + void add_function(bool is_public, ::std::string name, Function fcn); }; @@ -206,20 +241,25 @@ struct Item /// Representation of a parsed (and being converted) function class Module { - typedef ::std::vector< ::std::pair > itemlist_fcn_t; + typedef ::std::vector< Item > itemlist_fcn_t; typedef ::std::vector< ::std::pair > itemlist_mod_t; typedef ::std::vector< Item > itemlist_use_t; typedef ::std::vector< Item > itemlist_ext_t; + typedef ::std::vector< Item > itemlist_enum_t; + typedef ::std::vector< Item > itemlist_struct_t; - const Crate& m_crate; + Crate& m_crate; ::std::string m_name; ::std::vector m_attrs; itemlist_fcn_t m_functions; itemlist_mod_t m_submods; itemlist_use_t m_imports; itemlist_ext_t m_extern_crates; + + itemlist_enum_t m_enums; + itemlist_struct_t m_structs; public: - Module(const Crate& crate, ::std::string name): + Module(Crate& crate, ::std::string name): m_crate(crate), m_name(name) { @@ -231,7 +271,15 @@ public: void add_constant(bool is_public, ::std::string name, TypeRef type, Expr val); void add_global(bool is_public, bool is_mut, ::std::string name, TypeRef type, Expr val); void add_struct(bool is_public, ::std::string name, TypeParams params, ::std::vector items); - void add_function(bool is_public, Function func); + void add_enum(bool is_public, ::std::string name, Enum inst) { + m_enums.push_back( Item( move(name), move(inst), is_public ) ); + } + void add_function(bool is_public, ::std::string name, Function func) { + m_functions.push_back( Item( move(name), move(func), is_public ) ); + } + void add_submod(bool is_public, Module mod) { + m_submods.push_back( ::std::make_pair( move(mod), is_public ) ); + } void add_impl(Impl impl); void add_attr(MetaItem item) { @@ -240,6 +288,7 @@ public: void iterate_functions(fcn_visitor_t* visitor, const Crate& crate); + Crate& crate() { return m_crate; } const Crate& crate() const { return m_crate; } const ::std::string& name() const { return m_name; } @@ -255,6 +304,8 @@ public: const itemlist_mod_t& submods() const { return m_submods; } const itemlist_use_t& imports() const { return m_imports; } const itemlist_ext_t& extern_crates() const { return m_extern_crates; } + const itemlist_enum_t& enums() const { return m_enums; } + const itemlist_struct_t& structs() const { return m_structs; } }; class Crate @@ -279,6 +330,8 @@ class ExternCrate public: ExternCrate(); ExternCrate(const char *path); + Crate& crate() { return m_crate; } + const Crate& crate() const { return m_crate; } Module& root_module() { return m_crate.root_module(); } const Module& root_module() const { return m_crate.root_module(); } }; @@ -295,10 +348,10 @@ public: class Flat { ::std::vector m_structs; - ::std::vector m_functions; + ::std::vector< ::std::pair< ::std::string,Function> > m_functions; public: - const ::std::vector& functions() const { return m_functions; } + const ::std::vector< ::std::pair<::std::string, Function> >& functions() const { return m_functions; } const ::std::vector& structs() const { return m_structs; } }; diff --git a/src/ast/path.hpp b/src/ast/path.hpp index 05439e06..f990dedb 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -6,23 +6,20 @@ #include "../common.hpp" #include #include +#include +#include +#include class TypeRef; namespace AST { class Crate; +class Module; +class Enum; +class Struct; +class Function; -class TypeParam -{ -public: - TypeParam(bool is_lifetime, ::std::string name); - void addLifetimeBound(::std::string name); - void addTypeBound(TypeRef type); -}; - -typedef ::std::vector TypeParams; -typedef ::std::pair< ::std::string, TypeRef> StructItem; class PathNode { @@ -48,31 +45,71 @@ public: class Path { +public: + enum BindingType { + UNBOUND, + MODULE, + ENUM, + ENUM_VAR, + }; +private: enum Class { RELATIVE, ABSOLUTE, LOCAL, }; + + /// The crate defining the root of this path (used for path resolution) + const Crate* m_crate; + + /// Path class (absolute, relative, local) + /// - Absolute is "relative" to the crate root + /// - Relative doesn't have a set crate (and can't be resolved) + /// - Local is a special case to handle possible use of local varaibles Class m_class; ::std::vector m_nodes; + + BindingType m_binding_type = UNBOUND; + union { + const Module* module_; + const Enum* enum_; + struct { + const Enum* enum_; + unsigned int idx; + } enumvar; + } m_binding; public: Path(): + m_crate(nullptr), m_class(RELATIVE) {} struct TagAbsolute {}; Path(TagAbsolute): + m_crate(nullptr), m_class(ABSOLUTE) {} struct TagLocal {}; Path(TagLocal, ::std::string name): + m_crate(nullptr), m_class(LOCAL), m_nodes({PathNode(name, {})}) {} + Path(::std::initializer_list l): + m_crate(nullptr), + m_class(ABSOLUTE), + m_nodes(l) + {} + + void set_crate(const Crate& crate) { + if( !m_crate ) + m_crate = &crate; + } + static Path add_tailing(const Path& a, const Path& b) { Path ret(a); - for(const auto& ent : b.m_nodes) - ret.m_nodes.push_back(ent); + for(unsigned int i = 1; i < b.m_nodes.size(); i ++) + ret.m_nodes.push_back(b.m_nodes[i]); return ret; } Path operator+(PathNode&& pn) const { @@ -94,10 +131,15 @@ public: m_nodes.push_back(node); } - void resolve(const Crate& crate); + void resolve(); bool is_relative() const { return m_class == RELATIVE; } size_t size() const { return m_nodes.size(); } + + bool is_bound() const { return m_binding_type != UNBOUND; } + BindingType binding_type() const { return m_binding_type; } + const Module& bound_module() const { assert(m_binding_type == MODULE); return *m_binding.module_; } + ::std::vector& nodes() { return m_nodes; } const ::std::vector& nodes() const { return m_nodes; } @@ -105,6 +147,11 @@ public: const PathNode& operator[](size_t idx) const { return m_nodes[idx]; } friend ::std::ostream& operator<<(::std::ostream& os, const Path& path); +private: + void bind_module(const Module& mod); + void bind_enum(const Enum& ent, const ::std::vector& args); + void bind_enum_var(const Enum& ent, const ::std::string& name, const ::std::vector& args); + void bind_struct(const Struct& ent, const ::std::vector& args); }; } // namespace AST diff --git a/src/convert/render.cpp b/src/convert/render.cpp index 7f65945a..bcc0ef68 100644 --- a/src/convert/render.cpp +++ b/src/convert/render.cpp @@ -36,12 +36,14 @@ void Render_Crate(::std::ostream& os, const AST::Flat& crate) FOREACH(::std::vector, s, crate.structs()) os << "struct " << s->mangled_name() << ";\n"; - FOREACH(::std::vector, fcn, crate.functions()) + for(const auto& item : crate.functions()) { - Render_Type(os, fcn->rettype(), nullptr); - os << " " << fcn->name() << "("; + const auto& name = item.first; + const auto& fcn = item.second; + Render_Type(os, fcn.rettype(), nullptr); + os << " " << name << "("; bool is_first = true; - FOREACH(item_vec_t, f, fcn->args()) + FOREACH(item_vec_t, f, fcn.args()) { if( !is_first ) os << ", "; diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp index 6ea3fcc6..7f36c964 100644 --- a/src/convert/resolve.cpp +++ b/src/convert/resolve.cpp @@ -87,6 +87,8 @@ CPathResolver::CPathResolver(const AST::Crate& crate, const AST::Module& mod): void CPathResolver::resolve_path(AST::Path& path, bool allow_variables) const { + DEBUG("path = " << path); + // Handle generic components of the path for( auto& ent : path.nodes() ) { @@ -100,6 +102,11 @@ void CPathResolver::resolve_path(AST::Path& path, bool allow_variables) const if( !path.is_relative() ) { // Already absolute, our job is done + // - However, if the path isn't bound, bind it + if( !path.is_bound() ) { + path.set_crate(m_crate); + path.resolve(); + } } else { @@ -133,11 +140,12 @@ void CPathResolver::resolve_path(AST::Path& path, bool allow_variables) const // Check name down? // Add current module path path = m_module_path + path; + break; } } for( const auto& item_fcn : m_module.functions() ) { - if( item_fcn.first.name() == path[0].name() ) { + if( item_fcn.name == path[0].name() ) { path = m_module_path + path; break; } @@ -149,13 +157,18 @@ void CPathResolver::resolve_path(AST::Path& path, bool allow_variables) const if( bind_name == "" ) { // wildcard import! // TODO: Import should be tagged with - throw ParseError::Todo("CPathResolver::resolve_path() - Wildcards"); + //throw ParseError::Todo("CPathResolver::resolve_path() - Wildcards"); } else if( bind_name == path[0].name() ) { path = AST::Path::add_tailing(bind_path, path); + break; } } + DEBUG("path = " << path); + path.resolve(); + + throw ParseError::Todo("CPathResolver::resolve_path()"); } } @@ -250,6 +263,8 @@ void ResolvePaths_HandleFunction(const AST::Crate& crate, const AST::Module& mod void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& modpath, AST::Module& mod) { + DEBUG("modpath = " << modpath); + ::std::vector new_imports; for( auto& imp : mod.imports() ) { // TODO: Handle 'super' and 'self' imports @@ -258,15 +273,49 @@ void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& mod if( imp.name == "" ) { + DEBUG("Wildcard of " << imp.data); if( imp.is_pub ) { throw ParseError::Generic("Wildcard uses can't be public"); } // Wildcard import AST::Path& basepath = imp.data; - basepath.resolve(crate); - throw ParseError::Todo("ResolvePaths_HandleModule - wildcard use"); + basepath.set_crate(crate); + basepath.resolve(); + switch(basepath.binding_type()) + { + case AST::Path::UNBOUND: + throw ParseError::BugCheck("path unbound after calling .resolve()"); + case AST::Path::MODULE: + for( auto& submod : basepath.bound_module().submods() ) + { + if( submod.second == true ) + { + new_imports.push_back( basepath + AST::PathNode(submod.first.name(), {}) ); + } + } + for(const auto& imp : basepath.bound_module().imports() ) + { + if( imp.is_pub ) + { + if(imp.name == "") + throw ParseError::Generic("Wilcard uses can't be public"); + new_imports.push_back( imp.data ); + } + } + //throw ParseError::Todo("ResolvePaths_HandleModule - wildcard use on module"); + break; + } + } + } + + for( auto& new_imp : new_imports ) + { + if( not new_imp.is_bound() ) { + new_imp.set_crate(crate); + new_imp.resolve(); } + mod.add_alias(false, new_imp, new_imp[new_imp.size()-1].name()); } for( auto& submod : mod.submods() ) @@ -279,7 +328,7 @@ void ResolvePaths_HandleModule(const AST::Crate& crate, const AST::Path& modpath { for( auto& fcn : mod.functions() ) { - ResolvePaths_HandleFunction(crate, mod, fcn.first); + ResolvePaths_HandleFunction(crate, mod, fcn.data); } for( auto& submod : mod.submods() ) diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 1c2582f7..d3ca5b9b 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -243,10 +243,6 @@ AST::Function Parse_FunctionDef(TokenStream& lex) Token tok; - // Name - GET_CHECK_TOK(tok, lex, TOK_IDENT); - ::std::string name = tok.str(); - // Parameters AST::TypeParams params; if( GET_TOK(tok, lex) == TOK_LT ) @@ -329,7 +325,7 @@ AST::Function Parse_FunctionDef(TokenStream& lex) AST::Expr code = Parse_ExprBlock(lex); - return AST::Function(name, params, fcn_class, ret_type, args, code); + return AST::Function(params, fcn_class, ret_type, args, code); } void Parse_Struct(AST::Module& mod, TokenStream& lex, const bool is_public, const ::std::vector meta_items) @@ -469,9 +465,11 @@ AST::Impl Parse_Impl(TokenStream& lex) } switch(tok.type()) { - case TOK_RWORD_FN: - impl.add_function(is_public, Parse_FunctionDef(lex)); - break; + case TOK_RWORD_FN: { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + ::std::string name = tok.str(); + impl.add_function(is_public, name, Parse_FunctionDef(lex)); + break; } default: throw ParseError::Unexpected(tok); @@ -655,9 +653,11 @@ void Parse_ModRoot(Preproc& lex, AST::Module& mod, const ::std::string& path) mod.add_global(is_public, is_mut, name, type, val); break; } - case TOK_RWORD_FN: - mod.add_function(is_public, Parse_FunctionDef(lex)); - break; + case TOK_RWORD_FN: { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + ::std::string name = tok.str(); + mod.add_function(is_public, name, Parse_FunctionDef(lex)); + break; } case TOK_RWORD_STRUCT: Parse_Struct(mod, lex, is_public, meta_items); break; diff --git a/src/types.hpp b/src/types.hpp index f6a58d2a..4a596522 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -30,6 +30,9 @@ public: struct TagUnsizedArray {}; TypeRef(TagUnsizedArray _, TypeRef inner_type) {} + struct TagArg {}; + TypeRef(TagArg, ::std::string name) {} + struct TagPath {}; TypeRef(TagPath, AST::Path path) {} -- cgit v1.2.3