summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--src/ast/ast.cpp193
-rw-r--r--src/ast/ast.hpp26
-rw-r--r--src/ast/expr.cpp178
-rw-r--r--src/ast/expr.hpp76
-rw-r--r--src/ast/path.cpp25
-rw-r--r--src/ast/path.hpp2
-rw-r--r--src/ast/pattern.hpp31
-rw-r--r--src/convert/ast_iterate.cpp8
-rw-r--r--src/convert/render.cpp5
-rw-r--r--src/convert/typecheck_expr.cpp11
-rw-r--r--src/dump_as_rust.cpp290
-rw-r--r--src/include/main_bindings.hpp2
-rw-r--r--src/main.cpp12
-rw-r--r--src/parse/expr.cpp49
-rw-r--r--src/parse/root.cpp22
-rw-r--r--src/types.cpp116
-rw-r--r--src/types.hpp22
18 files changed, 867 insertions, 204 deletions
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<TypeRef>& 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&> Impl::matches(const TypeRef& trait, const TypeRef& type)
+{
+ DEBUG("this = " << *this);
+ if( m_params.n_params() )
+ {
+ ::std::vector<TypeRef> 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<Impl&>(i.second);
+ }
+ }
+ m_concrete_impls.push_back( make_pair(param_types, this->make_concrete(param_types)) );
+ return ::rust::option<Impl&>( 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<Impl&>( *this );
+ }
+ }
+ return ::rust::option<Impl&>();
+}
::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<void(Module& mod)> 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<Impl&> 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<Impl&> oimpl = impl.matches(trait, type);
+ if( oimpl.is_some() )
{
- return ::rust::option<Impl&>(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<TypeRef>& 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<TypeRef>& 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<TypeRef>& types) const
+{
+ return check_params( crate, const_cast< ::std::vector<TypeRef>&>(types), false );
+}
+bool TypeParams::check_params(Crate& crate, ::std::vector<TypeRef>& 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.size()<<" passed, expecting "<< m_params.size()<<")"));
+ }
+ else if( types.size() < m_params.size() )
+ {
+ if( allow_infer )
+ {
+ while( types.size() < m_params.size() )
+ {
+ types.push_back( m_params[types.size()].get_default() );
+ }
+ }
+ else
+ {
+ throw ::std::runtime_error(FMT("Too few generic params, (" << types.size() << " passed, expecting " << m_params.size() << ")"));
+ }
+ }
+ else
+ {
+ // Counts are good, time to validate types
+ }
+
+ for( unsigned int i = 0; i < types.size(); i ++ )
+ {
+ auto& type = types[i];
+ auto& param = m_params[i].name();
+ if( type.is_wildcard() )
+ {
+ for( const auto& bound : m_bounds )
+ {
+ if( bound.is_trait() && bound.name() == param )
+ {
+ const auto& trait = bound.type();
+ const auto& ty_traits = type.traits();
+
+ auto it = ::std::find(ty_traits.begin(), ty_traits.end(), trait);
+ if( it == ty_traits.end() )
+ {
+ throw ::std::runtime_error( FMT("No matching impl of "<<trait<<" for "<<type));
+ }
+ }
+ }
+ }
+ else
+ {
+ // Not a wildcard!
+ // Check that the type fits the bounds applied to it
+ for( const auto& bound : m_bounds )
+ {
+ if( bound.is_trait() && bound.name() == param )
+ {
+ const auto& trait = bound.type();
+ // Check if 'type' impls 'trait'
+ if( !crate.find_impl(type, trait).is_some() )
+ {
+ throw ::std::runtime_error( FMT("No matching impl of "<<trait<<" for "<<type));
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
::std::ostream& operator<<(::std::ostream& os, const TypeParams& tps)
{
//return os << "TypeParams({" << tps.m_params << "}, {" << tps.m_bounds << "})";
diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp
index 40a44b78..64726ecd 100644
--- a/src/ast/ast.hpp
+++ b/src/ast/ast.hpp
@@ -43,6 +43,7 @@ public:
void setDefault(TypeRef type);
const ::std::string& name() const { return m_name; }
+ const TypeRef& get_default() const { return m_default; }
bool is_type() const { return m_class == TYPE; }
@@ -99,6 +100,8 @@ public:
}
int find_name(const char* name) const;
+ bool check_params(Crate& crate, const ::std::vector<TypeRef>& types) const;
+ bool check_params(Crate& crate, ::std::vector<TypeRef>& types, bool allow_infer) const;
friend ::std::ostream& operator<<(::std::ostream& os, const TypeParams& tp);
SERIALISABLE_PROTOTYPES();
@@ -136,7 +139,7 @@ struct Item:
template <typename T>
using ItemList = ::std::vector<Item<T> >;
-typedef ::std::pair< ::std::string, TypeRef> StructItem;
+typedef Item<TypeRef> 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<StructItem> Arglist;
+ typedef ::std::vector< ::std::pair<AST::Pattern,TypeRef> > Arglist;
private:
Class m_fcn_class;
@@ -344,6 +349,8 @@ class Impl:
ItemList<TypeRef> m_types;
ItemList<Function> m_functions;
+
+ ::std::vector< ::std::pair< ::std::vector<TypeRef>, 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<Function>& functions() { return m_functions; }
ItemList<TypeRef>& types() { return m_types; }
+
+ Impl make_concrete(const ::std::vector<TypeRef>& types) const;
+
+ ::rust::option<Impl&> 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<Impl&> 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> 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<ExprNode> 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 << "["<<path.m_crate<<"]";
+ os << "{"<<path.m_crate<<"}";
for(const auto& n : path.m_nodes)
os << n;
break;
diff --git a/src/ast/path.hpp b/src/ast/path.hpp
index 5325f8ef..cfdf16c2 100644
--- a/src/ast/path.hpp
+++ b/src/ast/path.hpp
@@ -38,6 +38,7 @@ public:
const ::std::vector<TypeRef>& 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<ExprNode> m_node;
::std::vector<Pattern> 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<TypeRef> 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 <main_bindings.hpp>
+
+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<AST::Function>& 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<AST::Function>& 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<AST::Pattern, ExprNodeP> > 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<AST::Pattern, ::std::unique_ptr<ExprNode>> > 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<TypeRef> 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<AST::StructItem> 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<AST::StructItem> 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<AST::MetaItem> 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<TypeRef(const char*)> fcn)
/// This is used to handle extracting types passsed to methods/enum variants
void TypeRef::match_args(const TypeRef& other, ::std::function<void(const char*,const TypeRef&)> 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<void(const char*,
m_inner_types[0].match_args( other.m_inner_types[0], fcn );
break;
case TypeRef::ARRAY:
- throw ::std::runtime_error("TODO: TypeRef::match_args on ARRAY");
+ m_inner_types[0].match_args( other.m_inner_types[0], fcn );
+ if(m_size_expr.get())
+ {
+ throw ::std::runtime_error("TODO: Sized array match_args");
+ }
+ break;
case TypeRef::GENERIC:
throw ::std::runtime_error("Encountered GENERIC in match_args");
case TypeRef::PATH:
- throw ::std::runtime_error("TODO: TypeRef::match_args on PATH");
+ if( m_path.size() != other.m_path.size() )
+ throw ::std::runtime_error("Type mismatch (path size)");
+ for( unsigned int i = 0; i < m_path.size(); i++ )
+ {
+ auto& pn1 = m_path[i];
+ auto& pn2 = other.m_path[i];
+ if( pn1.name() != pn2.name() )
+ throw ::std::runtime_error("Type mismatch (path component)");
+
+ if( pn1.args().size() != pn2.args().size() )
+ throw ::std::runtime_error("Type mismatch (path component param count)");
+
+ for( unsigned int j = 0; j < pn1.args().size(); j ++ )
+ {
+ auto& t1 = pn1.args()[j];
+ auto& t2 = pn2.args()[j];
+ t1.match_args( t2, fcn );
+ }
+ }
+ break;
case TypeRef::ASSOCIATED:
throw ::std::runtime_error("TODO: TypeRef::match_args on ASSOCIATED");
}
@@ -309,14 +338,14 @@ bool TypeRef::operator==(const TypeRef& x) const
}
::std::ostream& operator<<(::std::ostream& os, const TypeRef& tr) {
- os << "TypeRef(";
+ //os << "TypeRef(";
switch(tr.m_class)
{
case TypeRef::ANY:
//os << "TagAny";
os << "_";
if( tr.m_inner_types.size() ) {
- os << ": {" << tr.m_inner_types << "}";
+ os << ": " << tr.m_inner_types << "";
}
break;
case TypeRef::UNIT:
@@ -340,21 +369,19 @@ bool TypeRef::operator==(const TypeRef& x) const
os << "*" << (tr.m_is_inner_mutable ? "mut" : "const") << " " << tr.m_inner_types[0];
break;
case TypeRef::ARRAY:
- os << "TagSizedArray, " << tr.m_inner_types[0] << ", " << tr.m_size_expr;
+ os << "[" << tr.m_inner_types[0] << "; " << tr.m_size_expr << "]";
break;
case TypeRef::GENERIC:
- os << "TagArg, " << tr.m_path[0].name();
+ os << "/* arg */ " << tr.m_path[0].name();
break;
case TypeRef::PATH:
- //os << "TagPath, " << tr.m_path;
os << tr.m_path;
break;
case TypeRef::ASSOCIATED:
- //os << "TagAssoc, <" << tr.m_inner_types[0] << " as " << tr.m_inner_types[1] << ">::" << 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);