* rust-macro-builtins.{h,cc}.
*/
using MacroTranscriberFunc
- = std::function<tl::optional<Fragment> (location_t, MacroInvocData &)>;
+ = std::function<tl::optional<Fragment> (location_t, MacroInvocData &,
+ bool semicolon)>;
} // namespace AST
} // namespace Rust
void
DefaultASTVisitor::visit (AST::InlineAsm &expr)
-{
- rust_unreachable ();
-}
+{}
void
DefaultASTVisitor::visit (AST::TypeParam ¶m)
void
InlineAsm::accept_vis (ASTVisitor &vis)
{
- rust_unreachable ();
vis.visit (*this);
}
* should make use of the actual rules. If the macro is builtin, then another
* associated transcriber should be used
*/
- static Fragment dummy_builtin (location_t, MacroInvocData &)
+ static Fragment dummy_builtin (location_t, MacroInvocData &, bool)
{
rust_unreachable ();
return Fragment::create_error ();
// <http://www.gnu.org/licenses/>.
#include "rust-macro-builtins-asm.h"
+#include "rust-ast.h"
+#include "rust-stmt.h"
namespace Rust {
std::map<AST::InlineAsmOption, std::string> InlineAsmOptionMap{
tl::optional<AST::Fragment>
MacroBuiltin::asm_handler (location_t invoc_locus, AST::MacroInvocData &invoc,
- bool is_global_asm)
+ bool semicolon, bool is_global_asm)
{
- return parse_asm (invoc_locus, invoc, is_global_asm);
+ return parse_asm (invoc_locus, invoc, is_global_asm, semicolon);
}
tl::expected<InlineAsmContext, std::string>
tl::optional<AST::Fragment>
parse_asm (location_t invoc_locus, AST::MacroInvocData &invoc,
- bool is_global_asm)
+ bool is_global_asm, bool semicolon)
{
// From the rule of asm.
// We first peek and see if it is a format string or not.
if (is_valid)
{
- AST::SingleASTNode single = AST::SingleASTNode (
- inline_asm_ctx.inline_asm.clone_expr_without_block ());
- std::vector<AST::SingleASTNode> single_vec = {single};
+ auto node = inline_asm_ctx.inline_asm.clone_expr_without_block ();
+
+ std::vector<AST::SingleASTNode> single_vec = {};
+
+ // If the macro invocation has a semicolon (`asm!("...");`), then we need
+ // to make it a statement. This way, it will be expanded properly.
+ if (semicolon)
+ single_vec.emplace_back (
+ AST::SingleASTNode (std::unique_ptr<AST::Stmt> (
+ new AST::ExprStmt (std::move (node), invoc_locus, semicolon))));
+ else
+ single_vec.emplace_back (AST::SingleASTNode (std::move (node)));
AST::Fragment fragment_ast
= AST::Fragment (single_vec,
tl::optional<AST::Fragment>
parse_asm (location_t invoc_locus, AST::MacroInvocData &invoc,
- bool is_global_asm);
+ bool is_global_asm, bool semicolon);
bool
check_identifier (Parser<MacroInvocLexer> &parser, std::string ident);
tl::optional<AST::Fragment>
MacroBuiltin::format_args_handler (location_t invoc_locus,
- AST::MacroInvocData &invoc,
+ AST::MacroInvocData &invoc, bool semicolon,
AST::FormatArgs::Newline nl)
{
auto input = format_args_parse_arguments (invoc);
tl::optional<AST::Fragment>
MacroBuiltin::include_bytes_handler (location_t invoc_locus,
- AST::MacroInvocData &invoc)
+ AST::MacroInvocData &invoc, bool semicolon)
{
/* Get target filename from the macro invocation, which is treated as a path
relative to the include!-ing file (currently being compiled). */
tl::optional<AST::Fragment>
MacroBuiltin::include_str_handler (location_t invoc_locus,
- AST::MacroInvocData &invoc)
+ AST::MacroInvocData &invoc, bool semicolon)
{
/* Get target filename from the macro invocation, which is treated as a path
relative to the include!-ing file (currently being compiled). */
tl::optional<AST::Fragment>
MacroBuiltin::include_handler (location_t invoc_locus,
- AST::MacroInvocData &invoc)
+ AST::MacroInvocData &invoc, bool semicolon)
{
/* Get target filename from the macro invocation, which is treated as a path
relative to the include!-ing file (currently being compiled). */
namespace Rust {
tl::optional<AST::Fragment>
-MacroBuiltin::file_handler (location_t invoc_locus, AST::MacroInvocData &)
+MacroBuiltin::file_handler (location_t invoc_locus, AST::MacroInvocData &, bool)
{
auto current_file = LOCATION_FILE (invoc_locus);
auto file_str = AST::SingleASTNode (make_string (invoc_locus, current_file));
}
tl::optional<AST::Fragment>
-MacroBuiltin::column_handler (location_t invoc_locus, AST::MacroInvocData &)
+MacroBuiltin::column_handler (location_t invoc_locus, AST::MacroInvocData &,
+ bool)
{
auto current_column = LOCATION_COLUMN (invoc_locus);
}
tl::optional<AST::Fragment>
-MacroBuiltin::line_handler (location_t invoc_locus, AST::MacroInvocData &)
+MacroBuiltin::line_handler (location_t invoc_locus, AST::MacroInvocData &, bool)
{
auto current_line = LOCATION_LINE (invoc_locus);
namespace Rust {
tl::optional<AST::Fragment>
MacroBuiltin::assert_handler (location_t invoc_locus,
- AST::MacroInvocData &invoc)
+ AST::MacroInvocData &invoc, bool semicolon)
{
rust_debug ("assert!() called");
during the compile time. */
tl::optional<AST::Fragment>
MacroBuiltin::compile_error_handler (location_t invoc_locus,
- AST::MacroInvocData &invoc)
+ AST::MacroInvocData &invoc, bool semicolon)
{
auto lit_expr
= parse_single_string_literal (BuiltinMacro::CompileError,
// Can we do that easily?
tl::optional<AST::Fragment>
MacroBuiltin::concat_handler (location_t invoc_locus,
- AST::MacroInvocData &invoc)
+ AST::MacroInvocData &invoc, bool semicolon)
{
auto invoc_token_tree = invoc.get_delim_tok_tree ();
MacroInvocLexer lex (invoc_token_tree.to_token_stream ());
/* Expand builtin macro env!(), which inspects an environment variable at
compile time. */
tl::optional<AST::Fragment>
-MacroBuiltin::env_handler (location_t invoc_locus, AST::MacroInvocData &invoc)
+MacroBuiltin::env_handler (location_t invoc_locus, AST::MacroInvocData &invoc,
+ bool semicolon)
{
auto invoc_token_tree = invoc.get_delim_tok_tree ();
MacroInvocLexer lex (invoc_token_tree.to_token_stream ());
}
tl::optional<AST::Fragment>
-MacroBuiltin::cfg_handler (location_t invoc_locus, AST::MacroInvocData &invoc)
+MacroBuiltin::cfg_handler (location_t invoc_locus, AST::MacroInvocData &invoc,
+ bool semicolon)
{
// only parse if not already parsed
if (!invoc.is_parsed ())
tl::optional<AST::Fragment>
MacroBuiltin::stringify_handler (location_t invoc_locus,
- AST::MacroInvocData &invoc)
+ AST::MacroInvocData &invoc, bool semicolon)
{
std::string content;
auto invoc_token_tree = invoc.get_delim_tok_tree ();
AST::MacroTranscriberFunc
format_args_maker (AST::FormatArgs::Newline nl)
{
- return [nl] (location_t loc, AST::MacroInvocData &invoc) {
- return MacroBuiltin::format_args_handler (loc, invoc, nl);
+ return [nl] (location_t loc, AST::MacroInvocData &invoc, bool semicolon) {
+ return MacroBuiltin::format_args_handler (loc, invoc, semicolon, nl);
};
}
{
bool global_asm = is_global_asm == isGlobalAsm::Global ? true : false;
- return [global_asm] (location_t loc, AST::MacroInvocData &invoc) {
- return MacroBuiltin::asm_handler (loc, invoc, global_asm);
- };
+ return
+ [global_asm] (location_t loc, AST::MacroInvocData &invoc, bool semicolon) {
+ return MacroBuiltin::asm_handler (loc, invoc, semicolon, global_asm);
+ };
}
std::unordered_map<std::string, AST::MacroTranscriberFunc>
}
tl::optional<AST::Fragment>
-MacroBuiltin::sorry (location_t invoc_locus, AST::MacroInvocData &invoc)
+MacroBuiltin::sorry (location_t invoc_locus, AST::MacroInvocData &invoc,
+ bool semicolon)
{
rust_sorry_at (invoc_locus, "unimplemented builtin macro: %qs",
invoc.get_path ().as_string ().c_str ());
tl::optional<AST::Fragment>
MacroBuiltin::proc_macro_builtin (location_t invoc_locus,
- AST::MacroInvocData &invoc)
+ AST::MacroInvocData &invoc, bool semicolon)
{
rust_error_at (invoc_locus, "cannot invoke derive macro: %qs",
invoc.get_path ().as_string ().c_str ());
static std::unordered_map<std::string, AST::MacroTranscriberFunc>
builtin_transcribers;
- static tl::optional<AST::Fragment>
- assert_handler (location_t invoc_locus, AST::MacroInvocData &invoc);
+ static tl::optional<AST::Fragment> assert_handler (location_t invoc_locus,
+ AST::MacroInvocData &invoc,
+ bool semicolon);
static tl::optional<AST::Fragment> file_handler (location_t invoc_locus,
- AST::MacroInvocData &invoc);
+ AST::MacroInvocData &invoc,
+ bool semicolon);
- static tl::optional<AST::Fragment>
- column_handler (location_t invoc_locus, AST::MacroInvocData &invoc);
+ static tl::optional<AST::Fragment> column_handler (location_t invoc_locus,
+ AST::MacroInvocData &invoc,
+ bool semicolon);
static tl::optional<AST::Fragment>
- include_bytes_handler (location_t invoc_locus, AST::MacroInvocData &invoc);
+ include_bytes_handler (location_t invoc_locus, AST::MacroInvocData &invoc,
+ bool semicolon);
static tl::optional<AST::Fragment>
- include_str_handler (location_t invoc_locus, AST::MacroInvocData &invoc);
+ include_str_handler (location_t invoc_locus, AST::MacroInvocData &invoc,
+ bool semicolon);
static tl::optional<AST::Fragment>
- stringify_handler (location_t invoc_locus, AST::MacroInvocData &invoc);
+ stringify_handler (location_t invoc_locus, AST::MacroInvocData &invoc,
+ bool semicolon);
static tl::optional<AST::Fragment>
- compile_error_handler (location_t invoc_locus, AST::MacroInvocData &invoc);
+ compile_error_handler (location_t invoc_locus, AST::MacroInvocData &invoc,
+ bool semicolon);
- static tl::optional<AST::Fragment>
- concat_handler (location_t invoc_locus, AST::MacroInvocData &invoc);
+ static tl::optional<AST::Fragment> concat_handler (location_t invoc_locus,
+ AST::MacroInvocData &invoc,
+ bool semicolon);
static tl::optional<AST::Fragment> env_handler (location_t invoc_locus,
- AST::MacroInvocData &invoc);
+ AST::MacroInvocData &invoc,
+ bool semicolon);
static tl::optional<AST::Fragment> cfg_handler (location_t invoc_locus,
- AST::MacroInvocData &invoc);
+ AST::MacroInvocData &invoc,
+ bool semicolon);
static tl::optional<AST::Fragment>
- include_handler (location_t invoc_locus, AST::MacroInvocData &invoc);
+ include_handler (location_t invoc_locus, AST::MacroInvocData &invoc,
+ bool semicolon);
static tl::optional<AST::Fragment> line_handler (location_t invoc_locus,
- AST::MacroInvocData &invoc);
+ AST::MacroInvocData &invoc,
+ bool semicolon);
static tl::optional<AST::Fragment> asm_handler (location_t invoc_locus,
AST::MacroInvocData &invoc,
+ bool semicolon,
bool is_global_asm);
static tl::optional<AST::Fragment>
format_args_handler (location_t invoc_locus, AST::MacroInvocData &invoc,
- AST::FormatArgs::Newline nl);
+ bool semicolon, AST::FormatArgs::Newline nl);
- static tl::optional<AST::Fragment> sorry (location_t invoc_locus,
- AST::MacroInvocData &invoc);
+ static tl::optional<AST::Fragment>
+ sorry (location_t invoc_locus, AST::MacroInvocData &invoc, bool semicolon);
/* Builtin procedural macros do not work directly on tokens, but still need a
* builtin transcriber to be considered proper builtin macros */
- static tl::optional<AST::Fragment> proc_macro_builtin (location_t,
- AST::MacroInvocData &);
+ static tl::optional<AST::Fragment>
+ proc_macro_builtin (location_t, AST::MacroInvocData &, bool);
};
} // namespace Rust
/* probably something here about parsing invoc and rules def token trees to
* token stream. if not, how would parser handle the captures of exprs and
- * stuff? on the other hand, token trees may be kind of useful in rules def as
- * creating a point where recursion can occur (like having
- * "compare_macro_match" and then it calling itself when it finds delimiters)
+ * stuff? on the other hand, token trees may be kind of useful in rules def
+ * as creating a point where recursion can occur (like having
+ * "compare_macro_match" and then it calling itself when it finds
+ * delimiters)
*/
/* find matching rule to invoc token tree, based on macro rule's matcher. if
/* TODO: it is probably better to modify AST::Token to store a pointer to a
* Lexer::Token (rather than being converted) - i.e. not so much have
- * AST::Token as a Token but rather a TokenContainer (as it is another type of
- * TokenTree). This will prevent re-conversion of Tokens between each type
- * all the time, while still allowing the heterogenous storage of token trees.
+ * AST::Token as a Token but rather a TokenContainer (as it is another type
+ * of TokenTree). This will prevent re-conversion of Tokens between each
+ * type all the time, while still allowing the heterogenous storage of token
+ * trees.
*/
AST::DelimTokenTree &invoc_token_tree = invoc.get_delim_tok_tree ();
last_invoc = *invoc.clone_macro_invocation_impl ();
last_def = *rdef;
+ rust_debug ("[ARTHUR] semicolon: %s", has_semicolon ? "yes" : "no");
+
if (rdef->is_builtin ())
- fragment = rdef->get_builtin_transcriber () (invoc.get_locus (), invoc_data)
+ fragment = rdef
+ ->get_builtin_transcriber () (invoc.get_locus (), invoc_data,
+ has_semicolon)
.value_or (AST::Fragment::create_empty ());
else
fragment = expand_decl_macro (invoc.get_locus (), invoc_data, *rdef,
void
InlineAsm::accept_vis (HIRExpressionVisitor &vis)
-{
- rust_unreachable ();
-}
+{}
void
InlineAsm::accept_vis (HIRFullVisitor &vis)
{
- rust_unreachable ();
vis.visit (*this);
}