From 6b506092f331a26328a45c00565336ac810b7559 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 15 Mar 2015 21:33:46 +0800 Subject: Rework type params, add ! "type" --- src/ast/ast.cpp | 18 ++- src/ast/ast.hpp | 44 ++++-- src/ast/expr.cpp | 4 +- src/ast/expr.hpp | 1 + src/convert/ast_iterate.cpp | 3 +- src/convert/typecheck_bounds.cpp | 4 +- src/convert/typecheck_expr.cpp | 10 +- src/convert/typecheck_params.cpp | 20 +-- src/dump_as_rust.cpp | 6 +- src/macros.cpp | 76 +++++++--- src/parse/expr.cpp | 7 +- src/parse/root.cpp | 306 ++++++++++++++++++++++++++------------- src/types.hpp | 7 + 13 files changed, 349 insertions(+), 157 deletions(-) (limited to 'src') 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& 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& 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 m_types; ItemList m_functions; ::std::vector< ::std::pair< ::std::vector, 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& 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 m_layer_counts; + Token m_next_token; // used for inserting a single token into the stream ::std::unique_ptr 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* 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* 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* 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 *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 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 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 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 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 traits): m_class(ANY), -- cgit v1.2.3