summaryrefslogtreecommitdiff
path: root/src/macro_rules/macro_rules.hpp
blob: 05b1e06557deafa932e15475ae0e239bfd35f010 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
 * MRustC - Rust Compiler
 * - By John Hodge (Mutabah/thePowersGang)
 *
 * macro_rules/macro_rules.hpp
 * - Macros by example - `macro_rules!`
 */
#ifndef MACROS_HPP_INCLUDED
#define MACROS_HPP_INCLUDED

#include "parse/lex.hpp"
#include "parse/tokentree.hpp"
#include <common.hpp>
#include <map>
#include <memory>
#include <cstring>
#include "macro_rules_ptr.hpp"
#include <set>

class MacroExpander;
class SimplePatEnt;

TAGGED_UNION(MacroExpansionEnt, Token,
    // TODO: have a "raw" stream instead of just tokens
    (Token, Token),
    // TODO: Have a flag on `NamedValue` that indicates that it is the only/last usage of this particular value (at this level)
    // NOTE: This is a 2:30 bitfield - with the high range indicating $crate
    (NamedValue, unsigned int),
    (Loop, struct {
        /// Contained entries
        ::std::vector< MacroExpansionEnt>   entries;
        /// Token used to join iterations
        Token   joiner;
        /// List of variables within this loop that control its iteration count
        /// Boolean is true if the variable will be unconditionally expanded
        ::std::map< unsigned int, bool>    variables;
        })
    );
extern ::std::ostream& operator<<(::std::ostream& os, const MacroExpansionEnt& x);

/// Matching pattern entry
struct MacroPatEnt
{
    RcString    name;
    unsigned int    name_index = 0;
    // TODO: Include a point span for the token?
    Token   tok;

    ::std::vector<MacroPatEnt>  subpats;

    enum Type {
        PAT_TOKEN,  // A token
        PAT_LOOP,   // $() Enables use of subpats

        PAT_TT, // :tt
        PAT_PAT,    // :pat
        PAT_IDENT,
        PAT_PATH,
        PAT_TYPE,
        PAT_EXPR,
        PAT_STMT,
        PAT_BLOCK,
        PAT_META,
        PAT_ITEM,   // :item
        PAT_VIS,
        PAT_LIFETIME,
    } type;

    MacroPatEnt():
        tok(TOK_NULL),
        type(PAT_TOKEN)
    {
    }
    MacroPatEnt(Token tok):
        tok( mv$(tok) ),
        type(PAT_TOKEN)
    {
    }

    MacroPatEnt(RcString name, unsigned int name_index, Type type):
        name( mv$(name) ),
        name_index( name_index ),
        tok(),
        type(type)
    {
    }

    MacroPatEnt(Token sep, bool need_once, ::std::vector<MacroPatEnt> ents):
        name( need_once ? "+" : "*" ),
        tok( mv$(sep) ),
        subpats( move(ents) ),
        type(PAT_LOOP)
    {
    }

    friend ::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt& x);
    friend ::std::ostream& operator<<(::std::ostream& os, const MacroPatEnt::Type& x);
};

struct SimplePatIfCheck
{
    MacroPatEnt::Type   ty; // If PAT_TOKEN, token is checked
    Token   tok;
};

/// Simple pattern entry for macro_rules! arm patterns
TAGGED_UNION( SimplePatEnt, End,
    // End of the pattern stream (expects EOF, and terminates the match process)
    (End, struct{}),
    (LoopStart, struct{}),
    (LoopNext, struct{}),
    (LoopEnd, struct{}),
    (Jump, struct {
        size_t jump_target;
        }),
    // Expect a specific token, erroring/failing the arm if nt met
    (ExpectTok, Token),
    // Expect a pattern match
    (ExpectPat, struct {
        MacroPatEnt::Type   type;
        unsigned int    idx;
        }),
    // Compare the head of the input stream and poke the pattern stream
    (If, struct {
        bool is_equal;
        size_t  jump_target;
        ::std::vector<SimplePatIfCheck> ents;
        })
    );

extern::std::ostream& operator<<(::std::ostream& os, const SimplePatEnt& x);

/// An expansion arm within a macro_rules! blcok
struct MacroRulesArm
{
    /// Names for the parameters
    ::std::vector<RcString>   m_param_names;

    /// Patterns
    ::std::vector<SimplePatEnt> m_pattern;

    /// Rule contents
    ::std::vector<MacroExpansionEnt> m_contents;

    ~MacroRulesArm();
    MacroRulesArm()
    {}
    MacroRulesArm(::std::vector<SimplePatEnt> pattern, ::std::vector<MacroExpansionEnt> contents):
        m_pattern( mv$(pattern) ),
        m_contents( mv$(contents) )
    {}
    MacroRulesArm(const MacroRulesArm&) = delete;
    MacroRulesArm& operator=(const MacroRulesArm&) = delete;
    MacroRulesArm(MacroRulesArm&&) = default;
    MacroRulesArm& operator=(MacroRulesArm&&) = default;
};

/// A sigle 'macro_rules!' block
class MacroRules
{
public:
    /// Marks if this macro should be exported from the defining crate
    bool m_exported = false;

    /// Crate that defined this macro
    /// - Populated on deserialise if not already set
    RcString   m_source_crate;

    Ident::Hygiene  m_hygiene;

    /// Expansion rules
    ::std::vector<MacroRulesArm>  m_rules;

    MacroRules()
    {
    }
    virtual ~MacroRules();
    MacroRules(MacroRules&&) = default;
};

extern ::std::unique_ptr<TokenStream>   Macro_InvokeRules(const char *name, const MacroRules& rules, const Span& sp, TokenTree input, AST::Module& mod);
extern MacroRulesPtr    Parse_MacroRules(TokenStream& lex);

extern ::std::vector<MacroPatEnt> Parse_MacroRules_Pat(TokenStream& lex, enum eTokenType open, enum eTokenType close,  ::std::vector<RcString>& names);
extern ::std::vector<MacroExpansionEnt> Parse_MacroRules_Cont(TokenStream& lex, enum eTokenType open, enum eTokenType close, const ::std::vector<RcString>& var_names, ::std::map<unsigned int,bool>* var_set_ptr=nullptr);
extern MacroRulesArm Parse_MacroRules_MakeArm(Span pat_sp, ::std::vector<MacroPatEnt> pattern, ::std::vector<MacroExpansionEnt> contents);

#endif // MACROS_HPP_INCLUDED