Skip to content

Commit 9fb06d6

Browse files
bors[bot]philberty
andauthored
Merge #938
938: First pass at declarative macro expansion r=philberty a=philberty This does not support repetition matchers but it supports simple declarative macros and transcribes them. The approach taken here is that we reuse our existing parser to call the apropriate functions as specified as part of the MacroFragmentType enum if the parser does not have errors parsing that item then it must be a match. Then once we match a rule we have a map of the token begin/end offsets for each fragment match, this is then used to adjust and create a new token stream for the macro rule definition so that when we feed it to the parser the tokens are already substituted. The resulting expression or item is then attached to the respective macro invocation and this is then name resolved and used for hir lowering. Fixes #17 #22 Addresses #573 Co-authored-by: Philip Herron <[email protected]>
2 parents 752bf6c + 37415ee commit 9fb06d6

31 files changed

+1383
-269
lines changed

gcc/rust/ast/rust-ast-full-test.cc

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4387,13 +4387,6 @@ std::vector<std::unique_ptr<Token> >
43874387
DelimTokenTree::to_token_stream () const
43884388
{
43894389
std::vector<std::unique_ptr<Token> > tokens;
4390-
4391-
// simulate presence of delimiters
4392-
const_TokenPtr left_paren
4393-
= Rust::Token::make (LEFT_PAREN, Linemap::unknown_location ());
4394-
tokens.push_back (
4395-
std::unique_ptr<Token> (new Token (std::move (left_paren))));
4396-
43974390
for (const auto &tree : token_trees)
43984391
{
43994392
std::vector<std::unique_ptr<Token> > stream = tree->to_token_stream ();
@@ -4402,13 +4395,7 @@ DelimTokenTree::to_token_stream () const
44024395
std::make_move_iterator (stream.end ()));
44034396
}
44044397

4405-
const_TokenPtr right_paren
4406-
= Rust::Token::make (RIGHT_PAREN, Linemap::unknown_location ());
4407-
tokens.push_back (
4408-
std::unique_ptr<Token> (new Token (std::move (right_paren))));
4409-
44104398
tokens.shrink_to_fit ();
4411-
44124399
return tokens;
44134400
}
44144401

gcc/rust/ast/rust-ast.h

Lines changed: 191 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,13 @@
2222

2323
#include "rust-system.h"
2424
#include "rust-hir-map.h"
25-
26-
// gccrs imports
27-
// required for AST::Token
2825
#include "rust-token.h"
2926
#include "rust-location.h"
3027

