/* * build an input token.. * consider only those starting with _ or A-Za-z. This is a * combo with lookup to speed things up. */ static ndptr inspect(int c, char *tp) { char *name = tp; char *etp = tp+MAXTOK; ndptr p; unsigned int h; h = *tp++ = c; while ((isalnum(c = gpbc()) || c == '_') && tp < etp) h = (h << 5) + h + (*tp++ = c); if (c != EOF) PUTBACK(c); *tp = EOS; /* token is too long, it won't match anything, but it can still * be output. */ if (tp == ep) { outputstr(name); while (isalnum(c = gpbc()) || c == '_') { if (sp < 0) putc(c, active); else CHRSAVE(c); } *name = EOS; return nil; } for (p = hashtab[h % HASHSIZE]; p != nil; p = p->nxtptr) if (h == p->hv && STREQ(name, p->name)) break; return p; }
TypeRef Parse_Type_ErasedType(TokenStream& lex, bool allow_trait_list) { Token tok; auto ps = lex.start_span(); ::std::vector<Type_TraitPath> traits; ::std::vector<AST::LifetimeRef> lifetimes; do { if( LOOK_AHEAD(lex) == TOK_LIFETIME ) { GET_TOK(tok, lex); lifetimes.push_back(AST::LifetimeRef( /*lex.point_span(),*/ lex.get_ident(mv$(tok)) )); } else { AST::HigherRankedBounds hrbs; if( lex.lookahead(0) == TOK_RWORD_FOR ) { hrbs = Parse_HRB(lex); } traits.push_back({ mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) }); } } while( GET_TOK(tok, lex) == TOK_PLUS ); PUTBACK(tok, lex); return TypeRef(lex.end_span(mv$(ps)), TypeData::make_ErasedType({ mv$(traits), mv$(lifetimes) })); }
TypeRef Parse_Type_Path(TokenStream& lex, ::AST::HigherRankedBounds hrbs, bool allow_trait_list) { Token tok; auto ps = lex.start_span(); if( hrbs.empty() && !allow_trait_list ) { return TypeRef(TypeRef::TagPath(), lex.end_span(mv$(ps)), Parse_Path(lex, PATH_GENERIC_TYPE)); } else { ::std::vector<Type_TraitPath> traits; ::std::vector<AST::LifetimeRef> lifetimes; traits.push_back(Type_TraitPath { mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) }); if( allow_trait_list ) { while( GET_TOK(tok, lex) == TOK_PLUS ) { if( LOOK_AHEAD(lex) == TOK_LIFETIME ) { GET_TOK(tok, lex); lifetimes.push_back(AST::LifetimeRef( /*lex.point_span(),*/ lex.get_ident(mv$(tok)) )); } else { if( lex.lookahead(0) == TOK_RWORD_FOR ) { hrbs = Parse_HRB(lex); } traits.push_back({ mv$(hrbs), Parse_Path(lex, PATH_GENERIC_TYPE) }); } } PUTBACK(tok, lex); } if( !traits[0].hrbs.empty() || traits.size() > 1 || lifetimes.size() > 0 ) { if( lifetimes.empty()) lifetimes.push_back(AST::LifetimeRef()); return TypeRef(lex.end_span(mv$(ps)), mv$(traits), mv$(lifetimes)); } else { return TypeRef(TypeRef::TagPath(), lex.end_span(mv$(ps)), mv$(traits.at(0).path)); } } }
::std::unique_ptr<TokenStream> expand(const Span& sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override { Token tok; auto lex = TTStream(sp, tt); if( ident != "" ) ERROR(sp, E0000, "asm! doesn't take an ident"); auto template_text = get_string(sp, lex, crate, mod); ::std::vector<::AST::ExprNode_Asm::ValRef> outputs; ::std::vector<::AST::ExprNode_Asm::ValRef> inputs; ::std::vector<::std::string> clobbers; ::std::vector<::std::string> flags; // Outputs if( lex.lookahead(0) == TOK_DOUBLE_COLON ) { GET_TOK(tok, lex); lex.putback(Token(TOK_COLON)); } else if( lex.lookahead(0) == TOK_COLON ) { GET_TOK(tok, lex); while( lex.lookahead(0) == TOK_STRING ) { //auto name = get_string(sp, lex); GET_CHECK_TOK(tok, lex, TOK_STRING); auto name = mv$(tok.str()); GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN); auto val = Parse_Expr0(lex); GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE); outputs.push_back( ::AST::ExprNode_Asm::ValRef { mv$(name), mv$(val) } ); if( lex.lookahead(0) != TOK_COMMA ) break; GET_TOK(tok, lex); } } else { } // Inputs if( lex.lookahead(0) == TOK_DOUBLE_COLON ) { GET_TOK(tok, lex); lex.putback(Token(TOK_COLON)); } else if( lex.lookahead(0) == TOK_COLON ) { GET_TOK(tok, lex); while( lex.lookahead(0) == TOK_STRING ) { GET_CHECK_TOK(tok, lex, TOK_STRING); auto name = mv$(tok.str()); GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN); auto val = Parse_Expr0(lex); GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE); inputs.push_back( ::AST::ExprNode_Asm::ValRef { mv$(name), mv$(val) } ); if( lex.lookahead(0) != TOK_COMMA ) break; GET_TOK(tok, lex); } } else { } // Clobbers if( lex.lookahead(0) == TOK_DOUBLE_COLON ) { GET_TOK(tok, lex); lex.putback(Token(TOK_COLON)); } else if( lex.lookahead(0) == TOK_COLON ) { GET_TOK(tok, lex); while( lex.lookahead(0) == TOK_STRING ) { GET_CHECK_TOK(tok, lex, TOK_STRING); clobbers.push_back( mv$(tok.str()) ); if( lex.lookahead(0) != TOK_COMMA ) break; GET_TOK(tok, lex); } } else { } // Flags if( lex.lookahead(0) == TOK_DOUBLE_COLON ) { GET_TOK(tok, lex); lex.putback(Token(TOK_COLON)); } else if( lex.lookahead(0) == TOK_COLON ) { GET_TOK(tok, lex); while( lex.lookahead(0) == TOK_STRING ) { GET_CHECK_TOK(tok, lex, TOK_STRING); flags.push_back( mv$(tok.str()) ); if( lex.lookahead(0) != TOK_COMMA ) break; GET_TOK(tok, lex); } } else { } // trailing `: voltaile` - TODO: Is this valid? if( lex.lookahead(0) == TOK_DOUBLE_COLON ) { GET_TOK(tok, lex); lex.putback(Token(TOK_COLON)); } else if( lex.lookahead(0) == TOK_COLON ) { GET_TOK(tok, lex); if( GET_TOK(tok, lex) == TOK_IDENT && tok.str() == "volatile" ) { flags.push_back( "volatile" ); } else { PUTBACK(tok, lex); } } else { } // has to be the end if( lex.lookahead(0) != TOK_EOF ) { ERROR(sp, E0000, "Unexpected token in asm! - " << lex.getToken()); } // Convert this into an AST node and insert as an intepolated expression ::AST::ExprNodeP rv = ::AST::ExprNodeP( new ::AST::ExprNode_Asm { mv$(template_text), mv$(outputs), mv$(inputs), mv$(clobbers), mv$(flags) } ); return box$( TTStreamO(sp, TokenTree(Token( InterpolatedFragment(InterpolatedFragment::EXPR, rv.release()) )))); }
TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list) { //TRACE_FUNCTION; auto ps = lex.start_span(); Token tok; switch( GET_TOK(tok, lex) ) { case TOK_INTERPOLATED_TYPE: return mv$(tok.frag_type()); // '!' - Only ever used as part of function prototypes, but is kinda a type... not allowed here though case TOK_EXCLAM: return TypeRef( Span(tok.get_pos()), TypeData::make_Bang({}) ); // '_' = Wildcard (type inferrence variable) case TOK_UNDERSCORE: return TypeRef(Span(tok.get_pos())); // 'unsafe' - An unsafe function type case TOK_RWORD_UNSAFE: // 'extern' - A function type with an ABI case TOK_RWORD_EXTERN: // 'fn' - Rust function case TOK_RWORD_FN: PUTBACK(tok, lex); return Parse_Type_Fn(lex); case TOK_RWORD_IMPL: return Parse_Type_ErasedType(lex, allow_trait_list); // '<' - An associated type cast case TOK_LT: case TOK_DOUBLE_LT: { PUTBACK(tok, lex); auto path = Parse_Path(lex, PATH_GENERIC_TYPE); return TypeRef(TypeRef::TagPath(), lex.end_span(mv$(ps)), mv$(path)); } // case TOK_RWORD_FOR: { auto hrls = Parse_HRB(lex); switch(LOOK_AHEAD(lex)) { case TOK_RWORD_UNSAFE: case TOK_RWORD_EXTERN: case TOK_RWORD_FN: return Parse_Type_Fn(lex, hrls); default: return Parse_Type_Path(lex, hrls, true); } } // <ident> - Either a primitive, or a path case TOK_IDENT: if( lex.lookahead(0) == TOK_EXCLAM ) { lex.getToken(); // TODO: path macros return TypeRef(TypeRef::TagMacro(), Parse_MacroInvocation(ps, mv$(tok.str()), lex)); } // or a primitive //if( auto ct = coretype_fromstring(tok.str()) ) //{ // return TypeRef(TypeRef::TagPrimitive(), Span(tok.get_pos()), ct); //} PUTBACK(tok, lex); return Parse_Type_Path(lex, {}, allow_trait_list); // - Fall through to path handling // '::' - Absolute path case TOK_DOUBLE_COLON: // 'self' - This relative path case TOK_RWORD_SELF: // 'super' - Parent relative path case TOK_RWORD_SUPER: // ':path' fragment case TOK_INTERPOLATED_PATH: PUTBACK(tok, lex); return Parse_Type_Path(lex, {}, allow_trait_list); // HACK! Convert && into & & case TOK_DOUBLE_AMP: lex.putback(Token(TOK_AMP)); // '&' - Reference type case TOK_AMP: { AST::LifetimeRef lifetime; // Reference tok = lex.getToken(); if( tok.type() == TOK_LIFETIME ) { lifetime = AST::LifetimeRef(/*lex.point_span(), */lex.get_ident(::std::move(tok))); tok = lex.getToken(); } bool is_mut = false; if( tok.type() == TOK_RWORD_MUT ) { is_mut = true; } else { PUTBACK(tok, lex); } return TypeRef(TypeRef::TagReference(), lex.end_span(mv$(ps)), ::std::move(lifetime), is_mut, Parse_Type(lex, false)); } // '*' - Raw pointer case TOK_STAR: // Pointer switch( GET_TOK(tok, lex) ) { case TOK_RWORD_MUT: // Mutable pointer return TypeRef(TypeRef::TagPointer(), lex.end_span(mv$(ps)), true, Parse_Type(lex, false)); case TOK_RWORD_CONST: // Immutable pointer return TypeRef(TypeRef::TagPointer(), lex.end_span(mv$(ps)), false, Parse_Type(lex, false)); default: throw ParseError::Unexpected(lex, tok, {TOK_RWORD_CONST, TOK_RWORD_MUT}); } throw ParseError::BugCheck("Reached end of Parse_Type:STAR"); // '[' - Array type case TOK_SQUARE_OPEN: { // Array TypeRef inner = Parse_Type(lex); if( GET_TOK(tok, lex) == TOK_SEMICOLON ) { // Sized array AST::Expr array_size = Parse_Expr(lex); GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); return TypeRef(TypeRef::TagSizedArray(), lex.end_span(mv$(ps)), mv$(inner), array_size.take_node()); } else if( tok.type() == TOK_SQUARE_CLOSE ) { return TypeRef(TypeRef::TagUnsizedArray(), lex.end_span(mv$(ps)), mv$(inner)); } else { throw ParseError::Unexpected(lex, tok/*, "; or ]"*/); } } // '(' - Tuple (or lifetime bounded trait) case TOK_PAREN_OPEN: { DEBUG("Tuple"); if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE ) return TypeRef(TypeRef::TagTuple(), lex.end_span(mv$(ps)), {}); PUTBACK(tok, lex); TypeRef inner = Parse_Type(lex, true); if( LOOK_AHEAD(lex) == TOK_PAREN_CLOSE ) { // Type in parens, NOT a tuple GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE); return inner; } else { ::std::vector<TypeRef> types; types.push_back( mv$(inner) ); while( GET_TOK(tok, lex) == TOK_COMMA ) { if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE ) break; else PUTBACK(tok, lex); types.push_back( Parse_Type(lex) ); } CHECK_TOK(tok, TOK_PAREN_CLOSE); return TypeRef(TypeRef::TagTuple(), lex.end_span(mv$(ps)), mv$(types)); } } default: throw ParseError::Unexpected(lex, tok); } throw ParseError::BugCheck("Reached end of Parse_Type"); }
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)); }
/* * expand_macro - user-defined macro expansion */ void expand_macro(const char *argv[], int argc) { const char *t; const char *p; int n; int argno; t = argv[0]; /* defn string as a whole */ p = t; while (*p) p++; p--; /* last character of defn */ while (p > t) { if (*(p - 1) != ARGFLAG) PUTBACK(*p); else { switch (*p) { case '#': pbnum(argc - 2); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if ((argno = *p - '0') < argc - 1) pbstr(argv[argno + 1]); break; case '*': if (argc > 2) { for (n = argc - 1; n > 2; n--) { pbstr(argv[n]); putback(COMMA); } pbstr(argv[2]); } break; case '@': if (argc > 2) { for (n = argc - 1; n > 2; n--) { pbstr(rquote); pbstr(argv[n]); pbstr(lquote); putback(COMMA); } pbstr(rquote); pbstr(argv[2]); pbstr(lquote); } break; default: PUTBACK(*p); PUTBACK('$'); break; } p--; } p--; } if (p == t) /* do last character */ PUTBACK(*p); }