Merge #1029
1029: Macro in trait impl r=CohenArthur a=CohenArthur Needs #1028 You can just review the last commit to avoid reviewing twice. Sorry about that! Co-authored-by: Arthur Cohen <arthur.cohen@embecosm.com>
This commit is contained in:
commit
1bb9a29688
|
@ -1511,18 +1511,51 @@ public:
|
||||||
EXPRESSION,
|
EXPRESSION,
|
||||||
ITEM,
|
ITEM,
|
||||||
STMT,
|
STMT,
|
||||||
|
EXTERN,
|
||||||
|
TRAIT,
|
||||||
|
IMPL,
|
||||||
|
TRAIT_IMPL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
NodeType kind;
|
||||||
|
|
||||||
|
// FIXME make this a union
|
||||||
|
std::unique_ptr<Expr> expr;
|
||||||
|
std::unique_ptr<Item> item;
|
||||||
|
std::unique_ptr<Stmt> stmt;
|
||||||
|
std::unique_ptr<ExternalItem> external_item;
|
||||||
|
std::unique_ptr<TraitItem> trait_item;
|
||||||
|
std::unique_ptr<InherentImplItem> impl_item;
|
||||||
|
std::unique_ptr<TraitImplItem> trait_impl_item;
|
||||||
|
|
||||||
|
public:
|
||||||
SingleASTNode (std::unique_ptr<Expr> expr)
|
SingleASTNode (std::unique_ptr<Expr> expr)
|
||||||
: kind (EXPRESSION), expr (std::move (expr)), item (nullptr), stmt (nullptr)
|
: kind (EXPRESSION), expr (std::move (expr))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
SingleASTNode (std::unique_ptr<Item> item)
|
SingleASTNode (std::unique_ptr<Item> item)
|
||||||
: kind (ITEM), expr (nullptr), item (std::move (item)), stmt (nullptr)
|
: kind (ITEM), item (std::move (item))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
SingleASTNode (std::unique_ptr<Stmt> stmt)
|
SingleASTNode (std::unique_ptr<Stmt> stmt)
|
||||||
: kind (STMT), expr (nullptr), item (nullptr), stmt (std::move (stmt))
|
: kind (STMT), stmt (std::move (stmt))
|
||||||
|
{}
|
||||||
|
|
||||||
|
SingleASTNode (std::unique_ptr<ExternalItem> item)
|
||||||
|
: kind (EXTERN), external_item (std::move (item))
|
||||||
|
{}
|
||||||
|
|
||||||
|
SingleASTNode (std::unique_ptr<TraitItem> item)
|
||||||
|
: kind (TRAIT), trait_item (std::move (item))
|
||||||
|
{}
|
||||||
|
|
||||||
|
SingleASTNode (std::unique_ptr<InherentImplItem> item)
|
||||||
|
: kind (IMPL), impl_item (std::move (item))
|
||||||
|
{}
|
||||||
|
|
||||||
|
SingleASTNode (std::unique_ptr<TraitImplItem> trait_impl_item)
|
||||||
|
: kind (TRAIT_IMPL), trait_impl_item (std::move (trait_impl_item))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
SingleASTNode (SingleASTNode const &other)
|
SingleASTNode (SingleASTNode const &other)
|
||||||
|
@ -1541,6 +1574,22 @@ public:
|
||||||
case STMT:
|
case STMT:
|
||||||
stmt = other.stmt->clone_stmt ();
|
stmt = other.stmt->clone_stmt ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EXTERN:
|
||||||
|
external_item = other.external_item->clone_external_item ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRAIT:
|
||||||
|
trait_item = other.trait_item->clone_trait_item ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IMPL:
|
||||||
|
impl_item = other.impl_item->clone_inherent_impl_item ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRAIT_IMPL:
|
||||||
|
trait_impl_item = other.trait_impl_item->clone_trait_impl_item ();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1560,6 +1609,22 @@ public:
|
||||||
case STMT:
|
case STMT:
|
||||||
stmt = other.stmt->clone_stmt ();
|
stmt = other.stmt->clone_stmt ();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EXTERN:
|
||||||
|
external_item = other.external_item->clone_external_item ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRAIT:
|
||||||
|
trait_item = other.trait_item->clone_trait_item ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IMPL:
|
||||||
|
impl_item = other.impl_item->clone_inherent_impl_item ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRAIT_IMPL:
|
||||||
|
trait_impl_item = other.trait_impl_item->clone_trait_impl_item ();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -1569,7 +1634,7 @@ public:
|
||||||
|
|
||||||
NodeType get_kind () const { return kind; }
|
NodeType get_kind () const { return kind; }
|
||||||
|
|
||||||
std::unique_ptr<Expr> &get_inner ()
|
std::unique_ptr<Expr> &get_expr ()
|
||||||
{
|
{
|
||||||
rust_assert (kind == EXPRESSION);
|
rust_assert (kind == EXPRESSION);
|
||||||
return expr;
|
return expr;
|
||||||
|
@ -1610,6 +1675,30 @@ public:
|
||||||
return std::move (item);
|
return std::move (item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<TraitItem> take_trait_item ()
|
||||||
|
{
|
||||||
|
rust_assert (!is_error ());
|
||||||
|
return std::move (trait_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ExternalItem> take_external_item ()
|
||||||
|
{
|
||||||
|
rust_assert (!is_error ());
|
||||||
|
return std::move (external_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<InherentImplItem> take_impl_item ()
|
||||||
|
{
|
||||||
|
rust_assert (!is_error ());
|
||||||
|
return std::move (impl_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<TraitImplItem> take_trait_impl_item ()
|
||||||
|
{
|
||||||
|
rust_assert (!is_error ());
|
||||||
|
return std::move (trait_impl_item);
|
||||||
|
}
|
||||||
|
|
||||||
void accept_vis (ASTVisitor &vis)
|
void accept_vis (ASTVisitor &vis)
|
||||||
{
|
{
|
||||||
switch (kind)
|
switch (kind)
|
||||||
|
@ -1625,6 +1714,22 @@ public:
|
||||||
case STMT:
|
case STMT:
|
||||||
stmt->accept_vis (vis);
|
stmt->accept_vis (vis);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case EXTERN:
|
||||||
|
external_item->accept_vis (vis);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRAIT:
|
||||||
|
trait_item->accept_vis (vis);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IMPL:
|
||||||
|
impl_item->accept_vis (vis);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRAIT_IMPL:
|
||||||
|
trait_impl_item->accept_vis (vis);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1638,9 +1743,18 @@ public:
|
||||||
return item == nullptr;
|
return item == nullptr;
|
||||||
case STMT:
|
case STMT:
|
||||||
return stmt == nullptr;
|
return stmt == nullptr;
|
||||||
default:
|
case EXTERN:
|
||||||
return true;
|
return external_item == nullptr;
|
||||||
|
case TRAIT:
|
||||||
|
return trait_item == nullptr;
|
||||||
|
case IMPL:
|
||||||
|
return impl_item == nullptr;
|
||||||
|
case TRAIT_IMPL:
|
||||||
|
return trait_impl_item == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gcc_unreachable ();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string as_string ()
|
std::string as_string ()
|
||||||
|
@ -1653,18 +1767,19 @@ public:
|
||||||
return "Item: " + item->as_string ();
|
return "Item: " + item->as_string ();
|
||||||
case STMT:
|
case STMT:
|
||||||
return "Stmt: " + stmt->as_string ();
|
return "Stmt: " + stmt->as_string ();
|
||||||
default:
|
case EXTERN:
|
||||||
return "";
|
return "External Item: " + external_item->as_string ();
|
||||||
|
case TRAIT:
|
||||||
|
return "Trait Item: " + trait_item->as_string ();
|
||||||
|
case IMPL:
|
||||||
|
return "Impl Item: " + impl_item->as_string ();
|
||||||
|
case TRAIT_IMPL:
|
||||||
|
return "Trait Impl Item: " + impl_item->as_string ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gcc_unreachable ();
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
NodeType kind;
|
|
||||||
|
|
||||||
// FIXME make this a union
|
|
||||||
std::unique_ptr<Expr> expr;
|
|
||||||
std::unique_ptr<Item> item;
|
|
||||||
std::unique_ptr<Stmt> stmt;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Basically, a "fragment" that can be incorporated into the AST, created as
|
/* Basically, a "fragment" that can be incorporated into the AST, created as
|
||||||
|
|
|
@ -460,6 +460,7 @@ class MacroInvocation : public TypeNoBounds,
|
||||||
public TraitItem,
|
public TraitItem,
|
||||||
public TraitImplItem,
|
public TraitImplItem,
|
||||||
public InherentImplItem,
|
public InherentImplItem,
|
||||||
|
public ExternalItem,
|
||||||
public ExprWithoutBlock
|
public ExprWithoutBlock
|
||||||
{
|
{
|
||||||
std::vector<Attribute> outer_attrs;
|
std::vector<Attribute> outer_attrs;
|
||||||
|
@ -537,6 +538,11 @@ protected:
|
||||||
return clone_macro_invocation_impl ();
|
return clone_macro_invocation_impl ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MacroInvocation *clone_external_item_impl () const final override
|
||||||
|
{
|
||||||
|
return clone_macro_invocation_impl ();
|
||||||
|
}
|
||||||
|
|
||||||
/*virtual*/ MacroInvocation *clone_macro_invocation_impl () const
|
/*virtual*/ MacroInvocation *clone_macro_invocation_impl () const
|
||||||
{
|
{
|
||||||
return new MacroInvocation (*this);
|
return new MacroInvocation (*this);
|
||||||
|
|
|
@ -1114,8 +1114,6 @@ AttrVisitor::visit (AST::ClosureExprInner &expr)
|
||||||
void
|
void
|
||||||
AttrVisitor::visit (AST::BlockExpr &expr)
|
AttrVisitor::visit (AST::BlockExpr &expr)
|
||||||
{
|
{
|
||||||
expander.push_context (MacroExpander::BLOCK);
|
|
||||||
|
|
||||||
// initial strip test based on outer attrs
|
// initial strip test based on outer attrs
|
||||||
expander.expand_cfg_attrs (expr.get_outer_attrs ());
|
expander.expand_cfg_attrs (expr.get_outer_attrs ());
|
||||||
if (expander.fails_cfg_with_expand (expr.get_outer_attrs ()))
|
if (expander.fails_cfg_with_expand (expr.get_outer_attrs ()))
|
||||||
|
@ -1135,31 +1133,13 @@ AttrVisitor::visit (AST::BlockExpr &expr)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// strip all statements
|
std::function<std::unique_ptr<AST::Stmt> (AST::SingleASTNode)> extractor
|
||||||
auto &stmts = expr.get_statements ();
|
= [] (AST::SingleASTNode node) { return node.take_stmt (); };
|
||||||
for (auto it = stmts.begin (); it != stmts.end ();)
|
|
||||||
{
|
|
||||||
auto &stmt = *it;
|
|
||||||
|
|
||||||
stmt->accept_vis (*this);
|
expand_macro_children (MacroExpander::BLOCK, expr.get_statements (),
|
||||||
|
extractor);
|
||||||
|
|
||||||
auto fragment = expander.take_expanded_fragment (*this);
|
expander.push_context (MacroExpander::BLOCK);
|
||||||
if (fragment.should_expand ())
|
|
||||||
{
|
|
||||||
// Remove the current expanded invocation
|
|
||||||
it = stmts.erase (it);
|
|
||||||
for (auto &node : fragment.get_nodes ())
|
|
||||||
{
|
|
||||||
it = stmts.insert (it, node.take_stmt ());
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (stmt->is_marked_for_strip ())
|
|
||||||
it = stmts.erase (it);
|
|
||||||
else
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// strip tail expression if exists - can actually fully remove it
|
// strip tail expression if exists - can actually fully remove it
|
||||||
if (expr.has_tail_expr ())
|
if (expr.has_tail_expr ())
|
||||||
|
@ -2489,8 +2469,11 @@ AttrVisitor::visit (AST::Trait &trait)
|
||||||
if (trait.has_where_clause ())
|
if (trait.has_where_clause ())
|
||||||
expand_where_clause (trait.get_where_clause ());
|
expand_where_clause (trait.get_where_clause ());
|
||||||
|
|
||||||
// strip trait items if required
|
std::function<std::unique_ptr<AST::TraitItem> (AST::SingleASTNode)> extractor
|
||||||
expand_pointer_allow_strip (trait.get_trait_items ());
|
= [] (AST::SingleASTNode node) { return node.take_trait_item (); };
|
||||||
|
|
||||||
|
expand_macro_children (MacroExpander::TRAIT, trait.get_trait_items (),
|
||||||
|
extractor);
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
AttrVisitor::visit (AST::InherentImpl &impl)
|
AttrVisitor::visit (AST::InherentImpl &impl)
|
||||||
|
@ -2523,8 +2506,11 @@ AttrVisitor::visit (AST::InherentImpl &impl)
|
||||||
if (impl.has_where_clause ())
|
if (impl.has_where_clause ())
|
||||||
expand_where_clause (impl.get_where_clause ());
|
expand_where_clause (impl.get_where_clause ());
|
||||||
|
|
||||||
// strip inherent impl items if required
|
std::function<std::unique_ptr<AST::InherentImplItem> (AST::SingleASTNode)>
|
||||||
expand_pointer_allow_strip (impl.get_impl_items ());
|
extractor = [] (AST::SingleASTNode node) { return node.take_impl_item (); };
|
||||||
|
|
||||||
|
expand_macro_children (MacroExpander::IMPL, impl.get_impl_items (),
|
||||||
|
extractor);
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
AttrVisitor::visit (AST::TraitImpl &impl)
|
AttrVisitor::visit (AST::TraitImpl &impl)
|
||||||
|
@ -2563,8 +2549,12 @@ AttrVisitor::visit (AST::TraitImpl &impl)
|
||||||
if (impl.has_where_clause ())
|
if (impl.has_where_clause ())
|
||||||
expand_where_clause (impl.get_where_clause ());
|
expand_where_clause (impl.get_where_clause ());
|
||||||
|
|
||||||
// strip trait impl items if required
|
std::function<std::unique_ptr<AST::TraitImplItem> (AST::SingleASTNode)>
|
||||||
expand_pointer_allow_strip (impl.get_impl_items ());
|
extractor
|
||||||
|
= [] (AST::SingleASTNode node) { return node.take_trait_impl_item (); };
|
||||||
|
|
||||||
|
expand_macro_children (MacroExpander::TRAIT_IMPL, impl.get_impl_items (),
|
||||||
|
extractor);
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
AttrVisitor::visit (AST::ExternalStaticItem &item)
|
AttrVisitor::visit (AST::ExternalStaticItem &item)
|
||||||
|
@ -2659,8 +2649,12 @@ AttrVisitor::visit (AST::ExternBlock &block)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// strip external items if required
|
std::function<std::unique_ptr<AST::ExternalItem> (AST::SingleASTNode)>
|
||||||
expand_pointer_allow_strip (block.get_extern_items ());
|
extractor
|
||||||
|
= [] (AST::SingleASTNode node) { return node.take_external_item (); };
|
||||||
|
|
||||||
|
expand_macro_children (MacroExpander::EXTERN, block.get_extern_items (),
|
||||||
|
extractor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// I don't think it would be possible to strip macros without expansion
|
// I don't think it would be possible to strip macros without expansion
|
||||||
|
|
|
@ -40,6 +40,54 @@ public:
|
||||||
void expand_trait_function_decl (AST::TraitFunctionDecl &decl);
|
void expand_trait_function_decl (AST::TraitFunctionDecl &decl);
|
||||||
void expand_trait_method_decl (AST::TraitMethodDecl &decl);
|
void expand_trait_method_decl (AST::TraitMethodDecl &decl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expand a set of values, erasing them if they are marked for strip, and
|
||||||
|
* replacing them with expanded macro nodes if necessary.
|
||||||
|
* This function is slightly different from `expand_pointer_allow_strip` as
|
||||||
|
* it can only be called in certain expansion contexts - where macro
|
||||||
|
* invocations are allowed.
|
||||||
|
*
|
||||||
|
* @param ctx Context to use for macro expansion
|
||||||
|
* @param values Iterable reference over values to replace or erase
|
||||||
|
* @param extractor Function to call when replacing values with the content
|
||||||
|
* of an expanded AST node
|
||||||
|
*/
|
||||||
|
template <typename T, typename U>
|
||||||
|
void expand_macro_children (MacroExpander::ContextType ctx, T &values,
|
||||||
|
std::function<U (AST::SingleASTNode)> extractor)
|
||||||
|
{
|
||||||
|
expander.push_context (ctx);
|
||||||
|
|
||||||
|
for (auto it = values.begin (); it != values.end ();)
|
||||||
|
{
|
||||||
|
auto &value = *it;
|
||||||
|
|
||||||
|
// mark for stripping if required
|
||||||
|
value->accept_vis (*this);
|
||||||
|
|
||||||
|
auto fragment = expander.take_expanded_fragment (*this);
|
||||||
|
if (fragment.should_expand ())
|
||||||
|
{
|
||||||
|
it = values.erase (it);
|
||||||
|
for (auto &node : fragment.get_nodes ())
|
||||||
|
{
|
||||||
|
it = values.insert (it, extractor (node));
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (value->is_marked_for_strip ())
|
||||||
|
{
|
||||||
|
it = values.erase (it);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expander.pop_context ();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T> void expand_pointer_allow_strip (T &values)
|
template <typename T> void expand_pointer_allow_strip (T &values)
|
||||||
{
|
{
|
||||||
for (auto it = values.begin (); it != values.end ();)
|
for (auto it = values.begin (); it != values.end ();)
|
||||||
|
@ -48,11 +96,14 @@ public:
|
||||||
|
|
||||||
// mark for stripping if required
|
// mark for stripping if required
|
||||||
value->accept_vis (*this);
|
value->accept_vis (*this);
|
||||||
|
|
||||||
if (value->is_marked_for_strip ())
|
if (value->is_marked_for_strip ())
|
||||||
it = values.erase (it);
|
{
|
||||||
|
it = values.erase (it);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
++it;
|
{
|
||||||
|
++it;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -786,7 +786,6 @@ parse_many (Parser<MacroInvocLexer> &parser, TokenId &delimiter,
|
||||||
std::function<AST::SingleASTNode ()> parse_fn)
|
std::function<AST::SingleASTNode ()> parse_fn)
|
||||||
{
|
{
|
||||||
std::vector<AST::SingleASTNode> nodes;
|
std::vector<AST::SingleASTNode> nodes;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (parser.peek_current_token ()->get_id () == delimiter)
|
if (parser.peek_current_token ()->get_id () == delimiter)
|
||||||
|
@ -814,6 +813,68 @@ transcribe_many_items (Parser<MacroInvocLexer> &parser, TokenId &delimiter)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transcribe 0 or more external items from a macro invocation
|
||||||
|
*
|
||||||
|
* @param parser Parser to extract items from
|
||||||
|
* @param delimiter Id of the token on which parsing should stop
|
||||||
|
*/
|
||||||
|
static std::vector<AST::SingleASTNode>
|
||||||
|
transcribe_many_ext (Parser<MacroInvocLexer> &parser, TokenId &delimiter)
|
||||||
|
{
|
||||||
|
return parse_many (parser, delimiter, [&parser] () {
|
||||||
|
auto item = parser.parse_external_item ();
|
||||||
|
return AST::SingleASTNode (std::move (item));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transcribe 0 or more trait items from a macro invocation
|
||||||
|
*
|
||||||
|
* @param parser Parser to extract items from
|
||||||
|
* @param delimiter Id of the token on which parsing should stop
|
||||||
|
*/
|
||||||
|
static std::vector<AST::SingleASTNode>
|
||||||
|
transcribe_many_trait_items (Parser<MacroInvocLexer> &parser,
|
||||||
|
TokenId &delimiter)
|
||||||
|
{
|
||||||
|
return parse_many (parser, delimiter, [&parser] () {
|
||||||
|
auto item = parser.parse_trait_item ();
|
||||||
|
return AST::SingleASTNode (std::move (item));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transcribe 0 or more impl items from a macro invocation
|
||||||
|
*
|
||||||
|
* @param parser Parser to extract items from
|
||||||
|
* @param delimiter Id of the token on which parsing should stop
|
||||||
|
*/
|
||||||
|
static std::vector<AST::SingleASTNode>
|
||||||
|
transcribe_many_impl_items (Parser<MacroInvocLexer> &parser, TokenId &delimiter)
|
||||||
|
{
|
||||||
|
return parse_many (parser, delimiter, [&parser] () {
|
||||||
|
auto item = parser.parse_inherent_impl_item ();
|
||||||
|
return AST::SingleASTNode (std::move (item));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transcribe 0 or more trait impl items from a macro invocation
|
||||||
|
*
|
||||||
|
* @param parser Parser to extract items from
|
||||||
|
* @param delimiter Id of the token on which parsing should stop
|
||||||
|
*/
|
||||||
|
static std::vector<AST::SingleASTNode>
|
||||||
|
transcribe_many_trait_impl_items (Parser<MacroInvocLexer> &parser,
|
||||||
|
TokenId &delimiter)
|
||||||
|
{
|
||||||
|
return parse_many (parser, delimiter, [&parser] () {
|
||||||
|
auto item = parser.parse_trait_impl_item ();
|
||||||
|
return AST::SingleASTNode (std::move (item));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transcribe 0 or more statements from a macro invocation
|
* Transcribe 0 or more statements from a macro invocation
|
||||||
*
|
*
|
||||||
|
@ -845,6 +906,60 @@ transcribe_expression (Parser<MacroInvocLexer> &parser)
|
||||||
return {AST::SingleASTNode (std::move (expr))};
|
return {AST::SingleASTNode (std::move (expr))};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::vector<AST::SingleASTNode>
|
||||||
|
transcribe_on_delimiter (Parser<MacroInvocLexer> &parser, bool semicolon,
|
||||||
|
AST::DelimType delimiter, TokenId last_token_id)
|
||||||
|
{
|
||||||
|
if (semicolon || delimiter == AST::DelimType::CURLY)
|
||||||
|
return transcribe_many_stmts (parser, last_token_id);
|
||||||
|
else
|
||||||
|
return transcribe_expression (parser);
|
||||||
|
} // namespace Rust
|
||||||
|
|
||||||
|
static std::vector<AST::SingleASTNode>
|
||||||
|
transcribe_context (MacroExpander::ContextType ctx,
|
||||||
|
Parser<MacroInvocLexer> &parser, bool semicolon,
|
||||||
|
AST::DelimType delimiter, TokenId last_token_id)
|
||||||
|
{
|
||||||
|
// The flow-chart in order to choose a parsing function is as follows:
|
||||||
|
//
|
||||||
|
// [switch special context]
|
||||||
|
// -- Item --> parser.parse_item();
|
||||||
|
// -- Trait --> parser.parse_trait_item();
|
||||||
|
// -- Impl --> parser.parse_impl_item();
|
||||||
|
// -- Extern --> parser.parse_extern_item();
|
||||||
|
// -- None --> [has semicolon?]
|
||||||
|
// -- Yes --> parser.parse_stmt();
|
||||||
|
// -- No --> [switch invocation.delimiter()]
|
||||||
|
// -- { } --> parser.parse_stmt();
|
||||||
|
// -- _ --> parser.parse_expr(); // once!
|
||||||
|
|
||||||
|
// If there is a semicolon OR we are expanding a MacroInvocationSemi, then
|
||||||
|
// we can parse multiple items. Otherwise, parse *one* expression
|
||||||
|
|
||||||
|
switch (ctx)
|
||||||
|
{
|
||||||
|
case MacroExpander::ContextType::ITEM:
|
||||||
|
return transcribe_many_items (parser, last_token_id);
|
||||||
|
break;
|
||||||
|
case MacroExpander::ContextType::TRAIT:
|
||||||
|
return transcribe_many_trait_items (parser, last_token_id);
|
||||||
|
break;
|
||||||
|
case MacroExpander::ContextType::IMPL:
|
||||||
|
return transcribe_many_impl_items (parser, last_token_id);
|
||||||
|
break;
|
||||||
|
case MacroExpander::ContextType::TRAIT_IMPL:
|
||||||
|
return transcribe_many_trait_impl_items (parser, last_token_id);
|
||||||
|
break;
|
||||||
|
case MacroExpander::ContextType::EXTERN:
|
||||||
|
return transcribe_many_ext (parser, last_token_id);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return transcribe_on_delimiter (parser, semicolon, delimiter,
|
||||||
|
last_token_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AST::ASTFragment
|
AST::ASTFragment
|
||||||
MacroExpander::transcribe_rule (
|
MacroExpander::transcribe_rule (
|
||||||
AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree,
|
AST::MacroRule &match_rule, AST::DelimTokenTree &invoc_token_tree,
|
||||||
|
@ -864,18 +979,15 @@ MacroExpander::transcribe_rule (
|
||||||
std::vector<std::unique_ptr<AST::Token>> substituted_tokens
|
std::vector<std::unique_ptr<AST::Token>> substituted_tokens
|
||||||
= substitute_context.substitute_tokens ();
|
= substitute_context.substitute_tokens ();
|
||||||
|
|
||||||
|
// handy for debugging
|
||||||
|
// for (auto &tok : substituted_tokens)
|
||||||
|
// rust_debug ("[tok] %s", tok->as_string ().c_str ());
|
||||||
|
|
||||||
// parse it to an ASTFragment
|
// parse it to an ASTFragment
|
||||||
MacroInvocLexer lex (std::move (substituted_tokens));
|
MacroInvocLexer lex (std::move (substituted_tokens));
|
||||||
Parser<MacroInvocLexer> parser (std::move (lex));
|
Parser<MacroInvocLexer> parser (std::move (lex));
|
||||||
|
|
||||||
// handy for debugging
|
|
||||||
// for (auto &tok : substituted_tokens)
|
|
||||||
// {
|
|
||||||
// rust_debug ("tok: [%s]", tok->as_string ().c_str ());
|
|
||||||
// }
|
|
||||||
|
|
||||||
auto last_token_id = TokenId::RIGHT_CURLY;
|
auto last_token_id = TokenId::RIGHT_CURLY;
|
||||||
std::vector<AST::SingleASTNode> nodes;
|
|
||||||
|
|
||||||
// this is used so we can check that we delimit the stream correctly.
|
// this is used so we can check that we delimit the stream correctly.
|
||||||
switch (transcribe_tree.get_delim_type ())
|
switch (transcribe_tree.get_delim_type ())
|
||||||
|
@ -905,33 +1017,9 @@ MacroExpander::transcribe_rule (
|
||||||
// as a statement (either via ExpressionStatement or
|
// as a statement (either via ExpressionStatement or
|
||||||
// MacroInvocationWithSemi)
|
// MacroInvocationWithSemi)
|
||||||
|
|
||||||
// The flow-chart in order to choose a parsing function is as follows:
|
auto nodes
|
||||||
//
|
= transcribe_context (ctx, parser, semicolon,
|
||||||
// [is in item context?]
|
invoc_token_tree.get_delim_type (), last_token_id);
|
||||||
// -- Yes --> parser.parse_item();
|
|
||||||
// -- No --> [has semicolon?]
|
|
||||||
// -- Yes --> parser.parse_stmt();
|
|
||||||
// -- No --> [switch invocation.delimiter()]
|
|
||||||
// -- { } --> parser.parse_stmt();
|
|
||||||
// -- _ --> parser.parse_expr();
|
|
||||||
|
|
||||||
// If there is a semicolon OR we are expanding a MacroInvocationSemi, then
|
|
||||||
// we can parse multiple items. Otherwise, parse *one* expression
|
|
||||||
|
|
||||||
if (ctx == ContextType::ITEM)
|
|
||||||
nodes = transcribe_many_items (parser, last_token_id);
|
|
||||||
else if (semicolon)
|
|
||||||
nodes = transcribe_many_stmts (parser, last_token_id);
|
|
||||||
else
|
|
||||||
switch (invoc_token_tree.get_delim_type ())
|
|
||||||
{
|
|
||||||
case AST::CURLY:
|
|
||||||
nodes = transcribe_many_stmts (parser, last_token_id);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
nodes = transcribe_expression (parser);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// emit any errors
|
// emit any errors
|
||||||
if (parser.has_errors ())
|
if (parser.has_errors ())
|
||||||
|
|
|
@ -187,6 +187,10 @@ struct MacroExpander
|
||||||
{
|
{
|
||||||
ITEM,
|
ITEM,
|
||||||
BLOCK,
|
BLOCK,
|
||||||
|
EXTERN,
|
||||||
|
TRAIT,
|
||||||
|
IMPL,
|
||||||
|
TRAIT_IMPL,
|
||||||
};
|
};
|
||||||
|
|
||||||
ExpansionCfg cfg;
|
ExpansionCfg cfg;
|
||||||
|
|
|
@ -5251,12 +5251,11 @@ Parser<ManagedTokenSource>::parse_inherent_impl_item ()
|
||||||
switch (t->get_id ())
|
switch (t->get_id ())
|
||||||
{
|
{
|
||||||
case IDENTIFIER:
|
case IDENTIFIER:
|
||||||
|
// FIXME: Arthur: Do we need to some lookahead here?
|
||||||
|
return parse_macro_invocation_semi (outer_attrs);
|
||||||
case SUPER:
|
case SUPER:
|
||||||
case SELF:
|
case SELF:
|
||||||
case CRATE:
|
case CRATE:
|
||||||
case DOLLAR_SIGN:
|
|
||||||
// these seem to be SimplePath tokens, so this is a macro invocation semi
|
|
||||||
return parse_macro_invocation_semi (std::move (outer_attrs));
|
|
||||||
case PUB: {
|
case PUB: {
|
||||||
// visibility, so not a macro invocation semi - must be constant,
|
// visibility, so not a macro invocation semi - must be constant,
|
||||||
// function, or method
|
// function, or method
|
||||||
|
@ -5813,6 +5812,8 @@ Parser<ManagedTokenSource>::parse_external_item ()
|
||||||
const_TokenPtr t = lexer.peek_token ();
|
const_TokenPtr t = lexer.peek_token ();
|
||||||
switch (t->get_id ())
|
switch (t->get_id ())
|
||||||
{
|
{
|
||||||
|
case IDENTIFIER:
|
||||||
|
return parse_macro_invocation_semi (outer_attrs);
|
||||||
case STATIC_TOK: {
|
case STATIC_TOK: {
|
||||||
// parse extern static item
|
// parse extern static item
|
||||||
lexer.skip_token ();
|
lexer.skip_token ();
|
||||||
|
|
|
@ -135,6 +135,10 @@ public:
|
||||||
*/
|
*/
|
||||||
std::unique_ptr<AST::Stmt> parse_stmt (bool allow_no_semi = false);
|
std::unique_ptr<AST::Stmt> parse_stmt (bool allow_no_semi = false);
|
||||||
std::unique_ptr<AST::Type> parse_type ();
|
std::unique_ptr<AST::Type> parse_type ();
|
||||||
|
std::unique_ptr<AST::ExternalItem> parse_external_item ();
|
||||||
|
std::unique_ptr<AST::TraitItem> parse_trait_item ();
|
||||||
|
std::unique_ptr<AST::InherentImplItem> parse_inherent_impl_item ();
|
||||||
|
std::unique_ptr<AST::TraitImplItem> parse_trait_impl_item ();
|
||||||
AST::PathInExpression parse_path_in_expression ();
|
AST::PathInExpression parse_path_in_expression ();
|
||||||
std::vector<std::unique_ptr<AST::LifetimeParam> > parse_lifetime_params ();
|
std::vector<std::unique_ptr<AST::LifetimeParam> > parse_lifetime_params ();
|
||||||
AST::Visibility parse_visibility ();
|
AST::Visibility parse_visibility ();
|
||||||
|
@ -285,7 +289,6 @@ private:
|
||||||
AST::AttrVec outer_attrs);
|
AST::AttrVec outer_attrs);
|
||||||
std::unique_ptr<AST::Trait> parse_trait (AST::Visibility vis,
|
std::unique_ptr<AST::Trait> parse_trait (AST::Visibility vis,
|
||||||
AST::AttrVec outer_attrs);
|
AST::AttrVec outer_attrs);
|
||||||
std::unique_ptr<AST::TraitItem> parse_trait_item ();
|
|
||||||
std::unique_ptr<AST::TraitItemType>
|
std::unique_ptr<AST::TraitItemType>
|
||||||
parse_trait_type (AST::AttrVec outer_attrs);
|
parse_trait_type (AST::AttrVec outer_attrs);
|
||||||
std::unique_ptr<AST::TraitItemConst>
|
std::unique_ptr<AST::TraitItemConst>
|
||||||
|
@ -293,17 +296,14 @@ private:
|
||||||
AST::SelfParam parse_self_param ();
|
AST::SelfParam parse_self_param ();
|
||||||
std::unique_ptr<AST::Impl> parse_impl (AST::Visibility vis,
|
std::unique_ptr<AST::Impl> parse_impl (AST::Visibility vis,
|
||||||
AST::AttrVec outer_attrs);
|
AST::AttrVec outer_attrs);
|
||||||
std::unique_ptr<AST::InherentImplItem> parse_inherent_impl_item ();
|
|
||||||
std::unique_ptr<AST::InherentImplItem>
|
std::unique_ptr<AST::InherentImplItem>
|
||||||
parse_inherent_impl_function_or_method (AST::Visibility vis,
|
parse_inherent_impl_function_or_method (AST::Visibility vis,
|
||||||
AST::AttrVec outer_attrs);
|
AST::AttrVec outer_attrs);
|
||||||
std::unique_ptr<AST::TraitImplItem> parse_trait_impl_item ();
|
|
||||||
std::unique_ptr<AST::TraitImplItem>
|
std::unique_ptr<AST::TraitImplItem>
|
||||||
parse_trait_impl_function_or_method (AST::Visibility vis,
|
parse_trait_impl_function_or_method (AST::Visibility vis,
|
||||||
AST::AttrVec outer_attrs);
|
AST::AttrVec outer_attrs);
|
||||||
std::unique_ptr<AST::ExternBlock>
|
std::unique_ptr<AST::ExternBlock>
|
||||||
parse_extern_block (AST::Visibility vis, AST::AttrVec outer_attrs);
|
parse_extern_block (AST::Visibility vis, AST::AttrVec outer_attrs);
|
||||||
std::unique_ptr<AST::ExternalItem> parse_external_item ();
|
|
||||||
AST::NamedFunctionParam parse_named_function_param (AST::AttrVec outer_attrs
|
AST::NamedFunctionParam parse_named_function_param (AST::AttrVec outer_attrs
|
||||||
= AST::AttrVec ());
|
= AST::AttrVec ());
|
||||||
AST::Method parse_method ();
|
AST::Method parse_method ();
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
macro_rules! define_trait {
|
||||||
|
($assoc:ident, $i:item) => {
|
||||||
|
type $assoc;
|
||||||
|
|
||||||
|
$i
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
trait DefinedThroughMacros {
|
||||||
|
define_trait!(
|
||||||
|
Inner,
|
||||||
|
fn takes_inner(i: Self::Inner) -> Self::Inner {
|
||||||
|
i
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
macro_rules! c_fn {
|
||||||
|
{$name:ident ($($arg_name:ident $arg_ty:ty),*) -> $ret_ty:ty} => {
|
||||||
|
fn $name($($arg_name: $arg_ty)*) -> $ret_ty;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
c_fn! {puts (s *const i8) -> i64}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
macro_rules! print {
|
||||||
|
() => {
|
||||||
|
fn puts(s: *const i8);
|
||||||
|
fn printf(fmt: *const i8, ...);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
print! {}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
macro_rules! maybe_impl {
|
||||||
|
($left:ident, $right:ident, $l_fn:ident, $r_fn:ident) => {
|
||||||
|
fn $l_fn(value: T) -> Maybe<T> {
|
||||||
|
Maybe::$left(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn $r_fn() -> Maybe<T> {
|
||||||
|
Maybe::$right
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Maybe<T> {
|
||||||
|
Just(T),
|
||||||
|
Nothing,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Maybe<T> {
|
||||||
|
maybe_impl!(Just, Nothing, just, nothing);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let _ = Maybe::just(14);
|
||||||
|
let _: Maybe<i32> = Maybe::nothing();
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
trait Valuable {
|
||||||
|
const VALUE: i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Something;
|
||||||
|
|
||||||
|
macro_rules! implement {
|
||||||
|
() => {
|
||||||
|
const VALUE: i32 = 18;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Valuable for Something {
|
||||||
|
implement!();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> i32 {
|
||||||
|
Something::VALUE - 18
|
||||||
|
}
|
Loading…
Reference in New Issue