]> git.tdb.fi Git - libs/datafile.git/blob - source/loader.cpp
Allow overloading keywords with different signatures
[libs/datafile.git] / source / loader.cpp
1 /* $Id$
2
3 This file is part of libmspdatafile
4 Copyright © 2006-2008, 2010  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <msp/strings/formatter.h>
9 #include "loader.h"
10 #include "type.h"
11
12 using namespace std;
13
14 namespace {
15
16 bool signature_match(char s, char a)
17 {
18         if(s==a)
19                 return true;
20         if(s==Msp::DataFile::IntType::signature && a==Msp::DataFile::FloatType::signature)
21                 return true;
22         return false;
23 }
24
25 bool signature_match(const string &st_sig, const string &act_sig)
26 {
27         if(act_sig=="*")
28                 return true;
29         else if(act_sig.size()==2 && act_sig[1]=='*')
30         {
31                 for(string::const_iterator i=st_sig.begin(); i!=st_sig.end(); ++i)
32                         if(*i!=act_sig[0])
33                                 return false;
34
35                 return true;
36         }
37         else if(st_sig.size()==act_sig.size())
38         {
39                 for(unsigned i=0; i<st_sig.size(); ++i)
40                         if(!signature_match(st_sig[i], act_sig[i]))
41                                 return false;
42
43                 return true;
44         }
45         else
46                 return false;
47 }
48
49 }
50
51 namespace Msp {
52 namespace DataFile {
53
54 Loader::~Loader()
55 {
56         for(ActionMap::iterator i = actions.begin(); i!=actions.end(); ++i)
57                 delete i->second;
58 }
59
60 void Loader::load(Parser &p)
61 {
62         while(p)
63         {
64                 Statement st = p.parse();
65                 if(st.valid)
66                         load_statement(st);
67         }
68         finish();
69 }
70
71 void Loader::load(const Statement &st)
72 {
73         for(list<Statement>::const_iterator i = st.sub.begin(); i!=st.sub.end(); ++i)
74                 load_statement(*i);
75         finish();
76 }
77
78 void Loader::load_statement(const Statement &st)
79 {
80         cur_st = &st;
81
82         try
83         {
84                 LoaderAction *act = find_action(ActionKey(st.keyword, st.get_signature()));
85                 if(act)
86                         act->execute(*this, st);
87         }
88         catch(Exception &e)
89         {
90                 cur_st = 0;
91                 if(!e.where()[0])
92                         e.at(st.get_location());
93
94                 throw;
95         }
96
97         cur_st = 0;
98 }
99
100 void Loader::load_sub_with(Loader &ldr)
101 {
102         if(!cur_st)
103                 throw InvalidState("load_sub called without current statement");
104
105         ldr.load(*cur_st);
106 }
107
108 void Loader::add(const string &kwd, LoaderAction *act)
109 {
110         ActionKey key(kwd, act->get_signature());
111         ActionMap::iterator i = actions.find(key);
112         if(i!=actions.end())
113         {
114                 delete i->second;
115                 i->second = act;
116         }
117         else
118                 actions[key] = act;
119 }
120
121 LoaderAction *Loader::find_action(const ActionKey &key) const
122 {
123         ActionMap::const_iterator begin = actions.lower_bound(ActionKey(key.keyword, string()));
124         ActionMap::const_iterator end = actions.upper_bound(ActionKey(key.keyword, "~"));
125
126         if(begin==end)
127                 throw KeyError("Unknown keyword", key.keyword);
128
129         for(ActionMap::const_iterator i=begin; i!=end; ++i)
130                 if(signature_match(key.signature, i->first.signature))
131                         return i->second;
132
133         throw KeyError(format("Keyword '%s' does not accept signature '%s'", key.keyword, key.signature));
134 }
135
136
137 Loader::ActionKey::ActionKey(const string &k, const string &s):
138         keyword(k),
139         signature(s)
140 { }
141
142 bool Loader::ActionKey::operator<(const ActionKey &other) const
143 {
144         if(keyword!=other.keyword)
145                 return keyword<other.keyword;
146         return signature<other.signature;
147 }
148
149 } // namespace DataFile
150 } // namespace Msp