3128
namespace Rust {
3229
// TODO: remove typedefs and make actual types for these
3330
typedef std::string Identifier;
3431
typedef int TupleIndex;
35-
3632
struct Session;
3733

3834
namespace AST {
@@ -48,34 +44,6 @@ enum DelimType
4844
CURLY
4945
};
5046

51-
// Base AST node object - TODO is this really required or useful? Where to draw
52-
// line?
53-
/*class Node {
54-
public:
55-
// Gets node's Location.
56-
Location get_locus() const {
57-
return loc;
58-
}
59-
60-
// Sets node's Location.
61-
void set_locus(Location loc_) {
62-
loc = loc_;
63-
}
64-
65-
// Get node output as a string. Pure virtual.
66-
virtual std::string as_string() const = 0;
67-
68-
virtual ~Node() {}
69-
70-
// TODO: constructor including Location? Make all derived classes have
71-
Location?
72-
73-
private:
74-
// The node's location.
75-
Location loc;
76-
};*/
77-
// decided to not have node as a "node" would never need to be stored
78-
7947
// forward decl for use in token tree method
8048
class Token;
8149

@@ -108,6 +76,14 @@ class TokenTree
10876
class MacroMatch
10977
{
11078
public:
79+
enum MacroMatchType
80+
{
81+
Fragment,
82+
Repetition,
83+
Matcher,
84+
Tok
85+
};
86+
11187
virtual ~MacroMatch () {}
11288

11389
virtual std::string as_string () const = 0;
@@ -121,6 +97,8 @@ class MacroMatch
12197

12298
virtual void accept_vis (ASTVisitor &vis) = 0;
12399

100+
virtual MacroMatchType get_macro_match_type () const = 0;
101+
124102
protected:
125103
// pure virtual clone implementation
126104
virtual MacroMatch *clone_macro_match_impl () const = 0;
@@ -234,6 +212,11 @@ class Token : public TokenTree, public MacroMatch
234212
// Get a new token pointer copy.
235213
const_TokenPtr get_tok_ptr () const { return tok_ref; }
236214

215+
MacroMatchType get_macro_match_type () const override
216+
{
217+
return MacroMatchType::Tok;
218+
}
219+
237220
protected:
238221
// No virtual for now as not polymorphic but can be in future
239222
/*virtual*/ Token *clone_token_impl () const { return new Token (*this); }
@@ -788,6 +771,13 @@ class DelimTokenTree : public TokenTree, public AttrInput
788771
{
789772
return AttrInput::AttrInputType::TOKEN_TREE;
790773
}
774+
775+
std::vector<std::unique_ptr<TokenTree> > &get_token_trees ()
776+
{
777+
return token_trees;
778+
}
779+
780+
DelimType get_delim_type () const { return delim_type; }
791781
};
792782

793783
/* Forward decl - definition moved to rust-expr.h as it requires LiteralExpr to
@@ -1485,6 +1475,160 @@ struct MacroInvocData
14851475
}
14861476
};
14871477

1478+
class SingleASTNode
1479+
{
1480+
public:
1481+
enum NodeType
1482+
{
1483+
EXPRESSION,
1484+
ITEM,
1485+
STMT,
1486+
};
1487+
1488+
SingleASTNode (std::unique_ptr<Expr> expr)
1489+
: type (EXPRESSION), expr (std::move (expr)), item (nullptr), stmt (nullptr)
1490+
{}
1491+
1492+
SingleASTNode (std::unique_ptr<Item> item)
1493+
: type (ITEM), expr (nullptr), item (std::move (item)), stmt (nullptr)
1494+
{}
1495+
1496+
SingleASTNode (std::unique_ptr<Stmt> stmt)
1497+
: type (STMT), expr (nullptr), item (nullptr), stmt (std::move (stmt))
1498+
{}
1499+
1500+
SingleASTNode (SingleASTNode const &other)
1501+
{
1502+
type = other.type;
1503+
switch (type)
1504+
{
1505+
case EXPRESSION:
1506+
expr = other.expr->clone_expr ();
1507+
break;
1508+
1509+
case ITEM:
1510+
item = other.item->clone_item ();
1511+
break;
1512+
1513+
case STMT:
1514+
stmt = other.stmt->clone_stmt ();
1515+
break;
1516+
}
1517+
}
1518+
1519+
SingleASTNode operator= (SingleASTNode const &other)
1520+
{
1521+
type = other.type;
1522+
switch (type)
1523+
{
1524+
case EXPRESSION:
1525+
expr = other.expr->clone_expr ();
1526+
break;
1527+
1528+
case ITEM:
1529+
item = other.item->clone_item ();
1530+
break;
1531+
1532+
case STMT:
1533+
stmt = other.stmt->clone_stmt ();
1534+
break;
1535+
}
1536+
return *this;
1537+
}
1538+
1539+
SingleASTNode (SingleASTNode &&other) = default;
1540+
SingleASTNode &operator= (SingleASTNode &&other) = default;
1541+
1542+
std::unique_ptr<Expr> &get_expr ()
1543+
{
1544+
rust_assert (type == EXPRESSION);
1545+
return expr;
1546+
}
1547+
1548+
std::unique_ptr<Item> &get_item ()
1549+
{
1550+
rust_assert (type == ITEM);
1551+
return item;
1552+
}
1553+
1554+
std::unique_ptr<Stmt> &get_stmt ()
1555+
{
1556+
rust_assert (type == STMT);
1557+
return stmt;
1558+
}
1559+
1560+
void accept_vis (ASTVisitor &vis)
1561+
{
1562+
switch (type)
1563+
{
1564+
case EXPRESSION:
1565+
expr->accept_vis (vis);
1566+
break;
1567+
1568+
case ITEM:
1569+
item->accept_vis (vis);
1570+
break;
1571+
1572+
case STMT:
1573+
stmt->accept_vis (vis);
1574+
break;
1575+
}
1576+
}
1577+
1578+
private:
1579+
NodeType type;
1580+
1581+
// FIXME make this a union
1582+
std::unique_ptr<Expr> expr;
1583+
std::unique_ptr<Item> item;
1584+
std::unique_ptr<Stmt> stmt;
1585+
};
1586+
1587+
/* Basically, a "fragment" that can be incorporated into the AST, created as
1588+
* a result of macro expansion. Really annoying to work with due to the fact
1589+
* that macros can really expand to anything. As such, horrible representation
1590+
* at the moment. */
1591+
class ASTFragment
1592+
{
1593+
private:
1594+
/* basic idea: essentially, a vector of tagged unions of different AST node
1595+
* types. Now, this could actually be stored without a tagged union if the
1596+
* different AST node types had a unified parent, but that would create
1597+
* issues with the diamond problem or significant performance penalties. So
1598+
* a tagged union had to be used instead. A vector is used to represent the
1599+
* ability for a macro to expand to two statements, for instance. */
1600+
1601+
std::vector<SingleASTNode> nodes;
1602+
1603+
public:
1604+
ASTFragment (std::vector<SingleASTNode> nodes) : nodes (std::move (nodes)) {}
1605+
1606+
ASTFragment (ASTFragment const &other)
1607+
{
1608+
nodes.clear ();
1609+
nodes.reserve (other.nodes.size ());
1610+
for (auto &n : other.nodes)
1611+
{
1612+
nodes.push_back (n);
1613+
}
1614+
}
1615+
1616+
ASTFragment &operator= (ASTFragment const &other)
1617+
{
1618+
nodes.clear ();
1619+
nodes.reserve (other.nodes.size ());
1620+
for (auto &n : other.nodes)
1621+
{
1622+
nodes.push_back (n);
1623+
}
1624+
return *this;
1625+
}
1626+
1627+
static ASTFragment create_empty () { return ASTFragment ({}); }
1628+
1629+
std::vector<SingleASTNode> &get_nodes () { return nodes; }
1630+
};
1631+
14881632
/* A macro invocation item (or statement) AST node (i.e. semi-coloned macro
14891633
* invocation) */
14901634
class MacroInvocationSemi : public MacroItem,
@@ -1496,14 +1640,20 @@ class MacroInvocationSemi : public MacroItem,
14961640
std::vector<Attribute> outer_attrs;
14971641
MacroInvocData invoc_data;
14981642
Location locus;
1643+
NodeId node_id;
1644+
1645+
// this is the expanded macro
1646+
ASTFragment fragment;
14991647

15001648
public:
15011649
std::string as_string () const override;
15021650

15031651
MacroInvocationSemi (MacroInvocData invoc_data,
15041652
std::vector<Attribute> outer_attrs, Location locus)
15051653
: outer_attrs (std::move (outer_attrs)),
1506-
invoc_data (std::move (invoc_data)), locus (locus)
1654+
invoc_data (std::move (invoc_data)), locus (locus),
1655+
node_id (Analysis::Mappings::get ()->get_next_node_id ()),
1656+
fragment (ASTFragment::create_empty ())
15071657
{}
15081658

15091659
void accept_vis (ASTVisitor &vis) override;
@@ -1527,6 +1677,14 @@ class MacroInvocationSemi : public MacroItem,
15271677

15281678
Location get_locus () const override final { return locus; }
15291679

1680+
MacroInvocData &get_invoc_data () { return invoc_data; }
1681+
1682+
ASTFragment &get_fragment () { return fragment; }
1683+
1684+
void set_fragment (ASTFragment &&f) { fragment = std::move (f); }
1685+
1686+
NodeId get_macro_node_id () const { return node_id; }
1687+
15301688
protected:
15311689
MacroInvocationSemi *clone_macro_invocation_semi_impl () const
15321690
{

0 commit comments

Comments
 (0)