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
|
#include <synext.hpp>
#include <parse/tokentree.hpp>
#include <parse/lex.hpp>
#include <parse/common.hpp>
#include "cfg.hpp"
#include <map>
#include <set>
::std::map< ::std::string, ::std::string> g_cfg_values;
::std::set< ::std::string > g_cfg_flags;
void Cfg_SetFlag(::std::string name) {
g_cfg_flags.insert( mv$(name) );
}
void Cfg_SetValue(::std::string name, ::std::string val) {
g_cfg_values.insert( ::std::make_pair(mv$(name), mv$(val)) );
}
bool check_cfg(Span sp, const ::AST::MetaItem& mi) {
if( mi.has_sub_items() ) {
// Must be `any`/`not`/`all`
if( mi.name() == "any" || mi.name() == "cfg" ) {
for(const auto& si : mi.items()) {
if( check_cfg(sp, si) )
return true;
}
return false;
}
else if( mi.name() == "not" ) {
if( mi.items().size() != 1 )
ERROR(sp, E0000, "cfg(not()) with != 1 argument");
return !check_cfg(sp, mi.items()[0]);
}
else if( mi.name() == "all" ) {
for(const auto& si : mi.items()) {
if( ! check_cfg(sp, si) )
return false;
}
return true;
}
else {
// oops
ERROR(sp, E0000, "Unknown cfg() function - " << mi.name());
}
}
else if( mi.has_string() ) {
// Equaliy
auto it = g_cfg_values.find(mi.name());
if( it != g_cfg_values.end() )
{
DEBUG(""<<mi.name()<<": '"<<it->second<<"' == '"<<mi.string()<<"'");
return it->second == mi.string();
}
else
{
WARNING(sp, W0000, "Unknown cfg() param '" << mi.name() << "'");
return false;
}
}
else {
// Flag
auto it = g_cfg_flags.find(mi.name());
return (it != g_cfg_flags.end());
}
BUG(sp, "Fell off the end of check_cfg");
}
class CCfgExpander:
public ExpandProcMacro
{
bool expand_early() const override { return true; }
::std::unique_ptr<TokenStream> expand(Span sp, const ::AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override
{
if( ident != "" ) {
ERROR(sp, E0000, "cfg! doesn't take an identifier");
}
auto lex = TTStreamO(tt);
auto attrs = Parse_MetaItem(lex);
DEBUG("cfg!() - " << attrs);
if( check_cfg(sp, attrs) ) {
return box$( TTStreamO(TokenTree(TOK_RWORD_TRUE )) );
}
else {
return box$( TTStreamO(TokenTree(TOK_RWORD_FALSE)) );
}
}
};
class CCfgHandler:
public ExpandDecorator
{
AttrStage stage() const override { return AttrStage::EarlyPre; }
void handle(const AST::MetaItem& mi, ::AST::Crate& crate, AST::MacroInvocation& mac) const override {
DEBUG("#[cfg] mac! - " << mi);
if( check_cfg(mac.span(), mi) ) {
// Leave as is
}
else {
mac.clear();
}
}
void handle(const AST::MetaItem& mi, ::AST::Crate& crate, const AST::Path& path, AST::Module& mod, AST::Item&i) const override {
DEBUG("#[cfg] item - " << mi);
if( check_cfg(Span(), mi) ) {
// Leave
}
else {
i = AST::Item::make_None({});
}
}
void handle(const AST::MetaItem& mi, ::AST::Crate& crate, ::std::unique_ptr<AST::ExprNode>& expr) const override {
DEBUG("#[cfg] expr - " << mi);
if( check_cfg(Span(expr->get_pos()), mi) ) {
// Leave
}
else {
expr.reset();
}
}
};
STATIC_MACRO("cfg", CCfgExpander);
STATIC_DECORATOR("cfg", CCfgHandler);
|