diff options
author | John Hodge <tpg@mutabah.net> | 2016-12-28 20:19:18 +1100 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-12-28 20:19:18 +1100 |
commit | 59d95e289122a84ea057ff5ed15d7d0e583138ed (patch) | |
tree | 663b285db0a406a8fbe181a89a3dc4f61accca6b /src/expand/asm.cpp | |
parent | bd913f6259896ce7317061e3607f3c8fd2371d89 (diff) | |
download | mrust-59d95e289122a84ea057ff5ed15d7d0e583138ed.tar.gz |
AST - Add asm! as an AST node
Diffstat (limited to 'src/expand/asm.cpp')
-rw-r--r-- | src/expand/asm.cpp | 114 |
1 files changed, 113 insertions, 1 deletions
diff --git a/src/expand/asm.cpp b/src/expand/asm.cpp index 3ca7bb72..6ca90f3e 100644 --- a/src/expand/asm.cpp +++ b/src/expand/asm.cpp @@ -7,16 +7,128 @@ */ #include <common.hpp> #include <synext_macro.hpp> +#include <synext.hpp> // for Expand_BareExpr #include <parse/tokentree.hpp> #include <parse/ttstream.hpp> +#include <parse/common.hpp> +#include <parse/parseerror.hpp> +#include <ast/expr.hpp> // for ExprNode_* +#include <parse/interpolated_fragment.hpp> + +namespace +{ + ::std::string get_string(const Span& sp, TokenStream& lex, const ::AST::Crate& crate, AST::Module& mod) + { + auto n = Parse_ExprVal(lex); + ASSERT_BUG(sp, n, "No expression returned"); + Expand_BareExpr(crate, mod, n); + + auto* format_string_np = dynamic_cast<AST::ExprNode_String*>(&*n); + if( !format_string_np ) { + ERROR(sp, E0000, "asm! requires a string literal - got " << *n); + } + //const auto& format_string_sp = format_string_np->span(); + return mv$( format_string_np->m_value ); + } +} class CAsmExpander: public ExpandProcMacro { ::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(tt); + if( ident != "" ) + ERROR(sp, E0000, "format_args! 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_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); + } + } + + // Inputs + 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); + } + } + + // Clobbers + 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); + } + } + + // Flags + 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); + } + } + + ::AST::ExprNodeP rv = ::AST::ExprNodeP( new ::AST::ExprNode_Asm { mv$(template_text), mv$(outputs), mv$(inputs), mv$(clobbers), mv$(flags) } ); // TODO: Convert this into an AST node - return box$( TTStreamO(TokenTree()) ); + return box$( TTStreamO(TokenTree(Token( InterpolatedFragment(InterpolatedFragment::EXPR, rv.release()) )))); } }; |