summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast/ast.cpp18
-rw-r--r--src/ast/ast.hpp44
-rw-r--r--src/ast/expr.cpp4
-rw-r--r--src/ast/expr.hpp1
-rw-r--r--src/convert/ast_iterate.cpp3
-rw-r--r--src/convert/typecheck_bounds.cpp4
-rw-r--r--src/convert/typecheck_expr.cpp10
-rw-r--r--src/convert/typecheck_params.cpp20
-rw-r--r--src/dump_as_rust.cpp6
-rw-r--r--src/macros.cpp76
-rw-r--r--src/parse/expr.cpp7
-rw-r--r--src/parse/root.cpp306
-rw-r--r--src/types.hpp7
13 files changed, 349 insertions, 157 deletions
diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp
index 0caa41a2..870d4eff 100644
--- a/src/ast/ast.cpp
+++ b/src/ast/ast.cpp
@@ -621,11 +621,14 @@ SERIALISE_TYPE(TypeParam::, "AST_TypeParam", {
::std::ostream& operator<<(::std::ostream& os, const GenericBound& x)
{
- //return os << "GenericBound(" << x.m_argname << "," << x.m_lifetime << "," << x.m_trait << ")";
- return os << x.m_argname << ": ('" << x.m_lifetime << " + " << x.m_trait << ")";
+ os << x.m_type << ": ";
+ if( x.m_lifetime != "" )
+ return os << "'" << x.m_lifetime;
+ else
+ return os << x.m_trait;
}
SERIALISE_TYPE_S(GenericBound, {
- s.item(m_argname);
+ s.item(m_type);
s.item(m_lifetime);
s.item(m_trait);
})
@@ -680,13 +683,14 @@ bool TypeParams::check_params(Crate& crate, ::std::vector<TypeRef>& types, bool
{
auto& type = types[i];
auto& param = m_params[i].name();
+ TypeRef test(TypeRef::TagArg(), param);
if( type.is_wildcard() )
{
for( const auto& bound : m_bounds )
{
- if( bound.is_trait() && bound.name() == param )
+ if( bound.is_trait() && bound.test() == test )
{
- const auto& trait = bound.type();
+ const auto& trait = bound.bound();
const auto& ty_traits = type.traits();
auto it = ::std::find(ty_traits.begin(), ty_traits.end(), trait);
@@ -703,9 +707,9 @@ bool TypeParams::check_params(Crate& crate, ::std::vector<TypeRef>& types, bool
// Check that the type fits the bounds applied to it
for( const auto& bound : m_bounds )
{
- if( bound.is_trait() && bound.name() == param )
+ if( bound.is_trait() && bound.test() == test )
{
- const auto& trait = bound.type();
+ const auto& trait = bound.bound();
// Check if 'type' impls 'trait'
if( !crate.find_impl(type, trait).is_some() )
{
diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp
index 81a0dbd6..8928aa97 100644
--- a/src/ast/ast.hpp
+++ b/src/ast/ast.hpp
@@ -41,7 +41,10 @@ public:
m_class( is_lifetime ? LIFETIME : TYPE ),
m_name( ::std::move(name) )
{}
- void setDefault(TypeRef type);
+ void setDefault(TypeRef type) {
+ assert(m_default.is_wildcard());
+ m_default = ::std::move(type);
+ }
const ::std::string& name() const { return m_name; }
const TypeRef& get_default() const { return m_default; }
@@ -55,25 +58,32 @@ public:
class GenericBound:
public Serialisable
{
- ::std::string m_argname;
+ TypeRef m_type;
+
::std::string m_lifetime;
- TypeRef m_trait;
+
+ bool m_optional;
+ AST::Path m_trait;
public:
+
GenericBound() {}
- GenericBound(::std::string argname, ::std::string lifetime):
- m_argname(argname),
+ GenericBound(TypeRef type, ::std::string lifetime):
+ m_type( ::std::move(type) ),
m_lifetime(lifetime)
{ }
- GenericBound(::std::string argname, TypeRef trait):
- m_argname(argname),
+ GenericBound(TypeRef type, AST::Path trait, bool optional=false):
+ m_type( ::std::move(type) ),
+ m_optional(optional),
m_trait( ::std::move(trait) )
{ }
bool is_trait() const { return m_lifetime == ""; }
- const ::std::string& name() const { return m_argname; }
- const TypeRef& type() const { return m_trait; }
+ const ::std::string& lifetime() const { return m_lifetime; }
+ const TypeRef& test() const { return m_type; }
+ const AST::Path& bound() const { return m_trait; }
- TypeRef& type() { return m_trait; }
+ TypeRef& test() { return m_type; }
+ AST::Path& bound() { return m_trait; }
friend ::std::ostream& operator<<(::std::ostream& os, const GenericBound& x);
SERIALISABLE_PROTOTYPES();
@@ -394,16 +404,26 @@ class Impl:
TypeRef m_trait;
TypeRef m_type;
+ bool m_is_negative;
ItemList<TypeRef> m_types;
ItemList<Function> m_functions;
::std::vector< ::std::pair< ::std::vector<TypeRef>, Impl > > m_concrete_impls;
public:
- Impl() {}
+ Impl(): m_is_negative(false) {}
Impl(TypeParams params, TypeRef impl_type, TypeRef trait_type):
m_params( move(params) ),
m_trait( move(trait_type) ),
- m_type( move(impl_type) )
+ m_type( move(impl_type) ),
+ m_is_negative(true)
+ {}
+
+ struct TagNegative {};
+ Impl(TagNegative, TypeParams params, TypeRef impl_type, TypeRef trait_type):
+ m_params( move(params) ),
+ m_trait( move(trait_type) ),
+ m_type( move(impl_type) ),
+ m_is_negative(true)
{}
void add_function(bool is_public, ::std::string name, Function fcn) {
diff --git a/src/ast/expr.cpp b/src/ast/expr.cpp
index 1246ad29..1f5eb377 100644
--- a/src/ast/expr.cpp
+++ b/src/ast/expr.cpp
@@ -454,6 +454,7 @@ void operator%(::Serialiser& s, const ExprNode_UniOp::Type t) {
_(INVERT)
_(BOX)
_(REF)
+ _(REFMUT)
#undef _
}
}
@@ -466,9 +467,10 @@ void operator%(::Deserialiser& s, enum ExprNode_UniOp::Type& t) {
_(INVERT)
_(BOX)
_(REF)
+ _(REFMUT)
+ #undef _
else
throw ::std::runtime_error( FMT("No uniop type for '" << n << "'") );
- #undef _
}
NODE(ExprNode_UniOp, {
s % m_type;
diff --git a/src/ast/expr.hpp b/src/ast/expr.hpp
index 121a1f09..21f67c2f 100644
--- a/src/ast/expr.hpp
+++ b/src/ast/expr.hpp
@@ -547,6 +547,7 @@ struct ExprNode_UniOp:
{
enum Type {
REF,
+ REFMUT,
BOX,
INVERT,
NEGATE,
diff --git a/src/convert/ast_iterate.cpp b/src/convert/ast_iterate.cpp
index 10eb4342..68c84a31 100644
--- a/src/convert/ast_iterate.cpp
+++ b/src/convert/ast_iterate.cpp
@@ -31,7 +31,8 @@ void CASTIterator::handle_params(AST::TypeParams& params)
}
for( auto& bound : params.bounds() )
{
- handle_type(bound.type());
+ handle_type(bound.test());
+ handle_path(bound.bound(), CASTIterator::MODE_TYPE);
}
}
diff --git a/src/convert/typecheck_bounds.cpp b/src/convert/typecheck_bounds.cpp
index 6a3fb4a7..3f3e6b8d 100644
--- a/src/convert/typecheck_bounds.cpp
+++ b/src/convert/typecheck_bounds.cpp
@@ -24,9 +24,9 @@ void CGenericBoundChecker::handle_params(AST::TypeParams& params)
{
if( bound.is_trait() )
{
- auto& trait = bound.type();
+ auto& trait = bound.bound();
DEBUG("trait = " << trait);
- if( not trait.is_path() or trait.path().binding_type() != AST::Path::TRAIT )
+ if( trait.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"));
diff --git a/src/convert/typecheck_expr.cpp b/src/convert/typecheck_expr.cpp
index d7f8afb1..6d88b1dd 100644
--- a/src/convert/typecheck_expr.cpp
+++ b/src/convert/typecheck_expr.cpp
@@ -114,9 +114,13 @@ void CTypeChecker::handle_params(AST::TypeParams& params)
for( const auto& bound : params.bounds() )
{
- int i = params.find_name(bound.name().c_str());
- assert(i >= 0);
- trs[bound.name()].add_trait( bound.type() );
+ if( bound.is_trait() && bound.test().is_type_param() )
+ {
+ const auto& name = bound.test().type_param();
+ int i = params.find_name(name.c_str());
+ assert(i >= 0);
+ trs[name].add_trait( bound.bound() );
+ }
}
assert(m_scopes.back().params.size() == 0);
diff --git a/src/convert/typecheck_params.cpp b/src/convert/typecheck_params.cpp
index 109713d4..b028c55f 100644
--- a/src/convert/typecheck_params.cpp
+++ b/src/convert/typecheck_params.cpp
@@ -20,8 +20,8 @@ public:
virtual void handle_params(AST::TypeParams& params) override;
private:
- bool has_impl_for_param(const ::std::string name, const TypeRef& trait) const;
- bool has_impl(const TypeRef& type, const TypeRef& trait) const;
+ bool has_impl_for_param(const ::std::string name, const AST::Path& trait) const;
+ bool has_impl(const TypeRef& type, const AST::Path& trait) const;
void check_generic_params(const AST::TypeParams& info, ::std::vector<TypeRef>& types, bool allow_infer = false);
};
@@ -36,7 +36,7 @@ public:
};
// === CODE ===
-bool CGenericParamChecker::has_impl_for_param(const ::std::string name, const TypeRef& trait) const
+bool CGenericParamChecker::has_impl_for_param(const ::std::string name, const AST::Path& trait) const
{
const AST::TypeParams* tps = nullptr;
// Locate params set that contains the passed name
@@ -60,12 +60,13 @@ bool CGenericParamChecker::has_impl_for_param(const ::std::string name, const Ty
}
// Search bound list for the passed trait
+ TypeRef param_type(TypeRef::TagArg(), name);
for( const auto& bound : tps->bounds() )
{
- if( bound.is_trait() && bound.name() == name )
+ if( bound.is_trait() && bound.test() == param_type )
{
- DEBUG("bound.type() {" << bound.type() << "} == trait {" << trait << "}");
- if( bound.type() == trait )
+ DEBUG("bound.type() {" << bound.bound() << "} == trait {" << trait << "}");
+ if( bound.bound() == trait )
return true;
}
}
@@ -75,7 +76,7 @@ bool CGenericParamChecker::has_impl_for_param(const ::std::string name, const Ty
DEBUG("No match in generics, returning failure");
return false;
}
-bool CGenericParamChecker::has_impl(const TypeRef& type, const TypeRef& trait) const
+bool CGenericParamChecker::has_impl(const TypeRef& type, const AST::Path& trait) const
{
DEBUG("(type = " << type << ", trait = " << trait << ")");
if( type.is_type_param() )
@@ -158,11 +159,12 @@ void CGenericParamChecker::check_generic_params(const AST::TypeParams& info, ::s
{
// Not a wildcard!
// Check that the type fits the bounds applied to it
+ TypeRef param_type(TypeRef::TagArg(), param);
for( const auto& bound : info.bounds() )
{
- if( bound.is_trait() && bound.name() == param )
+ if( bound.is_trait() && bound.test() == param_type )
{
- const auto& trait = bound.type();
+ const auto& trait = bound.bound();
// Check if 'type' impls 'trait'
if( !has_impl(type, trait) )
{
diff --git a/src/dump_as_rust.cpp b/src/dump_as_rust.cpp
index 471a0479..d8d5ad13 100644
--- a/src/dump_as_rust.cpp
+++ b/src/dump_as_rust.cpp
@@ -623,7 +623,11 @@ void RustPrinter::print_bounds(const AST::TypeParams& params)
m_os << ", ";
is_first = false;
- m_os << indent() << b.name() << ": ";
+ m_os << indent() << b.test() << ": ";
+ if( b.is_trait() )
+ m_os << b.bound();
+ else
+ m_os << b.lifetime();
m_os << "\n";
}
diff --git a/src/macros.cpp b/src/macros.cpp
index f375c0d4..b2528755 100644
--- a/src/macros.cpp
+++ b/src/macros.cpp
@@ -46,6 +46,7 @@ private:
/// Iteration counts for each layer
::std::vector<size_t> m_layer_counts;
+ Token m_next_token; // used for inserting a single token into the stream
::std::unique_ptr<TTStream> m_ttstream;
public:
@@ -73,6 +74,7 @@ public:
virtual Position getPosition() const override;
virtual Token realGetToken() override;
private:
+ const MacroRuleEnt& getCurLayerEnt() const;
const ::std::vector<MacroRuleEnt>* getCurLayer() const;
void prep_counts();
};
@@ -352,6 +354,13 @@ Position MacroExpander::getPosition() const
}
Token MacroExpander::realGetToken()
{
+ // Use m_next_token first
+ DEBUG("m_next_token = " << m_next_token);
+ if( m_next_token.type() != TOK_NULL )
+ {
+ return ::std::move(m_next_token);
+ }
+ // Then try m_ttstream
if( m_ttstream.get() )
{
DEBUG("TTStream set");
@@ -380,34 +389,32 @@ Token MacroExpander::realGetToken()
const auto& ent = ents[idx];
// - If not, just handle the next entry
// Check type of entry
- if( ent.name != "" )
+ if( ent.name == "*crate" ) {
+ // HACK: Handle $crate with a special name
+ DEBUG("Crate name hack");
+ m_ttstream.reset( new TTStream(m_crate_path) );
+ return m_ttstream->getToken();
+ }
+ else if( ent.name != "" )
{
// - Name
- // HACK: Handle $crate with a special name
- if( ent.name == "*crate" ) {
- DEBUG("Crate name hack");
- m_ttstream.reset( new TTStream(m_crate_path) );
- return m_ttstream->getToken();
- }
- else {
- const size_t iter_idx = m_offsets.back().second;
- const auto tt_i = m_mappings.equal_range( ::std::make_pair(layer, ent.name.c_str()) );
- if( tt_i.first == tt_i.second )
- throw ParseError::Generic( FMT("Cannot find mapping name: " << ent.name << " for layer " << layer) );
-
- size_t i = 0;
- for( auto it = tt_i.first; it != tt_i.second; it ++ )
+ const size_t iter_idx = m_offsets.back().second;
+ const auto tt_i = m_mappings.equal_range( ::std::make_pair(layer, ent.name.c_str()) );
+ if( tt_i.first == tt_i.second )
+ throw ParseError::Generic( FMT("Cannot find mapping name: " << ent.name << " for layer " << layer) );
+
+ size_t i = 0;
+ for( auto it = tt_i.first; it != tt_i.second; it ++ )
+ {
+ if( i == iter_idx )
{
- if( i == iter_idx )
- {
- DEBUG(ent.name << " #" << i << " - Setting TT");
- m_ttstream.reset( new TTStream(it->second) );
- return m_ttstream->getToken();
- }
- i ++;
+ DEBUG(ent.name << " #" << i << " - Setting TT");
+ m_ttstream.reset( new TTStream(it->second) );
+ return m_ttstream->getToken();
}
- throw ParseError::Generic( FMT("Cannot find mapping name: " << ent.name << " for layer " << layer) );
+ i ++;
}
+ throw ParseError::Generic( FMT("Too few instances of " << ent.name << " at layer " << layer) );
}
else if( ent.subpats.size() != 0 )
{
@@ -434,6 +441,13 @@ Token MacroExpander::realGetToken()
DEBUG("Restart layer");
m_offsets.back().first = 0;
m_offsets.back().second ++;
+
+ auto& loop_layer = getCurLayerEnt();
+ assert(loop_layer.subpats.size());
+ if( loop_layer.tok.type() != TOK_NULL ) {
+ DEBUG("- Separator token = " << loop_layer.tok);
+ return loop_layer.tok;
+ }
// Fall through and restart layer
}
else
@@ -484,6 +498,22 @@ void MacroExpander::prep_counts()
m_layer_counts.push_back(l.count);
}
}
+const MacroRuleEnt& MacroExpander::getCurLayerEnt() const
+{
+ assert( m_offsets.size() > 1 );
+
+ const ::std::vector<MacroRuleEnt>* ents = &m_root_contents;
+ for( unsigned int i = 0; i < m_offsets.size()-2; i ++ )
+ {
+ unsigned int ofs = m_offsets[i].first;
+ //DEBUG(i << " ofs=" << ofs << " / " << ents->size());
+ assert( ofs > 0 && ofs <= ents->size() );
+ ents = &(*ents)[ofs-1].subpats;
+ //DEBUG("ents = " << ents);
+ }
+ return (*ents)[m_offsets[m_offsets.size()-2].first-1];
+
+}
const ::std::vector<MacroRuleEnt>* MacroExpander::getCurLayer() const
{
assert( m_offsets.size() > 0 );
diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp
index d0d5bc7f..a8a16c7d 100644
--- a/src/parse/expr.cpp
+++ b/src/parse/expr.cpp
@@ -698,7 +698,12 @@ ExprNodeP Parse_Expr12(TokenStream& lex)
case TOK_RWORD_BOX:
return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::BOX, Parse_Expr12(lex) );
case TOK_AMP:
- return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::REF, Parse_Expr12(lex) );
+ if( GET_TOK(tok, lex) == TOK_RWORD_MUT )
+ return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::REFMUT, Parse_Expr12(lex) );
+ else {
+ lex.putback(tok);
+ return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::REF, Parse_Expr12(lex) );
+ }
default:
lex.putback(tok);
return Parse_ExprFC(lex);
diff --git a/src/parse/root.cpp b/src/parse/root.cpp
index c0257910..0e22b117 100644
--- a/src/parse/root.cpp
+++ b/src/parse/root.cpp
@@ -11,6 +11,42 @@ extern AST::Pattern Parse_Pattern(TokenStream& lex);
AST::MetaItem Parse_MetaItem(TokenStream& lex);
void Parse_ModRoot(TokenStream& lex, AST::Crate& crate, AST::Module& mod, LList<AST::Module*> *prev_modstack, const ::std::string& path);
+AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode);
+AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generic_mode);
+::std::vector<TypeRef> Parse_Path_GenericList(TokenStream& lex);
+AST::Path Parse_PathFrom(TokenStream& lex, AST::Path path, eParsePathGenericMode generic_mode);
+
+AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode)
+{
+ Token tok;
+ if( GET_TOK(tok, lex) == TOK_DOUBLE_COLON )
+ return Parse_Path(lex, true, generic_mode);
+ else
+ {
+ lex.putback(tok);
+ return Parse_Path(lex, false, generic_mode);
+ }
+}
+AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generic_mode)
+{
+ if( is_abs )
+ {
+ Token tok;
+ if( GET_TOK(tok, lex) == TOK_STRING ) {
+ ::std::string cratename = tok.str();
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
+ return Parse_PathFrom(lex, AST::Path(cratename, {}), generic_mode);
+ }
+ else {
+ lex.putback(tok);
+ return Parse_PathFrom(lex, AST::Path(AST::Path::TagAbsolute()), generic_mode);
+ }
+ }
+ else
+ return Parse_PathFrom(lex, AST::Path(), generic_mode);
+}
+
+/// Parse a list of parameters within a path
::std::vector<TypeRef> Parse_Path_GenericList(TokenStream& lex)
{
TRACE_FUNCTION;
@@ -105,25 +141,6 @@ AST::Path Parse_PathFrom(TokenStream& lex, AST::Path path, eParsePathGenericMode
return path;
}
-AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generic_mode)
-{
- if( is_abs )
- {
- Token tok;
- if( GET_TOK(tok, lex) == TOK_STRING ) {
- ::std::string cratename = tok.str();
- GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
- return Parse_PathFrom(lex, AST::Path(cratename, {}), generic_mode);
- }
- else {
- lex.putback(tok);
- return Parse_PathFrom(lex, AST::Path(AST::Path::TagAbsolute()), generic_mode);
- }
- }
- else
- return Parse_PathFrom(lex, AST::Path(), generic_mode);
-}
-
static const struct {
const char* name;
enum eCoreType type;
@@ -145,34 +162,8 @@ static const struct {
{"usize", CORETYPE_UINT},
};
-TypeRef Parse_Type_Fn(TokenStream& lex, ::std::string abi)
-{
- TRACE_FUNCTION;
- Token tok;
-
- ::std::vector<TypeRef> args;
- GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN);
- while( LOOK_AHEAD(lex) != TOK_PAREN_CLOSE )
- {
- args.push_back( Parse_Type(lex) );
- if( GET_TOK(tok, lex) != TOK_COMMA ) {
- lex.putback(tok);
- break;
- }
- }
- GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE);
-
- TypeRef ret_type = TypeRef(TypeRef::TagUnit());
- if( GET_TOK(tok, lex) == TOK_THINARROW )
- {
- ret_type = Parse_Type(lex);
- }
- else {
- lex.putback(tok);
- }
-
- return TypeRef(TypeRef::TagFunction(), ::std::move(abi), ::std::move(args), ::std::move(ret_type));
-}
+TypeRef Parse_Type(TokenStream& lex);
+TypeRef Parse_Type_Fn(TokenStream& lex, ::std::string abi);
TypeRef Parse_Type(TokenStream& lex)
{
@@ -284,13 +275,64 @@ TypeRef Parse_Type(TokenStream& lex)
CHECK_TOK(tok, TOK_PAREN_CLOSE);
return TypeRef(TypeRef::TagTuple(), types); }
case TOK_EXCLAM:
- throw ParseError::Todo("noreturn type");
+ throw ParseError::Generic(lex, "! is not a real type");
default:
throw ParseError::Unexpected(lex, tok);
}
throw ParseError::BugCheck("Reached end of Parse_Type");
}
+TypeRef Parse_Type_Fn(TokenStream& lex, ::std::string abi)
+{
+ TRACE_FUNCTION;
+ Token tok;
+
+ ::std::vector<TypeRef> args;
+ GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN);
+ while( LOOK_AHEAD(lex) != TOK_PAREN_CLOSE )
+ {
+ args.push_back( Parse_Type(lex) );
+ if( GET_TOK(tok, lex) != TOK_COMMA ) {
+ lex.putback(tok);
+ break;
+ }
+ }
+ GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE);
+
+ TypeRef ret_type = TypeRef(TypeRef::TagUnit());
+ if( GET_TOK(tok, lex) == TOK_THINARROW )
+ {
+ ret_type = Parse_Type(lex);
+ }
+ else {
+ lex.putback(tok);
+ }
+
+ return TypeRef(TypeRef::TagFunction(), ::std::move(abi), ::std::move(args), ::std::move(ret_type));
+}
+
+/// Parse type parameters in a definition
+void Parse_TypeBound(TokenStream& lex, AST::TypeParams& ret, TypeRef checked_type)
+{
+ TRACE_FUNCTION;
+ Token tok;
+
+ do
+ {
+ if(GET_TOK(tok, lex) == TOK_LIFETIME) {
+ ret.add_bound( AST::GenericBound(checked_type, tok.str()) );
+ }
+ else if( tok.type() == TOK_QMARK ) {
+ ret.add_bound( AST::GenericBound(checked_type, Parse_Path(lex, PATH_GENERIC_TYPE), true) );
+ }
+ else {
+ lex.putback(tok);
+ ret.add_bound( AST::GenericBound(checked_type, Parse_Path(lex, PATH_GENERIC_TYPE)) );
+ }
+ } while( GET_TOK(tok, lex) == TOK_PLUS );
+ lex.putback(tok);
+}
+
AST::TypeParams Parse_TypeParams(TokenStream& lex)
{
TRACE_FUNCTION;
@@ -299,8 +341,7 @@ AST::TypeParams Parse_TypeParams(TokenStream& lex)
Token tok;
do {
bool is_lifetime = false;
- tok = lex.getToken();
- switch(tok.type())
+ switch( GET_TOK(tok, lex) )
{
case TOK_IDENT:
break;
@@ -315,32 +356,45 @@ AST::TypeParams Parse_TypeParams(TokenStream& lex)
ret.add_param( AST::TypeParam( is_lifetime, param_name ) );
if( GET_TOK(tok, lex) == TOK_COLON )
{
- // TODO: Conditions
if( is_lifetime )
{
- throw ParseError::Todo("lifetime param conditions");
+ throw ParseError::Todo(lex, "lifetime param conditions");
}
-
- do
+ else
{
- if(GET_TOK(tok, lex) == TOK_LIFETIME) {
- ret.add_bound( AST::GenericBound(param_name, tok.str()) );
- }
- else {
- lex.putback(tok);
- ret.add_bound( AST::GenericBound(param_name, Parse_Type(lex)) );
- }
- } while( GET_TOK(tok, lex) == TOK_PLUS );
+ Parse_TypeBound(lex, ret, TypeRef(TypeRef::TagArg(), param_name));
+ }
+ GET_TOK(tok, lex);
+ }
+
+ if( tok.type() == TOK_EQUAL )
+ {
+ ret.params().back().setDefault( Parse_Type(lex) );
+ GET_TOK(tok, lex);
}
} while( tok.type() == TOK_COMMA );
lex.putback(tok);
return ret;
}
-void Parse_TypeConds(TokenStream& lex, AST::TypeParams& params)
+void Parse_WhereClause(TokenStream& lex, AST::TypeParams& params)
{
TRACE_FUNCTION;
- throw ParseError::Todo("type param conditions (where)");
+ Token tok;
+
+ do {
+ if( GET_TOK(tok, lex) == TOK_LIFETIME )
+ {
+ }
+ else
+ {
+ lex.putback(tok);
+ TypeRef type = Parse_Type(lex);
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+ Parse_TypeBound(lex, params, type);
+ }
+ } while( GET_TOK(tok, lex) == TOK_COMMA );
+ lex.putback(tok);
}
// Parse a single function argument
@@ -463,11 +517,17 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, AST::MetaIt
// Eat 'tok', negative comparison
}
- TypeRef ret_type;
+ TypeRef ret_type = TypeRef(TypeRef::TagUnit());;
if( GET_TOK(tok, lex) == TOK_THINARROW )
{
// Return type
- ret_type = Parse_Type(lex);
+ if( GET_TOK(tok, lex) == TOK_EXCLAM ) {
+ ret_type = TypeRef(TypeRef::TagInvalid());
+ }
+ else {
+ lex.putback(tok);
+ ret_type = Parse_Type(lex);
+ }
}
else
{
@@ -476,7 +536,7 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, AST::MetaIt
if( GET_TOK(tok, lex) == TOK_RWORD_WHERE )
{
- throw ParseError::Todo(lex, "where clauses on fn");
+ Parse_WhereClause(lex, params);
}
else {
lex.putback(tok);
@@ -542,7 +602,7 @@ void Parse_Struct(AST::Module& mod, TokenStream& lex, const bool is_public, cons
tok = lex.getToken();
if(tok.type() == TOK_RWORD_WHERE)
{
- Parse_TypeConds(lex, params);
+ Parse_WhereClause(lex, params);
tok = lex.getToken();
}
}
@@ -621,19 +681,9 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items)
// Trait bounds "trait Trait : 'lifetime + OtherTrait + OtherTrait2"
if(tok.type() == TOK_COLON)
{
- do
- {
- if( GET_TOK(tok, lex) == TOK_LIFETIME )
- {
- // Lifetime requirement
- throw ParseError::Todo("Trait bounds (lifetime)");
- }
- else
- {
- lex.putback(tok);
- params.add_bound( AST::GenericBound("Self", Parse_Type(lex)) );
- }
- } while(GET_TOK(tok, lex) == TOK_PLUS);
+ // 'Self' is a special generic type only valid within traits
+ Parse_TypeBound(lex, params, TypeRef(TypeRef::TagArg(), "Self"));
+ GET_TOK(tok, lex);
}
// TODO: Support "for Sized?"
@@ -641,7 +691,7 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items)
{
if( params.n_params() == 0 )
throw ParseError::Generic("Where clause with no generic params");
- Parse_TypeConds(lex, params);
+ Parse_WhereClause(lex, params);
tok = lex.getToken();
}
@@ -659,26 +709,40 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items)
GET_TOK(tok, lex);
}
+
switch(tok.type())
{
case TOK_RWORD_STATIC: {
throw ParseError::Todo("Associated static");
break; }
+ // Associated type
case TOK_RWORD_TYPE: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
::std::string name = tok.str();
- if( GET_TOK(tok, lex) == TOK_COLON ) {
- throw ParseError::Todo("Type bounds on associated type");
+ if( GET_TOK(tok, lex) == TOK_COLON )
+ {
+ // Bounded associated type
+ TypeRef a_type = TypeRef(TypeRef::TagAssoc(), TypeRef(TypeRef::TagArg(), "Self"), TypeRef(), name);
+ Parse_TypeBound(lex, params, a_type);
+ GET_TOK(tok, lex);
}
if( tok.type() == TOK_RWORD_WHERE ) {
- throw ParseError::Todo("Where clause on associated type");
+ throw ParseError::Todo(lex, "Where clause on associated type");
}
+
TypeRef default_type;
if( tok.type() == TOK_EQUAL ) {
default_type = Parse_Type(lex);
+ GET_TOK(tok, lex);
}
+
+ CHECK_TOK(tok, TOK_SEMICOLON);
trait.add_type( ::std::move(name), ::std::move(default_type) );
break; }
+ // Functions (possibly unsafe)
+ case TOK_RWORD_UNSAFE:
+ item_attrs.push_back( AST::MetaItem("#UNSAFE") );
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_FN);
case TOK_RWORD_FN: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
::std::string name = tok.str();
@@ -686,7 +750,7 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items)
trait.add_function( ::std::move(name), Parse_FunctionDef(lex, "rust", item_attrs, true, true) );
break; }
default:
- throw ParseError::Generic("Unexpected token, expected 'type' or 'fn'");
+ throw ParseError::Unexpected(lex, tok);
}
}
@@ -709,7 +773,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems meta_items)
tok = lex.getToken();
if(tok.type() == TOK_RWORD_WHERE)
{
- Parse_TypeConds(lex, params);
+ Parse_WhereClause(lex, params);
tok = lex.getToken();
}
}
@@ -773,7 +837,7 @@ AST::MetaItem Parse_MetaItem(TokenStream& lex)
}
}
-AST::Impl Parse_Impl(TokenStream& lex)
+AST::Impl Parse_Impl(TokenStream& lex, bool is_unsafe=false)
{
TRACE_FUNCTION;
Token tok;
@@ -789,22 +853,51 @@ AST::Impl Parse_Impl(TokenStream& lex)
lex.putback(tok);
}
// 2. Either a trait name (with type params), or the type to impl
- // - Don't care which at this stage
+
TypeRef trait_type;
- TypeRef impl_type = Parse_Type(lex);
- if( GET_TOK(tok, lex) == TOK_RWORD_FOR )
+ TypeRef impl_type;
+ // - Handle negative impls, which must be a trait
+ // "impl !Trait for Type {}"
+ if( GET_TOK(tok, lex) == TOK_EXCLAM )
{
- // Implementing a trait for another type, get the target type
- trait_type = impl_type;
+ trait_type = Parse_Type(lex);
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_FOR);
impl_type = Parse_Type(lex);
+
+ if( GET_TOK(tok, lex) == TOK_RWORD_WHERE )
+ {
+ Parse_WhereClause(lex, params);
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_BRACE_OPEN);
+ // negative impls can't have any content
+ GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
+
+ return AST::Impl(AST::Impl::TagNegative(), ::std::move(params),
+ ::std::move(impl_type), ::std::move(trait_type)
+ );
}
- else {
+ else
+ {
+ // - Don't care which at this stage
lex.putback(tok);
+
+ impl_type = Parse_Type(lex);
+ if( GET_TOK(tok, lex) == TOK_RWORD_FOR )
+ {
+ // Implementing a trait for another type, get the target type
+ trait_type = impl_type;
+ impl_type = Parse_Type(lex);
+ }
+ else {
+ lex.putback(tok);
+ }
}
+
// Where clause
if( GET_TOK(tok, lex) == TOK_RWORD_WHERE )
{
- Parse_TypeConds(lex, params);
+ Parse_WhereClause(lex, params);
}
else {
lex.putback(tok);
@@ -829,6 +922,12 @@ AST::Impl Parse_Impl(TokenStream& lex)
is_public = true;
GET_TOK(tok, lex);
}
+
+ if(tok.type() == TOK_RWORD_UNSAFE) {
+ item_attrs.push_back( AST::MetaItem("#UNSAFE") );
+ GET_TOK(tok, lex);
+ }
+
switch(tok.type())
{
case TOK_RWORD_TYPE: {
@@ -1267,7 +1366,8 @@ void Parse_ModRoot_Items(TokenStream& lex, AST::Crate& crate, AST::Module& mod,
::std::string name = tok.str();
auto expanded_macro = Macro_Invoke(lex, name.c_str(), tt);
- Parse_ModRoot_Items(*expanded_macro, crate, mod, modstack, path);
+ // Pass "!" as 'path' to allow termination on EOF
+ Parse_ModRoot_Items(*expanded_macro, crate, mod, modstack, "!");
}
break;
@@ -1375,6 +1475,15 @@ void Parse_ModRoot_Items(TokenStream& lex, AST::Crate& crate, AST::Module& mod,
// - self not allowed, not prototype
mod.add_function(is_public, tok.str(), Parse_FunctionDef(lex, "rust", ::std::move(meta_items), false, false));
break;
+ case TOK_RWORD_TRAIT: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ ::std::string name = tok.str();
+ mod.add_trait(is_public, name, Parse_TraitDef(lex, meta_items));
+ break;
+ }
+ case TOK_RWORD_IMPL:
+ mod.add_impl(Parse_Impl(lex, true));
+ break;
default:
throw ParseError::Unexpected(lex, tok);
}
@@ -1419,7 +1528,10 @@ void Parse_ModRoot_Items(TokenStream& lex, AST::Crate& crate, AST::Module& mod,
break;
case TOK_SEMICOLON:
DEBUG("Mod = " << name << ", curpath = " << path);
- if( path.back() != '/' )
+ if( path == "-" || path == "!" ) {
+ throw ParseError::Generic(lex, "Cannot load module from file within nested context");
+ }
+ else if( path.back() != '/' )
{
throw ParseError::Generic( FMT("Can't load from files outside of mod.rs or crate root") );
}
diff --git a/src/types.hpp b/src/types.hpp
index dad4493b..adc28f6f 100644
--- a/src/types.hpp
+++ b/src/types.hpp
@@ -43,6 +43,7 @@ class TypeRef:
{
/// Class
enum Class {
+ NONE,
ANY, //< '_' - Wildcard
//BOUNDED, //< '_: Traits' - Bounded type (a resolved type parameter usually)
UNIT, //< '()' - Unit / void
@@ -68,6 +69,12 @@ public:
TypeRef():
m_class(ANY)
{}
+
+ struct TagInvalid {};
+ TypeRef(TagInvalid):
+ m_class(NONE)
+ {}
+
struct TagBoundedAny {};
TypeRef(TagBoundedAny, ::std::vector<TypeRef> traits):
m_class(ANY),