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
|
/*
*/
#include "common.hpp"
#include "macros.hpp"
#include "parse/parseerror.hpp"
#include "parse/tokentree.hpp"
#include "parse/common.hpp"
typedef ::std::map< ::std::string, MacroRules> t_macro_regs;
t_macro_regs g_macro_registrations;
void Macro_InitDefaults()
{
// try!() macro
{
MacroRule rule;
rule.m_pattern.push_back( MacroPatEnt("val", MacroPatEnt::PAT_EXPR) );
// match $rule {
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_RWORD_MATCH)) );
rule.m_contents.push_back( MacroRuleEnt("val") );
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_BRACE_OPEN)) );
// Ok(v) => v,
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_IDENT, "Ok")) );
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_PAREN_OPEN)) );
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_IDENT, "v")) );
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_PAREN_CLOSE)) );
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_FATARROW)) );
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_IDENT, "v")) );
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_COMMA)) );
// Err(e) => return Err(r),
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_IDENT, "Err")) );
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_PAREN_OPEN)) );
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_IDENT, "e")) );
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_PAREN_CLOSE)) );
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_FATARROW)) );
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_RWORD_RETURN)) );
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_IDENT, "Err")) );
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_PAREN_OPEN)) );
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_IDENT, "e")) );
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_PAREN_CLOSE)) );
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_COMMA)) );
// }
rule.m_contents.push_back( MacroRuleEnt(Token(TOK_BRACE_CLOSE)) );
MacroRules rules;
rules.push_back(rule);
g_macro_registrations.insert( make_pair(::std::string("try"), rules));
}
}
MacroExpander Macro_Invoke(const char* name, TokenTree input)
{
// XXX: EVIL HACK! - This should be removed when std loading is implemented
if( g_macro_registrations.size() == 0 ) {
Macro_InitDefaults();
}
// 1. Locate macro with that name
t_macro_regs::iterator macro_reg = g_macro_registrations.find(name);
if( macro_reg != g_macro_registrations.end() )
{
const MacroRules& rules = macro_reg->second;
// 2. Check input token tree against possible variants
// 3. Bind names
// 4. Return expander
FOREACH(MacroRules, rule_it, rules)
{
Token tok;
// Create token stream for input tree
TTStream lex(input);
if(GET_TOK(tok, lex) == TOK_EOF) {
throw ParseError::Unexpected(tok);
}
::std::map<const char*,TokenTree,cmp_str> bound_tts;
// Parse according to rules
bool fail = false;
FOREACH(::std::vector<MacroPatEnt>, pat_it, rule_it->m_pattern)
{
TokenTree val;
const MacroPatEnt& pat = *pat_it;
try
{
switch(pat.type)
{
case MacroPatEnt::PAT_TOKEN:
GET_CHECK_TOK(tok, lex, pat.tok.type());
break;
case MacroPatEnt::PAT_EXPR:
val = Parse_TT_Expr(lex);
if(0)
case MacroPatEnt::PAT_STMT:
val = Parse_TT_Stmt(lex);
bound_tts.insert( std::make_pair(pat.name.c_str(), val) );
break;
default:
throw ParseError::Todo("macro pattern matching");
}
}
catch(const ParseError::Base& e)
{
fail = true;
break;
}
}
// TODO: Actually check if the final token is the closer to the first
if( !fail && GET_TOK(tok, lex) == TOK_EOF) {
throw ParseError::Unexpected(tok);
}
if( !fail && lex.getToken().type() == TOK_EOF )
{
return MacroExpander(rule_it->m_contents, bound_tts);
}
}
throw ParseError::Todo("Error when macro fails to match");
}
throw ParseError::Generic( ::std::string("Macro '") + name + "' was not found" );
}
Token MacroExpander::realGetToken()
{
if( m_ttstream.get() )
{
Token rv = m_ttstream->getToken();
if( rv.type() != TOK_EOF )
return rv;
m_ttstream.reset();
}
if( m_ofs < m_contents.size() )
{
const MacroRuleEnt& ent = m_contents[m_ofs];
m_ofs ++;
if( ent.name.size() != 0 ) {
// Binding!
m_ttstream.reset( new TTStream(m_mappings.at(ent.name.c_str())) );
return m_ttstream->getToken();
}
else {
return ent.tok;
}
throw ParseError::Todo("MacroExpander - realGetToken");
}
return Token(TOK_EOF);
}
|