/* * MRustC - Rust Compiler * - By John Hodge (Mutabah/thePowersGang) * * parse/paths.cpp * - Parsing for module paths */ #include "parseerror.hpp" #include "common.hpp" #include "../ast/ast.hpp" AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode); AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generic_mode); ::std::vector Parse_PathNodes(TokenStream& lex, eParsePathGenericMode generic_mode); ::std::vector Parse_Path_GenericList(TokenStream& lex); AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode) { Token tok; switch( GET_TOK(tok, lex) ) { case TOK_INTERPOLATED_PATH: return mv$(tok.frag_path()); case TOK_RWORD_SELF: GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); return Parse_Path(lex, false, generic_mode); case TOK_RWORD_SUPER: { GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); unsigned int count = 1; while( LOOK_AHEAD(lex) == TOK_RWORD_SUPER ) { count += 1; GET_TOK(tok, lex); GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); } return AST::Path(AST::Path::TagSuper(), count, Parse_PathNodes(lex, generic_mode)); } case TOK_DOUBLE_COLON: return Parse_Path(lex, true, generic_mode); case TOK_DOUBLE_LT: lex.putback( Token(TOK_LT) ); case TOK_LT: { TypeRef ty = Parse_Type(lex); if( GET_TOK(tok, lex) == TOK_RWORD_AS ) { ::AST::Path trait; if( GET_TOK(tok, lex) == TOK_DOUBLE_COLON ) { trait = Parse_Path(lex, true, PATH_GENERIC_TYPE); } else { PUTBACK(tok, lex); trait = Parse_Path(lex, false, PATH_GENERIC_TYPE); } GET_CHECK_TOK(tok, lex, TOK_GT); GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); return AST::Path(AST::Path::TagUfcs(), ty, trait, Parse_PathNodes(lex, generic_mode)); } else { PUTBACK(tok, lex); GET_CHECK_TOK(tok, lex, TOK_GT); // TODO: Terminating the "path" here is sometimes valid? GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); return AST::Path(AST::Path::TagUfcs(), ty, Parse_PathNodes(lex, generic_mode)); } throw ""; } default: PUTBACK(tok, lex); return Parse_Path(lex, false, generic_mode); } } AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generic_mode) { Token tok; if( is_abs ) { if( GET_TOK(tok, lex) == TOK_STRING ) { ::std::string cratename = tok.str(); GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); return AST::Path(cratename, Parse_PathNodes(lex, generic_mode)); } else { PUTBACK(tok, lex); return AST::Path("", Parse_PathNodes(lex, generic_mode)); } } else { //assert( GET_TOK(tok, lex) == TOK_IDENT ); //if( lex.lookahead(0) != TOK_DOUBLE_COLON ) { // return AST::Path( tok.str() ); //} //else { // PUTBACK(tok, lex); return AST::Path(AST::Path::TagRelative(), Parse_PathNodes(lex, generic_mode)); //} } } ::std::vector Parse_PathNodes(TokenStream& lex, eParsePathGenericMode generic_mode) { Token tok; ::std::vector ret; tok = lex.getToken(); while(true) { ::std::vector params; CHECK_TOK(tok, TOK_IDENT); ::std::string component = tok.str(); GET_TOK(tok, lex); if( generic_mode == PATH_GENERIC_TYPE ) { if( tok.type() == TOK_LT || tok.type() == TOK_DOUBLE_LT ) { // HACK! Handle breaking << into < < if( tok.type() == TOK_DOUBLE_LT ) lex.putback( Token(TOK_LT) ); // Type-mode generics "::path::to::Type" params = Parse_Path_GenericList(lex); tok = lex.getToken(); } // HACK - 'Fn*(...) -> ...' notation else if( tok.type() == TOK_PAREN_OPEN ) { auto ps = lex.start_span(); DEBUG("Fn() hack"); ::std::vector args; if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE ) { // Empty list } else { PUTBACK(tok, lex); do { args.push_back( Parse_Type(lex) ); } while( GET_TOK(tok, lex) == TOK_COMMA ); } CHECK_TOK(tok, TOK_PAREN_CLOSE); TypeRef ret_type = TypeRef( TypeRef::TagUnit(), Span(tok.get_pos()) ); if( GET_TOK(tok, lex) == TOK_THINARROW ) { ret_type = Parse_Type(lex); } else { PUTBACK(tok, lex); } DEBUG("- Fn("<"<C into Fn<(A,B),Ret=C> params = ::std::vector { TypeRef(TypeRef::TagTuple(), lex.end_span(ps), ::std::move(args)) }; // TODO: Use 'ret_type' as an associated type bound GET_TOK(tok, lex); } else { } } if( tok.type() != TOK_DOUBLE_COLON ) { ret.push_back( AST::PathNode(component, mv$(params)) ); break; } tok = lex.getToken(); if( generic_mode == PATH_GENERIC_EXPR && (tok.type() == TOK_LT || tok.type() == TOK_DOUBLE_LT) ) { // HACK! Handle breaking << into < < if( tok.type() == TOK_DOUBLE_LT ) lex.putback( Token(TOK_LT) ); // Expr-mode generics "::path::to::function::(arg1, arg2)" params = Parse_Path_GenericList(lex); tok = lex.getToken(); if( tok.type() != TOK_DOUBLE_COLON ) { ret.push_back( AST::PathNode(component, mv$(params)) ); break; } GET_TOK(tok, lex); } ret.push_back( AST::PathNode(component, mv$(params)) ); } PUTBACK(tok, lex); //if( path.is_trivial() ) { // path = AST::Path(path[0].name()); //} DEBUG("ret = " << ret); return ret; } /// Parse a list of parameters within a path ::std::vector Parse_Path_GenericList(TokenStream& lex) { TRACE_FUNCTION; Token tok; ::std::vector types; ::std::vector< ::std::string> lifetimes; ::std::map< ::std::string, TypeRef> assoc_bounds; //::std::vector int_args; do { if( LOOK_AHEAD(lex) == TOK_GT || LOOK_AHEAD(lex) == TOK_DOUBLE_GT || LOOK_AHEAD(lex) == TOK_GTE || LOOK_AHEAD(lex) == TOK_DOUBLE_GT_EQUAL ) { GET_TOK(tok, lex); break; } switch(GET_TOK(tok, lex)) { case TOK_LIFETIME: lifetimes.push_back( tok.str() ); break; case TOK_IDENT: if( LOOK_AHEAD(lex) == TOK_EQUAL ) { ::std::string name = tok.str(); GET_CHECK_TOK(tok, lex, TOK_EQUAL); assoc_bounds.insert( ::std::make_pair( ::std::move(name), Parse_Type(lex) ) ); break; } default: PUTBACK(tok, lex); types.push_back( Parse_Type(lex) ); break; } } while( GET_TOK(tok, lex) == TOK_COMMA ); // HACK: Split >> into > if(tok.type() == TOK_DOUBLE_GT_EQUAL) { lex.putback(Token(TOK_GTE)); } else if(tok.type() == TOK_GTE) { lex.putback(Token(TOK_EQUAL)); } else if(tok.type() == TOK_DOUBLE_GT) { lex.putback(Token(TOK_GT)); } else { CHECK_TOK(tok, TOK_GT); } // TODO: Actually use the lifetimes/assoc_bounds return types; }