summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Hodge (sonata) <tpg@mutabah.net>2015-01-18 12:35:22 +0800
committerJohn Hodge (sonata) <tpg@mutabah.net>2015-01-18 12:35:22 +0800
commit0390dc8a92c3c8d12421d529915ab350234301c3 (patch)
treea2becfe84d9202f1a7464411871669f07ee1d6e1 /src
parent0c9d8ed4cbe8d74a511176cd6577c9c3d0eb3ef6 (diff)
downloadmrust-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.hpp9
-rw-r--r--src/ast/path.cpp30
-rw-r--r--src/ast/path.hpp12
-rw-r--r--src/common.hpp20
-rw-r--r--src/convert/ast_iterate.cpp13
-rw-r--r--src/convert/ast_iterate.hpp2
-rw-r--r--src/convert/typecheck_bounds.cpp48
-rw-r--r--src/convert/typecheck_params.cpp93
-rw-r--r--src/include/main_bindings.hpp15
-rw-r--r--src/main.cpp8
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