diff options
author | John Hodge (sonata) <tpg@mutabah.net> | 2015-01-18 12:35:22 +0800 |
---|---|---|
committer | John Hodge (sonata) <tpg@mutabah.net> | 2015-01-18 12:35:22 +0800 |
commit | 0390dc8a92c3c8d12421d529915ab350234301c3 (patch) | |
tree | a2becfe84d9202f1a7464411871669f07ee1d6e1 /src | |
parent | 0c9d8ed4cbe8d74a511176cd6577c9c3d0eb3ef6 (diff) | |
download | mrust-0390dc8a92c3c8d12421d529915ab350234301c3.tar.gz |
Added pretty type printing, non-expr typecheck correctly fails on too many params (forgot to move iterator to associated types)
Diffstat (limited to 'src')
-rw-r--r-- | src/ast/ast.hpp | 9 | ||||
-rw-r--r-- | src/ast/path.cpp | 30 | ||||
-rw-r--r-- | src/ast/path.hpp | 12 | ||||
-rw-r--r-- | src/common.hpp | 20 | ||||
-rw-r--r-- | src/convert/ast_iterate.cpp | 13 | ||||
-rw-r--r-- | src/convert/ast_iterate.hpp | 2 | ||||
-rw-r--r-- | src/convert/typecheck_bounds.cpp | 48 | ||||
-rw-r--r-- | src/convert/typecheck_params.cpp | 93 | ||||
-rw-r--r-- | src/include/main_bindings.hpp | 15 | ||||
-rw-r--r-- | src/main.cpp | 8 |
10 files changed, 229 insertions, 21 deletions
diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 0ed83ec9..a57b4308 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -67,7 +67,9 @@ public: m_trait( ::std::move(trait) )
{ }
- TypeRef& get_type() { return m_trait; }
+ bool is_trait() const { return m_lifetime == ""; }
+ TypeRef& type() { return m_trait; }
+ const TypeRef& type() const { return m_trait; }
friend ::std::ostream& operator<<(::std::ostream& os, const GenericBound& x);
SERIALISABLE_PROTOTYPES();
@@ -82,6 +84,8 @@ public: TypeParams() {}
size_t n_params() const { return m_params.size(); }
+ const ::std::vector<TypeParam>& params() const { return m_params; }
+ const ::std::vector<GenericBound>& bounds() const { return m_bounds; }
::std::vector<TypeParam>& params() { return m_params; }
::std::vector<GenericBound>& bounds() { return m_bounds; }
@@ -255,6 +259,9 @@ public: {
}
+ const TypeParams& params() const { return m_params; }
+ const ItemList<TypeRef>& types() const { return m_types; }
+
void add_type(::std::string name, TypeRef type) {
m_types.push_back( Item<TypeRef>(move(name), move(type), true) );
}
diff --git a/src/ast/path.cpp b/src/ast/path.cpp index 8f77f008..e1a265bf 100644 --- a/src/ast/path.cpp +++ b/src/ast/path.cpp @@ -7,6 +7,8 @@ #include "../parse/parseerror.hpp" #include <algorithm> +#define PRETTY_PATH_PRINT 1 + namespace AST { // --- AST::PathNode @@ -23,6 +25,19 @@ const ::std::vector<TypeRef>& PathNode::args() const { return m_params; } +::std::ostream& operator<<(::std::ostream& os, const PathNode& pn) { + #if PRETTY_PATH_PRINT + os << "::"; + #endif + os << pn.m_name; + if( pn.m_params.size() ) + { + os << "<"; + os << pn.m_params; + os << ">"; + } + return os; +} SERIALISE_TYPE(PathNode::, "PathNode", { s << m_name; s << m_params; @@ -286,6 +301,20 @@ Path& Path::operator+=(const Path& other) } ::std::ostream& operator<<(::std::ostream& os, const Path& path) { + #if PRETTY_PATH_PRINT + switch(path.m_class) + { + case Path::RELATIVE: + os << "self"; + case Path::ABSOLUTE: + for(const auto& n : path.m_nodes) + os << n; + break; + case Path::LOCAL: + os << path.m_nodes[0].name(); + break; + } + #else switch(path.m_class) { case Path::RELATIVE: @@ -298,6 +327,7 @@ Path& Path::operator+=(const Path& other) os << "Path(TagLocal, " << path.m_nodes[0].name() << ")"; break; } + #endif return os; } ::Serialiser& operator<<(Serialiser& s, Path::Class pc) diff --git a/src/ast/path.hpp b/src/ast/path.hpp index 7b47bc37..7d6f9462 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -37,16 +37,7 @@ public: ::std::vector<TypeRef>& args() { return m_params; } const ::std::vector<TypeRef>& args() const; - friend ::std::ostream& operator<<(::std::ostream& os, const PathNode& pn) { - os << pn.m_name; - if( pn.m_params.size() ) - { - os << "<"; - os << pn.m_params; - os << ">"; - } - return os; - } + friend ::std::ostream& operator<<(::std::ostream& os, const PathNode& pn); SERIALISABLE_PROTOTYPES(); }; @@ -165,6 +156,7 @@ public: 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_; } + const Trait& bound_trait() const { assert(m_binding_type == TRAIT); return *m_binding.trait; } ::std::vector<PathNode>& nodes() { return m_nodes; } const ::std::vector<PathNode>& nodes() const { return m_nodes; } diff --git a/src/common.hpp b/src/common.hpp index 4e3e9be7..1e77d84a 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -9,8 +9,26 @@ #include <iostream> #include <vector> #include <cassert> +#include <sstream> -#define DEBUG(ss) do{ ::std::cerr << __FUNCTION__ << ": " << ss << ::std::endl; } while(0) +extern int g_debug_indent_level; + +#define FMT(ss) (dynamic_cast< ::std::stringstream&>(::std::stringstream() << ss).str()) +#define INDENT() do { g_debug_indent_level += 1; } while(0) +#define UNINDENT() do { g_debug_indent_level -= 1; } while(0) +#define DEBUG(ss) do{ ::std::cerr << ::RepeatLitStr{" ", g_debug_indent_level} << __FUNCTION__ << ": " << ss << ::std::endl; } while(0) + +struct RepeatLitStr +{ + const char *s; + int n; + + friend ::std::ostream& operator<<(::std::ostream& os, const RepeatLitStr& r) { + for(int i = 0; i < r.n; i ++ ) + os << r.s; + return os; + } +}; namespace rust { diff --git a/src/convert/ast_iterate.cpp b/src/convert/ast_iterate.cpp index 40133295..1e01d37d 100644 --- a/src/convert/ast_iterate.cpp +++ b/src/convert/ast_iterate.cpp @@ -3,11 +3,12 @@ #include "ast_iterate.hpp" #include "../ast/ast.hpp" -// handle_path is pure virtual - +void CASTIterator::handle_path(AST::Path& path, CASTIterator::PathMode pm) +{ +} void CASTIterator::handle_type(TypeRef& type) { - DEBUG("type = " << type); + //DEBUG("type = " << type); if( type.is_path() ) { handle_path(type.path(), MODE_TYPE); @@ -30,13 +31,14 @@ void CASTIterator::handle_params(AST::TypeParams& params) } for( auto& bound : params.bounds() ) { - handle_type(bound.get_type()); + handle_type(bound.type()); } } void CASTIterator::start_scope() { + INDENT(); } void CASTIterator::local_type(::std::string name) { @@ -52,11 +54,12 @@ void CASTIterator::local_use(::std::string name, AST::Path path) } void CASTIterator::end_scope() { + UNINDENT(); } void CASTIterator::handle_pattern(AST::Pattern& pat, const TypeRef& type_hint) { - DEBUG("pat = " << pat); + //DEBUG("pat = " << pat); // Resolve names switch(pat.type()) { diff --git a/src/convert/ast_iterate.hpp b/src/convert/ast_iterate.hpp index 3307159b..fad77926 100644 --- a/src/convert/ast_iterate.hpp +++ b/src/convert/ast_iterate.hpp @@ -23,7 +23,7 @@ public: MODE_TYPE, MODE_BIND, // Failure is allowed }; - virtual void handle_path(AST::Path& path, PathMode mode) = 0; + virtual void handle_path(AST::Path& path, PathMode mode); virtual void handle_type(TypeRef& type); virtual void handle_expr(AST::ExprNode& node); diff --git a/src/convert/typecheck_bounds.cpp b/src/convert/typecheck_bounds.cpp new file mode 100644 index 00000000..6a3fb4a7 --- /dev/null +++ b/src/convert/typecheck_bounds.cpp @@ -0,0 +1,48 @@ +/* + */ +#include <main_bindings.hpp> +#include "ast_iterate.hpp" +#include "../common.hpp" +#include <stdexcept> + +class CGenericBoundChecker: + public CASTIterator +{ +public: + virtual void handle_expr(AST::ExprNode& root) override; + virtual void handle_params(AST::TypeParams& params) override; +}; + +void CGenericBoundChecker::handle_expr(AST::ExprNode& root) +{ + // Do nothing (this iterator shouldn't recurse into expressions) +} + +void CGenericBoundChecker::handle_params(AST::TypeParams& params) +{ + for(auto& bound : params.bounds()) + { + if( bound.is_trait() ) + { + auto& trait = bound.type(); + DEBUG("trait = " << trait); + if( not trait.is_path() or trait.path().binding_type() != AST::Path::TRAIT ) + { + //throw CompileError::BoundNotTrait( bound.lex_scope(), bound.param(), trait ); + throw ::std::runtime_error(FMT("TODO - Bound " << trait << " not a trait")); + } + else { + DEBUG("Bound is a trait, good"); + } + } + } +} + +/// Typecheck generic bounds (where clauses) +void Typecheck_GenericBounds(AST::Crate& crate) +{ + DEBUG(" --- "); + CGenericBoundChecker chk; + chk.handle_module(AST::Path({}), crate.root_module()); +} + diff --git a/src/convert/typecheck_params.cpp b/src/convert/typecheck_params.cpp new file mode 100644 index 00000000..07d15bf6 --- /dev/null +++ b/src/convert/typecheck_params.cpp @@ -0,0 +1,93 @@ +/* + */ +#include <main_bindings.hpp> +#include "ast_iterate.hpp" +#include "../common.hpp" +#include <stdexcept> + +// === PROTOTYPES === +class CGenericParamChecker: + public CASTIterator +{ + int m_within_expr = 0; +public: + virtual void handle_path(AST::Path& path, CASTIterator::PathMode pm) override; + virtual void handle_expr(AST::ExprNode& root) override; +}; + +class CNodeVisitor: + public AST::NodeVisitor +{ + CGenericParamChecker& m_pc; +public: + CNodeVisitor(CGenericParamChecker& pc): + m_pc(pc) + {} +}; + +/// Check that the passed set of parameters match the requiremens for a generic item +/// +/// \param info Generic item information (param names and bounds) +/// \param types Type parameters being passed to the generic item +/// \param allow_infer Allow inferrence (mutates \a types with conditions from \a info) +bool check_generic_params(const AST::TypeParams& info, ::std::vector<TypeRef>& types, bool allow_infer = false) +{ + const auto& params = info.params(); + if( types.size() > params.size() ) + { + throw ::std::runtime_error(FMT("Too many generic params ("<<types.size()<<" passed, expecting "<< params.size()<<")")); + } + else if( types.size() < params.size() ) + { + if( allow_infer ) + { + while( types.size() < params.size() ) + { + types.push_back( TypeRef() ); + } + } + else + { + throw ::std::runtime_error(FMT("Too few generic params, ("<<types.size()<<" passed, expecting "<<params.size()<<")")); + } + } +} + +// === CODE === +void CGenericParamChecker::handle_path(AST::Path& path, CASTIterator::PathMode pm) +{ + AST::PathNode& last_node = path[path.size()-1]; + switch(path.binding_type()) + { + case AST::Path::TRAIT: + // Outside of expressions, param types must match perfectly + if( m_within_expr == 0 ) { + try { + check_generic_params(path.bound_trait().params(), last_node.args()); + } + catch( const ::std::exception& e ) + { + throw ::std::runtime_error( FMT("Checking '" << path << "', threw : " << e.what()) ); + } + } + break; + } +} + +void CGenericParamChecker::handle_expr(AST::ExprNode& root) +{ + m_within_expr += 1; + // Do nothing (this iterator shouldn't recurse into expressions) + CNodeVisitor nv(*this); + root.visit(nv); + m_within_expr -= 1; +} + +/// Typecheck generic parameters (ensure that they match all generic bounds) +void Typecheck_GenericParams(AST::Crate& crate) +{ + DEBUG(" --- "); + CGenericParamChecker chk; + chk.handle_module(AST::Path({}), crate.root_module()); +} + diff --git a/src/include/main_bindings.hpp b/src/include/main_bindings.hpp new file mode 100644 index 00000000..00b90ef3 --- /dev/null +++ b/src/include/main_bindings.hpp @@ -0,0 +1,15 @@ +/* + */ +#ifndef _MAIN_BINDINGS_HPP_ +#define _MAIN_BINDINGS_HPP_ + +#include "../ast/ast.hpp" + +extern AST::Crate Parse_Crate(::std::string mainfile); +extern void ResolvePaths(AST::Crate& crate); +extern void Typecheck_GenericBounds(AST::Crate& crate); +extern void Typecheck_GenericParams(AST::Crate& crate); +extern AST::Flat Convert_Flatten(const AST::Crate& crate); + +#endif + diff --git a/src/main.cpp b/src/main.cpp index c84a6b3d..c3952a35 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,10 +7,10 @@ #include "ast/ast.hpp"
#include <serialiser_texttree.hpp>
#include <cstring>
+#include <main_bindings.hpp>
-extern AST::Crate Parse_Crate(::std::string mainfile);
-extern void ResolvePaths(AST::Crate& crate);
-extern AST::Flat Convert_Flatten(const AST::Crate& crate);
+
+int g_debug_indent_level = 0;
/// main!
int main(int argc, char *argv[])
@@ -90,7 +90,9 @@ int main(int argc, char *argv[]) // Typecheck / type propagate module (type annotations of all values)
// - Check all generic conditions (ensure referenced trait is valid)
// > Also mark parameter with applicable traits
+ Typecheck_GenericBounds(crate);
// - Check all generic parameters match required conditions
+ Typecheck_GenericParams(crate);
// - Typecheck statics and consts
// - Typecheck + propagate functions
// > Forward pass first
|