From 76f199888f65fd21ffdae7c3518748098fdc0726 Mon Sep 17 00:00:00 2001 From: "John Hodge (sonata)" Date: Sun, 25 Jan 2015 17:59:48 +0800 Subject: Hacked in dumping as rust --- Makefile | 3 +- src/ast/ast.cpp | 193 ++++++++++++++++++++++++++- src/ast/ast.hpp | 26 +++- src/ast/expr.cpp | 178 ++++++++++++++----------- src/ast/expr.hpp | 76 ++++------- src/ast/path.cpp | 25 +++- src/ast/path.hpp | 2 + src/ast/pattern.hpp | 31 +++++ src/convert/ast_iterate.cpp | 8 +- src/convert/render.cpp | 5 +- src/convert/typecheck_expr.cpp | 11 +- src/dump_as_rust.cpp | 290 +++++++++++++++++++++++++++++++++++++++++ src/include/main_bindings.hpp | 2 + src/main.cpp | 12 +- src/parse/expr.cpp | 49 ++++--- src/parse/root.cpp | 22 ++-- src/types.cpp | 116 ++++++++++++++--- src/types.hpp | 22 +++- 18 files changed, 867 insertions(+), 204 deletions(-) create mode 100644 src/dump_as_rust.cpp diff --git a/Makefile b/Makefile index 6cff5d01..30184cbd 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ BIN := bin/mrustc$(EXESUF) OBJ := main.o macros.o types.o serialise.o OBJ += ast/ast.o ast/path.o ast/expr.o OBJ += parse/parseerror.o parse/lex.o parse/preproc.o parse/root.o parse/expr.o +OBJ += dump_as_rust.o OBJ += convert/ast_iterate.o OBJ += convert/resolve.o convert/typecheck_bounds.o convert/typecheck_params.o convert/typecheck_expr.o OBJ += convert/flatten.o convert/render.o @@ -30,7 +31,7 @@ clean: test: $(BIN) samples/1.rs mkdir -p output/ time $(DBG) $(BIN) samples/std.rs --emit ast -o output/std.ast - time $(DBG) $(BIN) samples/1.rs --crate-path output/std.ast + time $(DBG) $(BIN) samples/1.rs --crate-path output/std.ast -o output/test.c $(BIN): $(OBJ) @mkdir -p $(dir $@) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 80bc3c57..7f3430f2 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -67,6 +67,87 @@ SERIALISE_TYPE_S(Pattern, { s.item(m_path); }); +Impl Impl::make_concrete(const ::std::vector& types) const +{ + DEBUG("types={" << types << "}"); + INDENT(); + + assert(m_params.n_params()); + + Impl ret( TypeParams(), m_trait, m_type ); + + auto resolver = [&](const char *name) { + int idx = m_params.find_name(name); + assert(idx >= 0); + return types[idx]; + }; + + ret.m_trait.resolve_args(resolver); + ret.m_type.resolve_args(resolver); + + for(const auto& fcn : m_functions) + { + TypeParams new_fcn_params = fcn.data.params(); + for( auto& b : new_fcn_params.bounds() ) + b.type().resolve_args(resolver); + TypeRef new_ret_type = fcn.data.rettype(); + new_ret_type.resolve_args(resolver); + Function::Arglist new_args = fcn.data.args(); + for( auto& t : new_args ) + t.second.resolve_args(resolver); + + ret.add_function( fcn.is_pub, fcn.name, Function( ::std::move(new_fcn_params), fcn.data.fcn_class(), ::std::move(new_ret_type), ::std::move(new_args), Expr() ) ); + } + + UNINDENT(); + return ret; +} + +::rust::option Impl::matches(const TypeRef& trait, const TypeRef& type) +{ + DEBUG("this = " << *this); + if( m_params.n_params() ) + { + ::std::vector param_types(m_params.n_params()); + try + { + auto c = [&](const char* name,const TypeRef& ty){ + int idx = m_params.find_name(name); + assert( idx >= 0 ); + assert( (unsigned)idx < m_params.n_params() ); + param_types[idx].merge_with( ty ); + }; + m_trait.match_args(trait, c); + m_type.match_args(type, c); + + // Check that conditions match + // - TODO: Requires locating/checking trait implementations on types + + // The above two will throw if matching failed, so if we get here, it's a match + for( auto& i : m_concrete_impls ) + { + if( i.first == param_types ) + { + return ::rust::option(i.second); + } + } + m_concrete_impls.push_back( make_pair(param_types, this->make_concrete(param_types)) ); + return ::rust::option( m_concrete_impls.back().second ); + } + catch( const ::std::runtime_error& e ) + { + DEBUG("No match - " << e.what()); + } + } + else + { + if( m_trait == trait && m_type == type ) + { + return ::rust::option( *this ); + } + } + return ::rust::option(); +} ::std::ostream& operator<<(::std::ostream& os, const Impl& impl) { @@ -89,6 +170,25 @@ Crate::Crate(): m_load_std(true) { } + +static void iterate_module(Module& mod, ::std::function fcn) +{ + fcn(mod); + for( auto& sm : mod.submods() ) + iterate_module(sm.first, fcn); +} + +void Crate::post_parse() +{ + // Iterate all modules, grabbing pointers to all impl blocks + iterate_module(m_root_module, [this](Module& mod){ + for( auto& impl : mod.impls() ) + { + m_impl_index.push_back( &impl ); + } + }); +} + void Crate::iterate_functions(fcn_visitor_t* visitor) { m_root_module.iterate_functions(visitor, *this); @@ -107,6 +207,8 @@ const Module& Crate::get_root_module(const ::std::string& name) const { ::rust::option Crate::find_impl(const TypeRef& trait, const TypeRef& type) { + DEBUG("trait = " << trait << ", type = " << type); + // TODO: Support autoderef here? NO if( trait.is_wildcard() && !type.is_path() ) { @@ -118,10 +220,11 @@ const Module& Crate::get_root_module(const ::std::string& name) const { for( auto implptr : m_impl_index ) { Impl& impl = *implptr; - // TODO: Pass to impl for comparison (handles type params) - if( impl.trait() == trait && impl.type() == type ) + // TODO: What if there's two impls that match this combination? + ::rust::option oimpl = impl.matches(trait, type); + if( oimpl.is_some() ) { - return ::rust::option(impl); + return oimpl.unwrap(); } } DEBUG("No impl of " << trait << " for " << type); @@ -319,12 +422,12 @@ TypeRef Struct::get_field_type(const char *name, const ::std::vector& a // TODO: Should the bounds be checked here? Or is the count sufficient? for(const auto& f : m_fields) { - if( f.first == name ) + if( f.name == name ) { // Found it! if( args.size() ) { - TypeRef res = f.second; + TypeRef res = f.data; res.resolve_args( [&](const char *argname){ for(unsigned int i = 0; i < m_params.n_params(); i ++) { @@ -338,7 +441,7 @@ TypeRef Struct::get_field_type(const char *name, const ::std::vector& a } else { - return f.second; + return f.data; } } } @@ -411,6 +514,84 @@ int TypeParams::find_name(const char* name) const return -1; } +bool TypeParams::check_params(Crate& crate, const ::std::vector& types) const +{ + return check_params( crate, const_cast< ::std::vector&>(types), false ); +} +bool TypeParams::check_params(Crate& crate, ::std::vector& types, bool allow_infer) const +{ + // XXX: Make sure all params are types + { + for(const auto& p : m_params) + assert(p.is_type()); + } + + // Check parameter counts + if( types.size() > m_params.size() ) + { + throw ::std::runtime_error(FMT("Too many generic params ("<& types) const; + bool check_params(Crate& crate, ::std::vector& types, bool allow_infer) const; friend ::std::ostream& operator<<(::std::ostream& os, const TypeParams& tp); SERIALISABLE_PROTOTYPES(); @@ -136,7 +139,7 @@ struct Item: template using ItemList = ::std::vector >; -typedef ::std::pair< ::std::string, TypeRef> StructItem; +typedef Item StructItem; class Crate; @@ -207,8 +210,10 @@ public: m_type( move(type) ), m_value( move(value) ) {} - + + const Class& s_class() const { return m_class; } const TypeRef& type() const { return m_type; } + const Expr& value() const { return m_value; } SERIALISABLE_PROTOTYPES(); }; @@ -224,7 +229,7 @@ public: CLASS_MUTMETHOD, CLASS_VALMETHOD, }; - typedef ::std::vector Arglist; + typedef ::std::vector< ::std::pair > Arglist; private: Class m_fcn_class; @@ -344,6 +349,8 @@ class Impl: ItemList m_types; ItemList m_functions; + + ::std::vector< ::std::pair< ::std::vector, Impl > > m_concrete_impls; public: Impl() {} Impl(TypeParams params, TypeRef impl_type, TypeRef trait_type): @@ -370,6 +377,10 @@ public: TypeRef& type() { return m_type; } ItemList& functions() { return m_functions; } ItemList& types() { return m_types; } + + Impl make_concrete(const ::std::vector& types) const; + + ::rust::option matches(const TypeRef& trait, const TypeRef& type); friend ::std::ostream& operator<<(::std::ostream& os, const Impl& impl); SERIALISABLE_PROTOTYPES(); @@ -492,14 +503,15 @@ public: Crate(); Module& root_module() { return m_root_module; } - const Module& root_module() const { return m_root_module; } - Module& get_root_module(const ::std::string& name); - const Module& get_root_module(const ::std::string& name) const; - ::std::map< ::std::string, ExternCrate>& extern_crates() { return m_extern_crates; } + + const Module& root_module() const { return m_root_module; } + const Module& get_root_module(const ::std::string& name) const; const ::std::map< ::std::string, ExternCrate>& extern_crates() const { return m_extern_crates; } + void post_parse(); + ::rust::option find_impl(const TypeRef& trait, const TypeRef& type); Function& lookup_method(const TypeRef& type, const char *name); diff --git a/src/ast/expr.cpp b/src/ast/expr.cpp index 1009709b..91f77633 100644 --- a/src/ast/expr.cpp +++ b/src/ast/expr.cpp @@ -10,7 +10,10 @@ void Expr::visit_nodes(NodeVisitor& v) } ::std::ostream& operator<<(::std::ostream& os, const Expr& pat) { - return os << "Expr(TODO)"; + if( pat.m_node.get() ) + return os << *pat.m_node; + else + return os << "/* null */"; } SERIALISE_TYPE(Expr::, "Expr", { s.item(m_node); @@ -23,6 +26,16 @@ SERIALISE_TYPE(Expr::, "Expr", { m_node.reset(); }); +::std::ostream& operator<<(::std::ostream& os, const ExprNode& node) +{ + if( &node != nullptr ) { + node.print(os); + } + else { + os << "/* NULLPTR */"; + } + return os; +} ::std::unique_ptr ExprNode::from_deserialiser(Deserialiser& d) { ::std::string tag = d.start_object(); @@ -59,145 +72,151 @@ SERIALISE_TYPE(Expr::, "Expr", { ExprNode::~ExprNode() { } +#define NODE(class, serialise, _print) void class::visit(NodeVisitor& nv) { nv.visit(*this); } SERIALISE_TYPE_S(class, serialise) void class::print(::std::ostream& os) const _print + ExprNode_Block::~ExprNode_Block() { } -void ExprNode_Block::visit(NodeVisitor& nv) { - nv.visit(*this); -} -SERIALISE_TYPE_S(ExprNode_Block, { +NODE(ExprNode_Block, { s.item(m_nodes); +},{ + os << "{"; + for(const auto& n : m_nodes) + os << *n << ";"; + os << "}"; }) -void ExprNode_Macro::visit(NodeVisitor& nv) { - nv.visit(*this); -} -SERIALISE_TYPE_S(ExprNode_Macro, { +NODE(ExprNode_Macro, { s.item(m_name); //s.item(m_tokens); +},{ + os << m_name << "!(" << ")"; }) -void ExprNode_Return::visit(NodeVisitor& nv) { - nv.visit(*this); -} -SERIALISE_TYPE_S(ExprNode_Return, { +NODE(ExprNode_Return, { s.item(m_value); +},{ + os << "return " << *m_value; }) -void ExprNode_LetBinding::visit(NodeVisitor& nv) { - nv.visit(*this); -} -SERIALISE_TYPE_S(ExprNode_LetBinding, { +NODE(ExprNode_LetBinding, { s.item(m_pat); s.item(m_value); +},{ + os << "let " << m_pat << ": " << m_type << " = " << *m_value; }) -void ExprNode_Assign::visit(NodeVisitor& nv) { - nv.visit(*this); -} -SERIALISE_TYPE_S(ExprNode_Assign, { +NODE(ExprNode_Assign, { s.item(m_slot); s.item(m_value); +},{ + os << *m_slot << " = " << *m_value; }) -void ExprNode_CallPath::visit(NodeVisitor& nv) { - nv.visit(*this); -} -SERIALISE_TYPE_S(ExprNode_CallPath, { +NODE(ExprNode_CallPath, { s.item(m_path); s.item(m_args); +},{ + os << m_path << "("; + for(const auto& a : m_args) { + os << *a << ","; + } + os << ")"; }) -void ExprNode_CallMethod::visit(NodeVisitor& nv) { - nv.visit(*this); -} -SERIALISE_TYPE_S(ExprNode_CallMethod, { +NODE(ExprNode_CallMethod, { s.item(m_val); s.item(m_method); s.item(m_args); +},{ + os << "(" << *m_val << ")." << m_method << "("; + for(const auto& a : m_args) { + os << *a << ","; + } + os << ")"; }) -void ExprNode_CallObject::visit(NodeVisitor& nv) { - nv.visit(*this); -} -SERIALISE_TYPE_S(ExprNode_CallObject, { +NODE(ExprNode_CallObject, { s.item(m_val); s.item(m_args); +},{ + os << "(" << *m_val << ")("; + for(const auto& a : m_args) { + os << *a << ","; + } + os << ")"; }) -void ExprNode_Match::visit(NodeVisitor& nv) { - nv.visit(*this); -} -SERIALISE_TYPE_S(ExprNode_Match, { +NODE(ExprNode_Match, { s.item(m_val); s.item(m_arms); +},{ + os << "match ("<<*m_val<<") {"; + for(const auto& arm : m_arms) + { + os << " " << arm.first << " => " << *arm.second << ","; + } + os << "}"; }) -void ExprNode_If::visit(NodeVisitor& nv) { - nv.visit(*this); -} -SERIALISE_TYPE_S(ExprNode_If, { +NODE(ExprNode_If, { s.item(m_cond); s.item(m_true); s.item(m_false); +},{ + os << "if " << *m_cond << " { " << *m_true << " } else { " << *m_false << " }"; }) -void ExprNode_Integer::visit(NodeVisitor& nv) { - nv.visit(*this); -} -SERIALISE_TYPE_S(ExprNode_Integer, { +NODE(ExprNode_Integer, { s % m_datatype; s.item(m_value); +},{ + os << m_value; }) -void ExprNode_StructLiteral::visit(NodeVisitor& nv) { - nv.visit(*this); -} -SERIALISE_TYPE_S(ExprNode_StructLiteral, { +NODE(ExprNode_StructLiteral, { s.item(m_path); s.item(m_base_value); s.item(m_values); +},{ + os << "/* todo: sl */"; }) -void ExprNode_Tuple::visit(NodeVisitor& nv) { - nv.visit(*this); -} -SERIALISE_TYPE_S(ExprNode_Tuple, { +NODE(ExprNode_Tuple, { s.item(m_values); +},{ + os << "("; + for(const auto& a : m_values) { + os << *a << ","; + } + os << ")"; }) -void ExprNode_NamedValue::visit(NodeVisitor& nv) { - nv.visit(*this); -} -SERIALISE_TYPE_S(ExprNode_NamedValue, { +NODE(ExprNode_NamedValue, { s.item(m_path); +},{ + os << m_path; }) -void ExprNode_Field::visit(NodeVisitor& nv) { - nv.visit(*this); -} -SERIALISE_TYPE_S(ExprNode_Field, { +NODE(ExprNode_Field, { s.item(m_obj); s.item(m_name); +},{ + os << "(" << *m_obj << ")." << m_name; }) -void ExprNode_Deref::visit(NodeVisitor& nv) { - nv.visit(*this); -} -SERIALISE_TYPE_S(ExprNode_Deref, { +NODE(ExprNode_Deref, { s.item(m_value); +},{ + os << "*(" << *m_value << ")"; }); -void ExprNode_Cast::visit(NodeVisitor& nv) { - nv.visit(*this); -} -SERIALISE_TYPE_S(ExprNode_Cast, { +NODE(ExprNode_Cast, { s.item(m_value); s.item(m_type); +},{ + os << "(" << *m_value << " as " << m_type << ")"; }) -void ExprNode_BinOp::visit(NodeVisitor& nv) { - nv.visit(*this); -} void operator%(::Serialiser& s, const ExprNode_BinOp::Type t) { switch(t) { @@ -222,10 +241,23 @@ void operator%(::Deserialiser& s, ExprNode_BinOp::Type& t) { throw ::std::runtime_error(""); #undef _ } -SERIALISE_TYPE_S(ExprNode_BinOp, { +NODE(ExprNode_BinOp, { s % m_type; s.item(m_left); s.item(m_right); +},{ + os << "(" << *m_left << " "; + switch(m_type) + { + case CMPEQU: os << "=="; break; + case CMPNEQU: os << "!="; break; + case BITAND: os << "&"; break; + case BITOR: os << "|"; break; + case BITXOR: os << "^"; break; + case SHR: os << ">>"; break; + case SHL: os << "<<"; break; + } + os << " " << *m_right << ")"; }) diff --git a/src/ast/expr.hpp b/src/ast/expr.hpp index f1d16af0..2744b75e 100644 --- a/src/ast/expr.hpp +++ b/src/ast/expr.hpp @@ -25,12 +25,16 @@ public: virtual ~ExprNode() = 0; virtual void visit(NodeVisitor& nv) = 0; + virtual void print(::std::ostream& os) const = 0; TypeRef& get_res_type() { return m_res_type; } + friend ::std::ostream& operator<<(::std::ostream& os, const ExprNode& node); static ::std::unique_ptr from_deserialiser(Deserialiser& d); }; +#define NODE_METHODS() virtual void visit(NodeVisitor& nv) override; virtual void print(::std::ostream& os) const override; SERIALISABLE_PROTOTYPES(); + struct ExprNode_Block: public ExprNode { @@ -43,9 +47,7 @@ struct ExprNode_Block: } virtual ~ExprNode_Block() override; - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; struct ExprNode_Macro: @@ -60,9 +62,7 @@ struct ExprNode_Macro: m_tokens( move(tokens) ) {} - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; // Return a value @@ -77,9 +77,7 @@ struct ExprNode_Return: { } - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; struct ExprNode_LetBinding: public ExprNode @@ -96,9 +94,7 @@ struct ExprNode_LetBinding: { } - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; struct ExprNode_Assign: public ExprNode @@ -113,9 +109,7 @@ struct ExprNode_Assign: { } - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; struct ExprNode_CallPath: public ExprNode @@ -130,9 +124,7 @@ struct ExprNode_CallPath: { } - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; struct ExprNode_CallMethod: public ExprNode @@ -149,9 +141,7 @@ struct ExprNode_CallMethod: { } - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; // Call an object (Fn/FnMut/FnOnce) struct ExprNode_CallObject: @@ -166,9 +156,7 @@ struct ExprNode_CallObject: m_args( move(args) ) { } - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; struct ExprNode_Match: @@ -184,9 +172,7 @@ struct ExprNode_Match: m_arms( ::std::move(arms) ) { } - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; struct ExprNode_If: @@ -203,9 +189,7 @@ struct ExprNode_If: m_false( ::std::move(false_code) ) { } - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; // Literal integer struct ExprNode_Integer: @@ -221,9 +205,7 @@ struct ExprNode_Integer: { } - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; // Literal structure struct ExprNode_StructLiteral: @@ -241,9 +223,7 @@ struct ExprNode_StructLiteral: m_values( move(values) ) {} - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; // Tuple struct ExprNode_Tuple: @@ -256,9 +236,7 @@ struct ExprNode_Tuple: m_values( ::std::move(vals) ) {} - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; // Variable / Constant struct ExprNode_NamedValue: @@ -271,9 +249,7 @@ struct ExprNode_NamedValue: m_path( ::std::move(path) ) { } - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; // Field dereference struct ExprNode_Field: @@ -288,9 +264,7 @@ struct ExprNode_Field: m_name( ::std::move(name) ) { } - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; // Pointer dereference @@ -305,9 +279,7 @@ struct ExprNode_Deref: { } - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; // Type cast ('as') @@ -323,9 +295,7 @@ struct ExprNode_Cast: m_type( move(dst_type) ) { } - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; // Binary operation @@ -356,9 +326,7 @@ struct ExprNode_BinOp: { } - virtual void visit(NodeVisitor& nv) override; - - SERIALISABLE_PROTOTYPES(); + NODE_METHODS(); }; class NodeVisitor diff --git a/src/ast/path.cpp b/src/ast/path.cpp index 6daaf406..cd068694 100644 --- a/src/ast/path.cpp +++ b/src/ast/path.cpp @@ -259,7 +259,7 @@ void Path::bind_enum_var(const Enum& ent, const ::std::string& name, const ::std unsigned int idx = 0; for( idx = 0; idx < ent.variants().size(); idx ++ ) { - if( ent.variants()[idx].first == name ) { + if( ent.variants()[idx].name == name ) { break; } } @@ -311,6 +311,27 @@ bool Path::operator==(const Path& x) const return m_class == x.m_class && m_crate == x.m_crate && m_nodes == x.m_nodes; } +void Path::print_pretty(::std::ostream& os) const +{ + switch(m_class) + { + case Path::RELATIVE: + os << "self"; + for(const auto& n : m_nodes) + os << n; + break; + case Path::ABSOLUTE: + if( m_crate != "" ) + os << "::" << m_crate; + for(const auto& n : m_nodes) + os << n; + break; + case Path::LOCAL: + os << m_nodes[0].name(); + break; + } +} + ::std::ostream& operator<<(::std::ostream& os, const Path& path) { #if PRETTY_PATH_PRINT @@ -322,7 +343,7 @@ bool Path::operator==(const Path& x) const os << n; break; case Path::ABSOLUTE: - os << "["<& args() const; bool operator==(const PathNode& x) const; + void print_pretty(::std::ostream& os) const; friend ::std::ostream& operator<<(::std::ostream& os, const PathNode& pn); SERIALISABLE_PROTOTYPES(); @@ -183,6 +184,7 @@ public: bool operator==(const Path& x) const; SERIALISABLE_PROTOTYPES(); + void print_pretty(::std::ostream& os) const; friend ::std::ostream& operator<<(::std::ostream& os, const Path& path); friend ::Serialiser& operator<<(Serialiser& s, Path::Class pc); friend void operator>>(Deserialiser& s, Path::Class& pc); diff --git a/src/ast/pattern.hpp b/src/ast/pattern.hpp index 70fc77f4..82db2b7c 100644 --- a/src/ast/pattern.hpp +++ b/src/ast/pattern.hpp @@ -31,6 +31,37 @@ private: unique_ptr m_node; ::std::vector m_sub_patterns; public: + Pattern(Pattern&& o): + m_class(o.m_class), + m_binding( move(o.m_binding) ), + m_path( move(o.m_path) ), + m_node( move(o.m_node) ), + m_sub_patterns( move(o.m_sub_patterns) ) + { } + + Pattern(const Pattern& o): + m_class(o.m_class), + m_binding(o.m_binding), + m_path(o.m_path), + m_node(nullptr), + m_sub_patterns(o.m_sub_patterns) + { + if( o.m_node.get() ) { + DEBUG("Cloning " << o); + throw ::std::runtime_error(FMT("Cloning pattern with node : " << o)); + } + } + + Pattern& operator=(Pattern o) + { + m_class = o.m_class, + m_binding = move(o.m_binding); + m_path = move(o.m_path); + m_node = move(o.m_node); + m_sub_patterns = move(o.m_sub_patterns); + return *this; + } + Pattern(): m_class(ANY) {} diff --git a/src/convert/ast_iterate.cpp b/src/convert/ast_iterate.cpp index 1c232b33..26ef2191 100644 --- a/src/convert/ast_iterate.cpp +++ b/src/convert/ast_iterate.cpp @@ -151,8 +151,8 @@ void CASTIterator::handle_function(AST::Path path, AST::Function& fcn) for( auto& arg : fcn.args() ) { handle_type(arg.second); - AST::Pattern pat(AST::Pattern::TagBind(), arg.first); - handle_pattern( pat, arg.second ); + // TODO: Check if pattern is irrefutable? + handle_pattern( arg.first, arg.second ); } if( fcn.code().is_valid() ) @@ -193,7 +193,7 @@ void CASTIterator::handle_struct(AST::Path path, AST::Struct& str) start_scope(); handle_params( str.params() ); for( auto& f : str.fields() ) - handle_type( f.second ); + handle_type( f.data ); end_scope(); } void CASTIterator::handle_enum(AST::Path path, AST::Enum& enm) @@ -201,7 +201,7 @@ void CASTIterator::handle_enum(AST::Path path, AST::Enum& enm) start_scope(); handle_params( enm.params() ); for( auto& f : enm.variants() ) - handle_type( f.second ); + handle_type( f.data ); end_scope(); } void CASTIterator::handle_trait(AST::Path path, AST::Trait& trait) diff --git a/src/convert/render.cpp b/src/convert/render.cpp index 338fdd06..ce64e600 100644 --- a/src/convert/render.cpp +++ b/src/convert/render.cpp @@ -24,7 +24,7 @@ void Render_CStruct(::std::ostream& os, const AST::CStruct& str) for(auto& f : str.fields()) { os << "\t"; - Render_Type(os, f.second, f.first.c_str()); + Render_Type(os, f.data, f.name.c_str()); os << ";\n"; } os << "}\n"; @@ -48,7 +48,8 @@ void Render_Crate(::std::ostream& os, const AST::Flat& crate) if( !is_first ) os << ", "; is_first = false; - Render_Type(os, f.second, f.first.c_str()); + // TODO: handle pattern + //Render_Type(os, f.second, f.first.c_str()); } os << ")\n{\n"; // Dump expression AST diff --git a/src/convert/typecheck_expr.cpp b/src/convert/typecheck_expr.cpp index c647ed54..3c39d9a4 100644 --- a/src/convert/typecheck_expr.cpp +++ b/src/convert/typecheck_expr.cpp @@ -184,8 +184,7 @@ void CTypeChecker::handle_function(AST::Path path, AST::Function& fcn) for( auto& arg : fcn.args() ) { handle_type(arg.second); - AST::Pattern pat(AST::Pattern::TagBind(), arg.first); - handle_pattern( pat, arg.second ); + handle_pattern( arg.first, arg.second ); } CTC_NodeVisitor nv(*this); @@ -230,8 +229,8 @@ void CTC_NodeVisitor::visit(AST::ExprNode_NamedValue& node) auto idx = p.bound_idx(); // Enum variant: // - Check that this variant takes no arguments - if( !enm.variants()[idx].second.is_unit() ) - throw ::std::runtime_error( FMT("Used a non-unit variant as a raw value - " << enm.variants()[idx].second)); + if( !enm.variants()[idx].data.is_unit() ) + throw ::std::runtime_error( FMT("Used a non-unit variant as a raw value - " << enm.variants()[idx].data)); // - Set output type to the enum (wildcard params, not default) AST::Path tp = p; tp.nodes().pop_back(); @@ -523,8 +522,8 @@ void CTC_NodeVisitor::visit(AST::ExprNode_CallPath& node) // 2. Create a pattern from the argument types and the format of the variant DEBUG("argtypes = [" << argtypes << "]"); ::std::vector item_args(enm.params().n_params()); - DEBUG("variant type = " << var.second << ""); - var.second.match_args( + DEBUG("variant type = " << var.data << ""); + var.data.match_args( TypeRef(TypeRef::TagTuple(), argtypes), [&](const char *name, const TypeRef& t) { DEBUG("Binding " << name << " to type " << t); diff --git a/src/dump_as_rust.cpp b/src/dump_as_rust.cpp new file mode 100644 index 00000000..1a0b426d --- /dev/null +++ b/src/dump_as_rust.cpp @@ -0,0 +1,290 @@ +/* + * MRustC - Mutabah's Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * dump_as_rust.cpp + * - Dumps the AST of a crate as rust code (annotated) + */ +#include "ast/expr.hpp" +#include + +class RustPrinter: + public AST::NodeVisitor +{ + ::std::ostream& m_os; + int m_indent_level; +public: + RustPrinter(::std::ostream& os): + m_os(os), + m_indent_level(0) + {} + + void handle_module(const AST::Module& mod); + void handle_struct(const AST::Struct& s); + void handle_enum(const AST::Enum& s); + void handle_trait(const AST::Trait& s); + + void handle_function(const AST::Item& f); + +private: + void print_params(const AST::TypeParams& params); + void print_bounds(const AST::TypeParams& params); + void print_pattern(const AST::Pattern& p); + + void inc_indent(); + RepeatLitStr indent(); + void dec_indent(); +}; + +void Dump_Rust(const char *Filename, const AST::Crate& crate) +{ + ::std::ofstream os(Filename); + RustPrinter printer(os); + printer.handle_module(crate.root_module()); +} + +void RustPrinter::handle_module(const AST::Module& mod) +{ + m_os << "\n"; + + for( const auto& sm : mod.submods() ) + { + m_os << indent() << (sm.second ? "pub " : "") << "mod " << sm.first.name() << " {\n"; + inc_indent(); + handle_module(sm.first); + dec_indent(); + m_os << indent() << "}\n"; + m_os << "\n"; + } + + + for( const auto& i : mod.structs() ) + { + m_os << indent() << (i.is_pub ? "pub " : "") << "struct " << i.name; + handle_struct(i.data); + } + + for( const auto& i : mod.enums() ) + { + m_os << indent() << (i.is_pub ? "pub " : "") << "enum " << i.name; + handle_enum(i.data); + } + + for( const auto& i : mod.traits() ) + { + m_os << indent() << (i.is_pub ? "pub " : "") << "trait " << i.name; + handle_trait(i.data); + } + + for( const auto& i : mod.statics() ) + { + m_os << indent() << (i.is_pub ? "pub " : ""); + switch( i.data.s_class() ) + { + case AST::Static::CONST: m_os << "const "; break; + case AST::Static::STATIC: m_os << "static "; break; + case AST::Static::MUT: m_os << "static mut "; break; + } + m_os << i.name << ": " << i.data.type() << " = "; + //handle_expr(i.data.value()); + m_os << ";\n"; + } + + for( const auto& i : mod.functions() ) + { + handle_function(i); + } +} + +void RustPrinter::print_params(const AST::TypeParams& params) +{ + if( params.n_params() > 0 ) + { + bool is_first = true; + m_os << "<"; + for( const auto& p : params.params() ) + { + if( !is_first ) + m_os << ", "; + m_os << p.name(); + is_first = false; + } + m_os << ">"; + } +} + +void RustPrinter::print_bounds(const AST::TypeParams& params) +{ + if( params.bounds().size() ) + { + m_os << indent() << "where\n"; + inc_indent(); + bool is_first = true; + + for( const auto& b : params.bounds() ) + { + if( !is_first ) + m_os << ", "; + is_first = false; + + m_os << indent() << b.name() << ": "; + m_os << "\n"; + } + + dec_indent(); + } +} + +void RustPrinter::print_pattern(const AST::Pattern& p) +{ + if( p.binding() != "" && p.type() == AST::Pattern::ANY ) { + m_os << p.binding(); + return; + } + + if( p.binding() != "" ) + m_os << p.binding() << " @ "; + switch(p.type()) + { + case AST::Pattern::ANY: + m_os << "_"; + break; + case AST::Pattern::VALUE: + m_os << p.node(); + break; + case AST::Pattern::MAYBE_BIND: + m_os << "/*?*/" << p.path(); + break; + case AST::Pattern::TUPLE_STRUCT: + m_os << p.path(); + case AST::Pattern::TUPLE: + m_os << "("; + for(const auto& sp : p.sub_patterns()) + print_pattern(sp); + m_os << ")"; + break; + } +} + +void RustPrinter::handle_struct(const AST::Struct& s) +{ + print_params(s.params()); + + if( s.fields().size() == 0 ) + { + m_os << "()\n"; + print_bounds(s.params()); + m_os << indent() << ";\n"; + } + else if( s.fields().size() == 1 && s.fields()[0].name == "" ) + { + m_os << "(" << "" <<")\n"; + print_bounds(s.params()); + m_os << indent() << ";\n"; + } + else + { + m_os << "\n"; + print_bounds(s.params()); + + m_os << indent() << "{\n"; + inc_indent(); + for( const auto& i : s.fields() ) + { + m_os << indent() << (i.is_pub ? "pub " : "") << i.name << ": " << i.data.print_pretty() << "\n"; + } + dec_indent(); + m_os << indent() << "}\n"; + } + m_os << "\n"; +} + +void RustPrinter::handle_enum(const AST::Enum& s) +{ + print_params(s.params()); + m_os << "\n"; + print_bounds(s.params()); + + m_os << indent() << "{\n"; + inc_indent(); + for( const auto& i : s.variants() ) + { + m_os << indent() << i.name; + if( i.data.sub_types().size() ) + m_os << i.data.print_pretty(); + m_os << ",\n"; + } + dec_indent(); + m_os << indent() << "}\n"; + m_os << "\n"; +} + +void RustPrinter::handle_trait(const AST::Trait& s) +{ + print_params(s.params()); + m_os << "\n"; + print_bounds(s.params()); + + m_os << indent() << "{\n"; + inc_indent(); + + for( const auto& i : s.types() ) + { + m_os << indent() << "type " << i.name << "\n"; + } + for( const auto& i : s.functions() ) + { + handle_function(i); + } + + dec_indent(); + m_os << indent() << "}\n"; + m_os << "\n"; +} + +void RustPrinter::handle_function(const AST::Item& f) +{ + m_os << indent() << (f.is_pub ? "pub " : "") << "fn " << f.name; + print_params(f.data.params()); + m_os << "("; + bool is_first = true; + for( const auto& a : f.data.args() ) + { + if( !is_first ) + m_os << ", "; + print_pattern( a.first ); + m_os << ": " << a.second.print_pretty(); + is_first = false; + } + m_os << ")"; + if( !f.data.rettype().is_unit() ) + { + m_os << " -> " << f.data.rettype().print_pretty(); + } + + if( f.data.code().is_valid() ) + { + m_os << "\n"; + print_bounds(f.data.params()); + + m_os << indent() << f.data.code() << "\n"; + } + else + { + print_bounds(f.data.params()); + m_os << ";\n"; + } +} + +void RustPrinter::inc_indent() +{ + m_indent_level ++; +} +RepeatLitStr RustPrinter::indent() +{ + return RepeatLitStr { " ", m_indent_level }; +} +void RustPrinter::dec_indent() +{ + m_indent_level --; +} diff --git a/src/include/main_bindings.hpp b/src/include/main_bindings.hpp index b7161edd..fef57184 100644 --- a/src/include/main_bindings.hpp +++ b/src/include/main_bindings.hpp @@ -12,5 +12,7 @@ extern void Typecheck_GenericParams(AST::Crate& crate); extern void Typecheck_Expr(AST::Crate& crate); extern AST::Flat Convert_Flatten(const AST::Crate& crate); +extern void Dump_Rust(const char *Filename, const AST::Crate& crate); + #endif diff --git a/src/main.cpp b/src/main.cpp index 3c2a2787..9e533139 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -75,11 +75,12 @@ int main(int argc, char *argv[]) outfile += ".o"; } - Serialiser_TextTree s_tt(::std::cout); - Serialiser& s = s_tt; + //Serialiser_TextTree s_tt(::std::cout); + //Serialiser& s = s_tt; try { AST::Crate crate = Parse_Crate(infile); + crate.post_parse(); //s << crate; @@ -98,6 +99,8 @@ int main(int argc, char *argv[]) // > Forward pass first Typecheck_Expr(crate); + Dump_Rust( FMT(outfile << ".rs").c_str(), crate ); + if( strcmp(emit_type, "ast") == 0 ) { ::std::ofstream os(outfile); @@ -116,5 +119,10 @@ int main(int argc, char *argv[]) ::std::cerr << "Parser Error: " << e.what() << ::std::endl; return 2; } + catch(const ::std::exception& e) + { + ::std::cerr << "Misc Error: " << e.what() << ::std::endl; + return 2; + } return 0; } diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index e91a8b26..91cedabd 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -325,30 +325,43 @@ ExprNodeP Parse_IfStmt(TokenStream& lex) return NEWNODE( AST::ExprNode_If, ::std::move(cond), ::std::move(code), ::std::move(altcode) ); } +ExprNodeP Parse_Expr_Match(TokenStream& lex) +{ + TRACE_FUNCTION; + Token tok; + + // 1. Get expression + ExprNodeP switch_val = Parse_Expr1(lex); + GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN); + + ::std::vector< ::std::pair > arms; + do { + if( GET_TOK(tok, lex) == TOK_BRACE_CLOSE ) + break; + lex.putback(tok); + AST::Pattern pat = Parse_Pattern(lex); + + GET_CHECK_TOK(tok, lex, TOK_FATARROW); + + bool opt_semicolon = false; + ExprNodeP val = Parse_Stmt(lex, opt_semicolon); + + arms.push_back( ::std::make_pair( ::std::move(pat), ::std::move(val) ) ); + } while( GET_TOK(tok, lex) == TOK_COMMA ); + CHECK_TOK(tok, TOK_BRACE_CLOSE); + + return NEWNODE( AST::ExprNode_Match, ::std::move(switch_val), ::std::move(arms) ); +} + // 0.5: Blocks ExprNodeP Parse_ExprBlocks(TokenStream& lex) { + TRACE_FUNCTION; Token tok; switch( GET_TOK(tok, lex) ) { - case TOK_RWORD_MATCH: { - // 1. Get expression - ExprNodeP switch_val = Parse_Expr1(lex); - GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN); - ::std::vector< ::std::pair> > arms; - do { - if( GET_TOK(tok, lex) == TOK_BRACE_CLOSE ) - break; - lex.putback(tok); - AST::Pattern pat = Parse_Pattern(lex); - GET_CHECK_TOK(tok, lex, TOK_FATARROW); - bool opt_semicolon = false; - ExprNodeP val = Parse_Stmt(lex, opt_semicolon); - arms.push_back( ::std::make_pair( ::std::move(pat), ::std::move(val) ) ); - } while( GET_TOK(tok, lex) == TOK_COMMA ); - CHECK_TOK(tok, TOK_BRACE_CLOSE); - return NEWNODE( AST::ExprNode_Match, ::std::move(switch_val), ::std::move(arms) ); - } + case TOK_RWORD_MATCH: + return Parse_Expr_Match(lex); case TOK_RWORD_IF: // TODO: if let return Parse_IfStmt(lex); diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 2c559d84..2b4126e9 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -8,6 +8,8 @@ unsigned int TraceLog::depth = 0; +extern AST::Pattern Parse_Pattern(TokenStream& lex); + ::std::vector Parse_Path_GenericList(TokenStream& lex) { TRACE_FUNCTION; @@ -317,19 +319,20 @@ AST::Function Parse_FunctionDef(TokenStream& lex, bool allow_no_code=false) { // Unbound method } - ::std::vector args; + + AST::Function::Arglist args; if( tok.type() != TOK_PAREN_CLOSE ) { lex.putback(tok); // Argument list do { - GET_CHECK_TOK(tok, lex, TOK_IDENT); - ::std::string name = tok.str(); + AST::Pattern pat = Parse_Pattern(lex); + GET_CHECK_TOK(tok, lex, TOK_COLON); TypeRef type = Parse_Type(lex); - args.push_back( ::std::make_pair(name, type) ); - tok = lex.getToken(); - } while( tok.type() == TOK_COMMA ); + + args.push_back( ::std::make_pair( ::std::move(pat), ::std::move(type) ) ); + } while( GET_TOK(tok, lex) == TOK_COMMA ); CHECK_TOK(tok, TOK_PAREN_CLOSE); } else { @@ -437,11 +440,12 @@ void Parse_Struct(AST::Module& mod, TokenStream& lex, const bool is_public, cons ::std::vector items; while( (tok = lex.getToken()).type() != TOK_BRACE_CLOSE ) { + bool is_pub = false; CHECK_TOK(tok, TOK_IDENT); ::std::string name = tok.str(); GET_CHECK_TOK(tok, lex, TOK_COLON); TypeRef type = Parse_Type(lex); - items.push_back( ::std::make_pair(name, type) ); + items.push_back( AST::StructItem( ::std::move(name), ::std::move(type), is_pub ) ); tok = lex.getToken(); if(tok.type() == TOK_BRACE_CLOSE) break; @@ -556,11 +560,11 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const ::std::vector met } while( GET_TOK(tok, lex) == TOK_COMMA ); CHECK_TOK(tok, TOK_PAREN_CLOSE); GET_TOK(tok, lex); - variants.push_back( AST::StructItem(::std::move(name), TypeRef(TypeRef::TagTuple(), ::std::move(types))) ); + variants.push_back( AST::StructItem(::std::move(name), TypeRef(TypeRef::TagTuple(), ::std::move(types)), true) ); } else { - variants.push_back( AST::StructItem(::std::move(name), TypeRef(TypeRef::TagUnit())) ); + variants.push_back( AST::StructItem(::std::move(name), TypeRef(TypeRef::TagUnit()), true) ); } if( tok.type() != TOK_COMMA ) diff --git a/src/types.cpp b/src/types.cpp index 33b564dd..445f394c 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -64,6 +64,7 @@ bool TypeRef::deref(bool is_implicit) case TypeRef::ASSOCIATED: throw ::std::runtime_error("TODO: TypeRef::deref on ASSOCIATED"); } + throw ::std::runtime_error("BUGCHECK: Fell off end of TypeRef::deref"); } /// Merge the contents of the passed type with this type @@ -72,14 +73,15 @@ bool TypeRef::deref(bool is_implicit) void TypeRef::merge_with(const TypeRef& other) { // Ignore if other is wildcard - if( other.m_class == TypeRef::ANY ) { - assert(other.m_inner_types.size() == 0 && "TODO: merge_with on bounded _"); - return; - } + //if( other.m_class == TypeRef::ANY ) { + // assert(other.m_inner_types.size() == 0 && "TODO: merge_with on bounded _"); + // return; + //} - // If this is a wildcard, then replace with the othet type + // If this is a wildcard, then replace with the other type if( m_class == TypeRef::ANY ) { - assert(m_inner_types.size() == 0 && "TODO: merge_with on bounded _"); + if( m_inner_types.size() && m_inner_types.size() != other.m_inner_types.size() ) + throw ::std::runtime_error("TypeRef::merge_with - Handle bounded wildcards"); *this = other; return; } @@ -177,16 +179,19 @@ void TypeRef::resolve_args(::std::function fcn) /// This is used to handle extracting types passsed to methods/enum variants void TypeRef::match_args(const TypeRef& other, ::std::function fcn) const { - // If the other type is a wildcard, early return - // - TODO - Might want to restrict the other type to be of the same form as this type - if( other.m_class == TypeRef::ANY ) - return; // If this type is a generic, then call the closure with the other type if( m_class == TypeRef::GENERIC ) { fcn( m_path[0].name().c_str(), other ); return ; } + // If the other type is a wildcard, early return + // - TODO - Might want to restrict the other type to be of the same form as this type + if( other.m_class == TypeRef::ANY ) + return; + + DEBUG("this = " << *this << ", other = " << other); + // Any other case, it's a "pattern" match if( m_class != other.m_class ) throw ::std::runtime_error("Type mismatch (class)"); @@ -215,11 +220,35 @@ void TypeRef::match_args(const TypeRef& other, ::std::function::" << tr.m_path[0].name(); os << "<" << tr.m_inner_types[0] << " as " << tr.m_inner_types[1] << ">::" << tr.m_path[0].name(); break; } - os << ")"; + //os << ")"; return os; } @@ -442,3 +469,54 @@ SERIALISE_TYPE(TypeRef::, "TypeRef", { m_size_expr.reset(); s.item( m_path ); }) + + +void PrettyPrintType::print(::std::ostream& os) const +{ + switch(m_type.m_class) + { + case TypeRef::ANY: + os << "_"; + if( m_type.m_inner_types.size() ) { + os << "/* : " << m_type.m_inner_types << "*/"; + } + break; + case TypeRef::UNIT: + os << "()"; + break; + case TypeRef::PRIMITIVE: + os << m_type.m_core_type; + break; + case TypeRef::TUPLE: + os << "("; + for(const auto& t : m_type.m_inner_types) + os << t.print_pretty() << ","; + os << ")"; + break; + case TypeRef::REFERENCE: + os << "&" << (m_type.m_is_inner_mutable ? "mut " : "") << m_type.m_inner_types[0].print_pretty(); + break; + case TypeRef::POINTER: + os << "*" << (m_type.m_is_inner_mutable ? "mut" : "const") << " " << m_type.m_inner_types[0].print_pretty(); + break; + case TypeRef::ARRAY: + os << "[" << m_type.m_inner_types[0].print_pretty() << ", " << m_type.m_size_expr << "]"; + break; + case TypeRef::GENERIC: + os << m_type.m_path[0].name(); + break; + case TypeRef::PATH: + os << m_type.m_path; + break; + case TypeRef::ASSOCIATED: + os << "<" << m_type.m_inner_types[0].print_pretty() << " as " << m_type.m_inner_types[1].print_pretty() << ">::" << m_type.m_path[0].name(); + break; + } + +} + +::std::ostream& operator<<(::std::ostream& os, const PrettyPrintType& v) +{ + v.print(os); + return os; +} diff --git a/src/types.hpp b/src/types.hpp index 2cbbd0bb..4864e703 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -24,6 +24,19 @@ class TypeBounds }; +class PrettyPrintType +{ + const TypeRef& m_type; +public: + PrettyPrintType(const TypeRef& ty): + m_type(ty) + {} + + void print(::std::ostream& os) const; + + friend ::std::ostream& operator<<(::std::ostream& os, const PrettyPrintType& v); +}; + /// A type class TypeRef: public Serialisable @@ -31,6 +44,7 @@ class TypeRef: /// Class enum Class { ANY, //< '_' - Wildcard + //BOUNDED, //< '_: Traits' - Bounded type (a resolved type parameter usually) UNIT, //< '()' - Unit / void PRIMITIVE, //< Any primitive (builtin type) TUPLE, @@ -138,7 +152,9 @@ public: /// Returns true if the type is fully known (all sub-types are not wildcards) bool is_concrete() const; + bool is_unbounded() const { return m_class == ANY && m_inner_types.size() == 0; } bool is_wildcard() const { return m_class == ANY; } + bool is_unit() const { return m_class == UNIT; } bool is_path() const { return m_class == PATH; } bool is_type_param() const { return m_class == GENERIC; } @@ -154,7 +170,11 @@ public: bool operator==(const TypeRef& x) const; bool operator!=(const TypeRef& x) const { return !(*this == x); } - + + PrettyPrintType print_pretty() const { return PrettyPrintType(*this); } + + friend class PrettyPrintType; + friend ::std::ostream& operator<<(::std::ostream& os, const TypeRef& tr); static const char* class_name(TypeRef::Class c); -- cgit v1.2.3