summaryrefslogtreecommitdiff
path: root/macros.cpp
blob: e6750f49093bec810bff38177df2c5e046b3eeab (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
/*
 */
#include "macros.hpp"
#include "parse/parseerror.hpp"
#include "parse/tokentree.hpp"
#include "parse/common.hpp"

#define FOREACH(basetype, it, src)  for(basetype::const_iterator it = src.begin(); it != src.end(); ++ it)

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)
        {
            // Create token stream for input tree
            TTStream    lex(input);
            ::std::map<const char*,TokenTree>   bound_tts;
            // Parse according to rules
            bool fail = false;
            FOREACH(::std::vector<MacroPatEnt>, pat_it, rule_it->m_pattern)
            {
                Token   tok;
                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;
                }
            }
            if( !fail && lex.getToken().type() == TOK_EOF )
            {
                throw ParseError::Todo("Macro expansions");
            }
        }
        throw ParseError::Todo("Error when macro fails to match");
    }

    throw ParseError::Generic( ::std::string("Macro '") + name + "' was not found" );
}

Token MacroExpander::realGetToken()
{
    throw ParseError::Todo("MacroExpander");
}