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
|
#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$(name)) );
}
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() )
{
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 {
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 {
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 {
if( check_cfg(Span(expr->get_pos()), mi) ) {
// Leave
}
else {
expr.reset();
}
}
};
STATIC_MACRO("cfg", CCfgExpander);
STATIC_DECORATOR("cfg", CCfgHandler);
|