From b28f21a27b355fef18bb8daf75f447c69ddad8ee Mon Sep 17 00:00:00 2001 From: "John Hodge (sonata)" Date: Wed, 14 Jan 2015 11:17:57 +0800 Subject: Local type resolution added, framework for local use statements --- src/ast/ast.cpp | 36 ++++++++------ src/ast/ast.hpp | 80 +++++++++++++++++++++++------- src/common.hpp | 55 +++++++++++++++++++++ src/convert/resolve.cpp | 128 +++++++++++++++++++++++++++++++++++++++++------- src/main.cpp | 5 +- src/parse/root.cpp | 2 +- 6 files changed, 254 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index d1e8c9fd..48cbdb9d 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -10,7 +10,6 @@ namespace AST { ExternCrate ExternCrate_std(); - SERIALISE_TYPE(MetaItem::, "AST_MetaItem", { s << m_name; s << m_str_val; @@ -42,12 +41,12 @@ SERIALISE_TYPE(MetaItem::, "AST_MetaItem", { } -Impl::Impl(TypeRef impl_type, TypeRef trait_type) -{ -} -void Impl::add_function(bool is_public, ::std::string name, Function fcn) -{ -} +SERIALISE_TYPE(Impl::, "AST_Impl", { + s << m_params; + s << m_trait; + s << m_type; + s << m_functions; +}) Crate::Crate(): m_root_module(*this, ""), @@ -144,9 +143,6 @@ void Module::add_ext_crate(::std::string ext_name, ::std::string int_name) m_extern_crates.push_back( Item< ::std::string>( ::std::move(int_name), ::std::move(ext_name), false ) ); } -void Module::add_impl(Impl impl) -{ -} void Module::iterate_functions(fcn_visitor_t *visitor, const Crate& crate) { for( auto fcn_item : this->m_functions ) @@ -200,10 +196,6 @@ SERIALISE_TYPE(Struct::, "AST_Struct", { s << m_fields; }) -TypeParam::TypeParam(bool is_lifetime, ::std::string name) -{ - -} void TypeParam::addLifetimeBound(::std::string name) { @@ -211,6 +203,22 @@ void TypeParam::addLifetimeBound(::std::string name) void TypeParam::addTypeBound(TypeRef type) { +} +::std::ostream& operator<<(::std::ostream& os, const TypeParam& tp) +{ + os << "TypeParam("; + switch(tp.m_class) + { + case TypeParam::LIFETIME: os << "'"; break; + case TypeParam::TYPE: os << ""; break; + } + os << tp.m_name; + if( tp.m_trait_bounds.size() ) + { + os << ": [" << tp.m_trait_bounds << "]"; + } + os << ")"; + return os; } SERIALISE_TYPE(TypeParam::, "AST_TypeParam", { // TODO: TypeParam diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 7a417e4f..f1289940 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -24,11 +24,30 @@ using ::std::move; class TypeParam: public Serialisable { + enum Class { + LIFETIME, + TYPE, + //INTEGER, + }; + Class m_class; + ::std::string m_name; + ::std::vector m_trait_bounds; public: - TypeParam(bool is_lifetime, ::std::string name); + TypeParam(bool is_lifetime, ::std::string name): + m_class( is_lifetime ? LIFETIME : TYPE ), + m_name( ::std::move(name) ) + {} void addLifetimeBound(::std::string name); void addTypeBound(TypeRef type); + void setDefault(TypeRef type); + + const ::std::string& name() const { return m_name; } + bool is_type() const { return m_class == TYPE; } + //TypeRef& get_default() const { return m_ + ::std::vector& get_bounds() { assert(is_type()); return m_trait_bounds; } + + friend ::std::ostream& operator<<(::std::ostream& os, const TypeParam& tp); SERIALISABLE_PROTOTYPES(); }; @@ -158,21 +177,6 @@ public: SERIALISABLE_PROTOTYPES(); }; -class Impl -{ -public: - Impl(TypeRef impl_type, TypeRef trait_type); - - void add_function(bool is_public, ::std::string name, Function fcn); -}; - - -class Crate; -class ExternCrate; -class Module; - -typedef void fcn_visitor_t(const AST::Crate& crate, const AST::Module& mod, Function& fcn); - template struct Item: public Serialisable @@ -195,6 +199,44 @@ struct Item: }) }; +class Impl: + public Serialisable +{ + TypeParams m_params; + TypeRef m_trait; + TypeRef m_type; + + ::std::vector > m_functions; +public: + Impl(TypeParams params, TypeRef impl_type, TypeRef trait_type): + m_params( move(params) ), + m_trait( move(trait_type) ), + m_type( move(impl_type) ) + {} + + void add_function(bool is_public, ::std::string name, Function fcn) { + m_functions.push_back( Item( ::std::move(name), ::std::move(fcn), is_public ) ); + } + + const TypeParams& params() const { return m_params; } + const TypeRef& trait() const { return m_trait; } + const TypeRef& type() const { return m_type; } + + TypeParams& params() { return m_params; } + TypeRef& trait() { return m_trait; } + TypeRef& type() { return m_type; } + ::std::vector >& functions() { return m_functions; } + + SERIALISABLE_PROTOTYPES(); +}; + + +class Crate; +class ExternCrate; +class Module; + +typedef void fcn_visitor_t(const AST::Crate& crate, const AST::Module& mod, Function& fcn); + /// Representation of a parsed (and being converted) function class Module: public Serialisable @@ -218,6 +260,7 @@ class Module: itemlist_static_t m_statics; itemlist_enum_t m_enums; itemlist_struct_t m_structs; + ::std::vector m_impls; public: Module(Crate& crate, ::std::string name): m_crate(crate), @@ -246,7 +289,9 @@ 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_impl(Impl impl) { + m_impls.push_back( ::std::move(impl) ); + } void add_attr(MetaItem item) { m_attrs.push_back(item); @@ -264,6 +309,7 @@ public: itemlist_mod_t& submods() { return m_submods; } itemlist_use_t& imports() { return m_imports; } itemlist_ext_t& extern_crates() { return m_extern_crates; } + ::std::vector& impls() { return m_impls; } const ::std::vector& attrs() const { return m_attrs; } const itemlist_fcn_t& functions() const { return m_functions; } diff --git a/src/common.hpp b/src/common.hpp index a7b14fdd..4e3e9be7 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -8,9 +8,64 @@ #include #include +#include #define DEBUG(ss) do{ ::std::cerr << __FUNCTION__ << ": " << ss << ::std::endl; } while(0) +namespace rust { + +template +class option +{ + bool m_set; + T m_data; +public: + option(T ent): + m_set(true), + m_data( ::std::move(ent) ) + {} + option(): + m_set(false) + {} + + bool is_none() const { return !m_set; } + bool is_some() const { return m_set; } + + const T& unwrap() const { + assert(is_some()); + return m_data; + } +}; +template +class option +{ + T* m_ptr; +public: + option(T& ent): + m_ptr(&ent) + {} + option(): + m_ptr(nullptr) + {} + + bool is_none() const { return m_ptr == nullptr; } + bool is_some() const { return m_ptr != nullptr; } + T& unwrap() const { + assert(is_some()); + return *m_ptr; + } +}; +template +option Some(T data) { + return option( ::std::move(data) ); +} +template +option None() { + return option( ); +} + +}; + namespace AST { template diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp index 67e0eda6..a696e802 100644 --- a/src/convert/resolve.cpp +++ b/src/convert/resolve.cpp @@ -11,10 +11,28 @@ class CPathResolver { + struct LocalItem + { + enum Type { + TYPE, + VAR, + } type; + ::std::string name; + AST::Path path; + + LocalItem(): + type(VAR), name() + {} + LocalItem(Type t, ::std::string name, AST::Path path=AST::Path()): + type(t), + name( ::std::move(name) ), + path( ::std::move(path) ) + {} + }; const AST::Crate& m_crate; const AST::Module& m_module; const AST::Path m_module_path; - ::std::vector< ::std::string > m_locals; + ::std::vector< LocalItem > m_locals; // TODO: Maintain a stack of variable scopes public: @@ -34,19 +52,38 @@ public: void push_scope() { DEBUG(""); - m_locals.push_back( ::std::string() ); + m_locals.push_back( LocalItem() ); } void pop_scope() { DEBUG(m_locals.size() << " items"); for( auto it = m_locals.end(); it-- != m_locals.begin(); ) { - if( *it == "" ) { + if( it->name == "" ) { m_locals.erase(it, m_locals.end()); return ; } } m_locals.clear(); } + void add_local_type(::std::string name) { + m_locals.push_back( LocalItem(LocalItem::TYPE, ::std::move(name)) ); + } + void add_local_var(::std::string name) { + m_locals.push_back( LocalItem(LocalItem::VAR, ::std::move(name)) ); + } + 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 { + for( auto it = m_locals.end(); it -- != m_locals.begin(); ) + { + if( it->type == type && it->name == name ) { + return ::rust::option(it->path); + } + } + return ::rust::option(); + } }; // Path resolution checking @@ -122,25 +159,43 @@ void CPathResolver::resolve_path(AST::Path& path, ResolvePathMode mode) const } else { - if( mode == MODE_EXPR && path.size() == 1 && path[0].args().size() == 0 ) + // 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; + LocalItem::Type search_type = (is_trivial_path && mode == MODE_EXPR ? LocalItem::VAR : LocalItem::TYPE); + auto local = lookup_local( search_type, path[0].name() ); + if( local.is_some() ) { - // One non-generic component, look in the current function for a variable - const ::std::string& var = path[0].name(); - DEBUG("varname = " << var); - auto varslot = m_locals.end(); - for(auto slot = m_locals.begin(); slot != m_locals.end(); ++slot) + auto rpath = local.unwrap(); + DEBUG("Local hit: " << path[0].name() << " = " << rpath); + + // Local import? + if( rpath.size() > 0 ) { - if( *slot == var ) { - varslot = slot; - } + path = AST::Path::add_tailing(rpath, path); + path.resolve( m_crate ); + return ; } - if( varslot != m_locals.end() ) + // Local variable? + // - TODO: What would happen if MODE_EXPR but path isn't a single ident? + if( mode == MODE_EXPR && is_trivial_path ) { - DEBUG("Located slot"); - path = AST::Path(AST::Path::TagLocal(), var); + 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()); + return ; + } + + // TODO: What about sub-types and methods on type params? + // - Invalid afaik, instead Trait::method() is used } // Search relative to current module @@ -165,6 +220,14 @@ void CPathResolver::resolve_path(AST::Path& path, ResolvePathMode mode) const return ; } } + 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.statics() ) { if( item.name == path[0].name() ) { @@ -254,7 +317,7 @@ void CPathResolver::handle_pattern(AST::Pattern& pat) } // Extract bindings and add to namespace if( pat.binding().size() > 0 ) - m_locals.push_back( pat.binding() ); + add_local_var(pat.binding()); for( auto& subpat : pat.sub_patterns() ) handle_pattern(subpat); @@ -275,7 +338,7 @@ void CPathResolver::handle_function(AST::Function& fcn) DEBUG("Code"); for( auto& arg : fcn.args() ) - m_locals.push_back(arg.first); + add_local_var(arg.first); fcn.code().visit_nodes( node_visitor ); pop_scope(); if( m_locals.size() != 0 ) @@ -362,13 +425,42 @@ void ResolvePaths_HandleModule_Use(const AST::Crate& crate, const AST::Path& mod void ResolvePaths_HandleModule(const AST::Crate& crate, const AST::Path& modpath, AST::Module& mod) { + CPathResolver pr(crate, mod, modpath); for( auto& fcn : mod.functions() ) { - CPathResolver pr(crate, mod, modpath); DEBUG("Handling function '" << fcn.name << "'"); pr.handle_function(fcn.data); } + for( auto& impl : mod.impls() ) + { + DEBUG("Handling impl<" << impl.params() << "> " << impl.trait() << " for " << impl.type()); + + // Params + pr.push_scope(); + for( auto& param : impl.params() ) + { + DEBUG("Param " << param); + pr.add_local_type(param.name()); + for(auto& trait : param.get_bounds()) + pr.resolve_type(trait); + } + // Trait + pr.resolve_type( impl.trait() ); + // Type + pr.resolve_type( impl.type() ); + + // TODO: Associated types + + // Functions + for( auto& fcn : impl.functions() ) + { + DEBUG("- Function '" << fcn.name << "'"); + pr.handle_function(fcn.data); + } + pr.pop_scope(); + } + for( auto& submod : mod.submods() ) { DEBUG("Handling submod '" << submod.first.name() << "'"); diff --git a/src/main.cpp b/src/main.cpp index 19841c12..f35f93ce 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,16 +12,17 @@ extern AST::Flat Convert_Flatten(const AST::Crate& crate); /// main! int main(int argc, char *argv[]) { + Serialiser_TextTree s_tt(::std::cout); + Serialiser& s = s_tt; try { AST::Crate crate = Parse_Crate("samples/1.rs"); - Serialiser_TextTree s_tt(::std::cout); - Serialiser& s = s_tt; s << crate; // Resolve names to be absolute names (include references to the relevant struct/global/function) ResolvePaths(crate); + s << crate; // Typecheck / type propagate module (type annotations of all values) diff --git a/src/parse/root.cpp b/src/parse/root.cpp index a0b8329f..6be74e76 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -453,7 +453,7 @@ AST::Impl Parse_Impl(TokenStream& lex) } GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN); - AST::Impl impl(impl_type, trait_type); + AST::Impl impl( ::std::move(params), ::std::move(impl_type), ::std::move(trait_type) ); // A sequence of method implementations while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE ) -- cgit v1.2.3