]> git.tdb.fi Git - libs/datafile.git/blob - source/loader.cpp
Consider full statement signature when dealing with auxiliary loaders
[libs/datafile.git] / source / loader.cpp
1 #include <msp/strings/format.h>
2 #include "dataerror.h"
3 #include "loader.h"
4 #include "type.h"
5
6 using namespace std;
7
8 namespace {
9
10 template<typename T>
11 struct Set
12 {
13         T &ref;
14         T orig;
15
16         Set(T &r, const T &v): ref(r), orig(r) { r = v; }
17         ~Set() { ref = orig; }
18 };
19
20 bool signature_match(char s, char a)
21 {
22         if(s==a)
23                 return true;
24         if(s==Msp::DataFile::IntType::signature && a==Msp::DataFile::FloatType::signature)
25                 return true;
26         return false;
27 }
28
29 bool signature_match(const string &st_sig, const string &act_sig)
30 {
31         if(act_sig=="*")
32                 return true;
33         else if(act_sig.size()==2 && act_sig[1]=='*')
34         {
35                 for(string::const_iterator i=st_sig.begin(); i!=st_sig.end(); ++i)
36                         if(*i!=act_sig[0])
37                                 return false;
38
39                 return true;
40         }
41         else if(st_sig.size()==act_sig.size())
42         {
43                 for(unsigned i=0; i<st_sig.size(); ++i)
44                         if(!signature_match(st_sig[i], act_sig[i]))
45                                 return false;
46
47                 return true;
48         }
49         else
50                 return false;
51 }
52
53 }
54
55
56 namespace Msp {
57 namespace DataFile {
58
59 class unknown_keyword: public runtime_error
60 {
61 public:
62         unknown_keyword(const std::string &k):
63                 runtime_error(k)
64         { }
65
66         virtual ~unknown_keyword() throw() { }
67 };
68
69
70 class invalid_signature: public runtime_error
71 {
72 public:
73         invalid_signature(const std::string &k, const std::string &s):
74                 runtime_error(format("%s %s", k, s))
75         { }
76
77         virtual ~invalid_signature() throw() { }
78 };
79
80
81 Loader::Loader():
82         cur_st(0),
83         check_sub_loads(false)
84 { }
85
86 Loader::~Loader()
87 {
88         for(ActionMap::iterator i=actions.begin(); i!=actions.end(); ++i)
89                 delete i->second;
90 }
91
92 void Loader::load(Parser &p)
93 {
94         while(p)
95         {
96                 Statement st = p.parse();
97                 if(st.valid)
98                         load_statement(st);
99         }
100         finish();
101 }
102
103 void Loader::load(const Statement &st)
104 {
105         for(list<Statement>::const_iterator i=st.sub.begin(); i!=st.sub.end(); ++i)
106                 load_statement(*i);
107         finish();
108 }
109
110 void Loader::load_statement(const Statement &st)
111 {
112         Set<const Statement *> set_cst(cur_st, &st);
113
114         try
115         {
116                 ActionKey key(st.keyword, st.get_signature());
117
118                 if(!aux_loaders.empty() && !has_action(key))
119                 {
120                         for(list<Loader *>::const_iterator i=aux_loaders.begin(); i!=aux_loaders.end(); ++i)
121                                 if((*i)->has_action(key))
122                                         return (*i)->load_statement(st);
123                 }
124
125                 LoaderAction *act = find_action(key);
126                 if(act)
127                 {
128                         sub_loaded = false;
129                         act->execute(*this, st);
130                         if(check_sub_loads && !st.sub.empty() && !sub_loaded)
131                                 throw logic_error("substatements ignored");
132                 }
133         }
134         catch(const data_error &)
135         {
136                 throw;
137         }
138         catch(const exception &e)
139         {
140                 throw data_error(st.source, st.line, e);
141         }
142 }
143
144 void Loader::load_sub_with(Loader &ldr)
145 {
146         if(!cur_st)
147                 throw logic_error("no current statement");
148
149         ldr.load(*cur_st);
150         sub_loaded = true;
151 }
152
153 void Loader::add(const string &kwd, LoaderAction *act)
154 {
155         ActionKey key(kwd, (act ? act->get_signature() : "*"));
156         ActionMap::iterator i = actions.find(key);
157         if(i!=actions.end())
158         {
159                 delete i->second;
160                 i->second = act;
161         }
162         else
163                 actions[key] = act;
164 }
165
166 void Loader::add_auxiliary_loader(Loader &ldr)
167 {
168         aux_loaders.push_back(&ldr);
169 }
170
171 bool Loader::has_action(const ActionKey &key) const
172 {
173         ActionMap::const_iterator i = actions.lower_bound(ActionKey(key.keyword, string()));
174         for(; (i!=actions.end() && i->first.keyword==key.keyword); ++i)
175                 if(signature_match(key.signature, i->first.signature))
176                         return true;
177         return false;
178 }
179
180 LoaderAction *Loader::find_action(const ActionKey &key) const
181 {
182         ActionMap::const_iterator begin = actions.lower_bound(ActionKey(key.keyword, string()));
183         ActionMap::const_iterator end = actions.upper_bound(ActionKey(key.keyword, "~"));
184
185         if(begin==end)
186                 throw unknown_keyword(key.keyword);
187
188         for(ActionMap::const_iterator i=begin; i!=end; ++i)
189                 if(signature_match(key.signature, i->first.signature))
190                         return i->second;
191
192         throw invalid_signature(key.keyword, key.signature);
193 }
194
195 const string &Loader::get_source() const
196 {
197         if(!cur_st)
198                 throw logic_error("no current statement");
199         return cur_st->source;
200 }
201
202
203 Loader::ActionKey::ActionKey(const string &k, const string &s):
204         keyword(k),
205         signature(s)
206 { }
207
208 bool Loader::ActionKey::operator<(const ActionKey &other) const
209 {
210         if(keyword!=other.keyword)
211                 return keyword<other.keyword;
212         return signature<other.signature;
213 }
214
215 } // namespace DataFile
216 } // namespace Msp