/// Parse the pattern of a macro_rules! arm ::std::vector<MacroPatEnt> Parse_MacroRules_Pat(TokenStream& lex, enum eTokenType open, enum eTokenType close, ::std::vector< ::std::string>& names) { TRACE_FUNCTION; Token tok; ::std::vector<MacroPatEnt> ret; int depth = 0; while( GET_TOK(tok, lex) != close || depth > 0 ) { if( tok.type() == open ) { depth ++; } else if( tok.type() == close ) { if(depth == 0) throw ParseError::Generic(FMT("Unmatched " << Token(close) << " in macro pattern")); depth --; } switch(tok.type()) { case TOK_DOLLAR: switch( GET_TOK(tok, lex) ) { // TODO: Allow any reserved word case TOK_RWORD_TYPE: case TOK_RWORD_PUB: case TOK_IDENT: { ::std::string name = tok.type() == TOK_IDENT ? mv$(tok.str()) : FMT(tok); GET_CHECK_TOK(tok, lex, TOK_COLON); GET_CHECK_TOK(tok, lex, TOK_IDENT); ::std::string type = mv$(tok.str()); unsigned int idx = ::std::find( names.begin(), names.end(), name ) - names.begin(); if( idx == names.size() ) names.push_back( name ); if(0) ; else if( type == "tt" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_TT) ); else if( type == "pat" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_PAT) ); else if( type == "ident" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_IDENT) ); else if( type == "path" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_PATH) ); else if( type == "expr" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_EXPR) ); else if( type == "stmt" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_STMT) ); else if( type == "ty" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_TYPE) ); else if( type == "meta" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_META) ); else if( type == "block" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_BLOCK) ); else if( type == "item" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_ITEM) ); else ERROR(lex.point_span(), E0000, "Unknown fragment type '" << type << "'"); break; } case TOK_PAREN_OPEN: { auto subpat = Parse_MacroRules_Pat(lex, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, names); enum eTokenType joiner = TOK_NULL; GET_TOK(tok, lex); if( tok.type() != TOK_PLUS && tok.type() != TOK_STAR ) { DEBUG("joiner = " << tok); joiner = tok.type(); GET_TOK(tok, lex); } DEBUG("tok = " << tok); switch(tok.type()) { case TOK_PLUS: DEBUG("$()+ " << subpat); ret.push_back( MacroPatEnt(Token(joiner), true, ::std::move(subpat)) ); break; case TOK_STAR: DEBUG("$()* " << subpat); ret.push_back( MacroPatEnt(Token(joiner), false, ::std::move(subpat)) ); break; default: throw ParseError::Unexpected(lex, tok); } break; } default: throw ParseError::Unexpected(lex, tok); } break; case TOK_EOF: throw ParseError::Unexpected(lex, tok); default: ret.push_back( MacroPatEnt(tok) ); break; } } return ret; }
TypeRef Parse_Type_Fn(TokenStream& lex, ::AST::HigherRankedBounds hrbs) { auto ps = lex.start_span(); TRACE_FUNCTION; Token tok; ::std::string abi = ""; bool is_unsafe = false; GET_TOK(tok, lex); // `unsafe` if( tok.type() == TOK_RWORD_UNSAFE ) { is_unsafe = true; GET_TOK(tok, lex); } // `exern` if( tok.type() == TOK_RWORD_EXTERN ) { if( GET_TOK(tok, lex) == TOK_STRING ) { abi = tok.str(); if( abi == "" ) ERROR(lex.point_span(), E0000, "Empty ABI"); GET_TOK(tok, lex); } else { abi = "C"; } } // `fn` CHECK_TOK(tok, TOK_RWORD_FN); ::std::vector<TypeRef> args; bool is_variadic = false; GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN); while( LOOK_AHEAD(lex) != TOK_PAREN_CLOSE ) { if( LOOK_AHEAD(lex) == TOK_TRIPLE_DOT ) { GET_TOK(tok, lex); is_variadic = true; break; } // Handle `ident: ` if( (lex.lookahead(0) == TOK_IDENT || lex.lookahead(0) == TOK_UNDERSCORE) && lex.lookahead(1) == TOK_COLON ) { GET_TOK(tok, lex); GET_TOK(tok, lex); } args.push_back( Parse_Type(lex) ); if( GET_TOK(tok, lex) != TOK_COMMA ) { PUTBACK(tok, lex); break; } } GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE); // `-> RetType` TypeRef ret_type = TypeRef(TypeRef::TagUnit(), Span(tok.get_pos())); if( GET_TOK(tok, lex) == TOK_THINARROW ) { ret_type = Parse_Type(lex, false); } else { PUTBACK(tok, lex); } return TypeRef(TypeRef::TagFunction(), lex.end_span(mv$(ps)), mv$(hrbs), is_unsafe, mv$(abi), mv$(args), is_variadic, mv$(ret_type)); }
/// Parse the contents (replacement) of a macro_rules! arm ::std::vector<MacroExpansionEnt> Parse_MacroRules_Cont( TokenStream& lex, enum eTokenType open, enum eTokenType close, const ::std::vector< ::std::string>& var_names, ::std::map<unsigned int,bool>* var_set_ptr=nullptr ) { TRACE_FUNCTION; Token tok; ::std::vector<MacroExpansionEnt> ret; int depth = 0; while( GET_TOK(tok, lex) != close || depth > 0 ) { if( tok.type() == TOK_EOF ) { throw ParseError::Unexpected(lex, tok); } if( tok.type() == TOK_NULL ) continue ; if( tok.type() == open ) { DEBUG("depth++"); depth ++; } else if( tok.type() == close ) { DEBUG("depth--"); if(depth == 0) ERROR(lex.point_span(), E0000, "Unmatched " << Token(close) << " in macro content"); depth --; } // `$` - Macro metavars if( tok.type() == TOK_DOLLAR ) { GET_TOK(tok, lex); // `$(` if( tok.type() == TOK_PAREN_OPEN ) { ::std::map<unsigned int, bool> var_set; auto content = Parse_MacroRules_Cont(lex, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, var_names, &var_set); // ^^ The above will eat the PAREN_CLOSE GET_TOK(tok, lex); enum eTokenType joiner = TOK_NULL; if( tok.type() != TOK_PLUS && tok.type() != TOK_STAR ) { joiner = tok.type(); GET_TOK(tok, lex); } bool is_optional = (tok.type() == TOK_STAR); if( var_set_ptr ) { for(const auto& v : var_set) { // If `is_optional`: Loop may not be expanded, so var_not_opt=false // Else, inherit bool var_not_opt = (is_optional ? false : v.second); var_set_ptr->insert( ::std::make_pair(v.first, var_not_opt) ).first->second |= var_not_opt; } } DEBUG("joiner = " << Token(joiner) << ", content = " << content); switch(tok.type()) { case TOK_PLUS: case TOK_STAR: // TODO: Ensure that +/* match up? ret.push_back( MacroExpansionEnt({mv$(content), joiner, mv$(var_set)}) ); break; default: throw ParseError::Unexpected(lex, tok); } } //else if( tok.type() == TOK_IDENT || tok_is_rword(tok.type()) ) else if( tok.type() == TOK_IDENT || tok.type() == TOK_RWORD_TYPE || tok.type() == TOK_RWORD_PUB ) { // Look up the named parameter in the list of param names for this arm auto name = tok.type() == TOK_IDENT ? tok.str() : FMT(tok); unsigned int idx = ::std::find(var_names.begin(), var_names.end(), name) - var_names.begin(); if( idx == var_names.size() ) { // TODO: `error-chain`'s quick_error macro has an arm which refers to an undefined metavar. // - Maybe emit a warning and use a marker index. WARNING(lex.point_span(), W0000, "Macro variable $" << name << " not found"); // Emit the literal $ <name> ret.push_back( MacroExpansionEnt(Token(TOK_DOLLAR)) ); ret.push_back( MacroExpansionEnt(mv$(tok)) ); continue ; } if( var_set_ptr ) { var_set_ptr->insert( ::std::make_pair(idx,true) ); } ret.push_back( MacroExpansionEnt(idx) ); } else if( tok.type() == TOK_RWORD_CRATE ) { ret.push_back( MacroExpansionEnt( (1<<30) | 0 ) ); } else { throw ParseError::Unexpected(lex, tok); } } else { ret.push_back( MacroExpansionEnt( mv$(tok) ) ); } } return ret; }