]> git.tdb.fi Git - libs/datafile.git/blob - source/loader.cpp
Cosmetic changes
[libs/datafile.git] / source / loader.cpp
1 #include <msp/core/raii.h>
2 #include <msp/strings/format.h>
3 #include "except.h"
4 #include "loader.h"
5 #include "type.h"
6
7 using namespace std;
8
9 namespace {
10
11 int signature_match(char s, char a)
12 {
13         if(s==a)
14                 return 3;
15         if(s==Msp::DataFile::IntType::signature && a==Msp::DataFile::FloatType::signature)
16                 return 1;
17         return 0;
18 }
19
20 int signature_match(const string &st_sig, const string &act_sig)
21 {
22         if(act_sig=="*")
23                 return 1;
24         else if(act_sig.size()==2 && act_sig[1]=='*')
25         {
26                 int match = 3;
27                 for(string::const_iterator i=st_sig.begin(); (i!=st_sig.end() && match); ++i)
28                         match = min(match, signature_match(*i, act_sig[0]));
29
30                 return match;
31         }
32         else if(st_sig.size()==act_sig.size())
33         {
34                 int match = 3;
35                 for(unsigned i=0; (i<st_sig.size() && match); ++i)
36                         match = min(match, signature_match(st_sig[i], act_sig[i]));
37
38                 return match ? match+1 : 0;
39         }
40         else
41                 return 0;
42 }
43
44 }
45
46
47 namespace Msp {
48 namespace DataFile {
49
50 Loader::Loader():
51         actions(0),
52         cur_st(0),
53         direct(false),
54         check_sub_loads(false)
55 { }
56
57 Loader::~Loader()
58 {
59         for(ActionMap::iterator i=local_actions.begin(); i!=local_actions.end(); ++i)
60                 delete i->second;
61 }
62
63 void Loader::load(Parser &p)
64 {
65         if(!actions)
66                 throw logic_error("no actions");
67
68         while(p)
69         {
70                 if(p.peek(0))
71                         load_direct(p, 0);
72                 else if(p)  // Peek may have processed an __end, so recheck goodness
73                 {
74                         // Parse in raw mode so we can peek immediately after a mode change
75                         Statement st = p.parse(true);
76                         if(st.valid && !st.control)
77                                 load_statement(st);
78                 }
79         }
80         finish();
81 }
82
83 void Loader::load(const Statement &st)
84 {
85         if(!actions)
86                 throw logic_error("no actions");
87
88         for(list<Statement>::const_iterator i=st.sub.begin(); i!=st.sub.end(); ++i)
89                 load_statement(*i);
90         finish();
91 }
92
93 void Loader::load_direct(Parser &p, unsigned l)
94 {
95         SetForScope<Parser *> set_parser(cur_parser, &p);
96         SetForScope<unsigned> set_level(cur_level, l);
97
98         while(p)
99         {
100                 const StatementKey *key = p.peek(l);
101                 if(!key)
102                         break;
103
104                 LoaderAction *act = find_action(*key);
105                 if(act)
106                 {
107                         SetFlag set_direct(direct);
108                         if(!p.parse_and_load(l, *this, *act))
109                                 throw logic_error("direct load failed");
110                 }
111                 else
112                         load_statement(p.parse());
113         }
114 }
115
116 void Loader::load_statement(const Statement &st)
117 {
118         SetForScope<const Statement *> set_cst(cur_st, &st);
119
120         try
121         {
122                 StatementKey key(st.keyword, st.get_signature());
123
124                 if(!aux_loaders.empty() && !has_action(key))
125                 {
126                         for(vector<Loader *>::const_iterator i=aux_loaders.begin(); i!=aux_loaders.end(); ++i)
127                                 if((*i)->has_action(key))
128                                         return (*i)->load_statement(st);
129                 }
130
131                 LoaderAction *act = find_action(key);
132                 if(act)
133                 {
134                         sub_loaded = false;
135                         act->execute(*this, st);
136                         if(check_sub_loads && !st.sub.empty() && !sub_loaded)
137                                 throw logic_error("substatements ignored");
138                 }
139         }
140         catch(const data_error &)
141         {
142                 throw;
143         }
144         catch(const exception &e)
145         {
146                 throw data_error(st.source, st.line, e);
147         }
148 }
149
150 void Loader::load_sub_with(Loader &ldr)
151 {
152         if(direct)
153         {
154                 ldr.load_direct(*cur_parser, cur_level+1);
155                 ldr.finish();
156         }
157         else if(cur_st)
158         {
159                 ldr.load(*cur_st);
160                 sub_loaded = true;
161         }
162         else
163                 throw logic_error("no current statement");
164 }
165
166 void Loader::set_actions(ActionMap &a)
167 {
168         if(actions)
169                 throw logic_error("actions already set");
170
171         actions = &a;
172         if(a.empty())
173                 init_actions();
174 }
175
176 void Loader::add(const string &kwd, LoaderAction *act)
177 {
178         if(!actions)
179                 actions = &local_actions;
180
181         StatementKey key(kwd, (act ? act->get_signature() : "*"));
182         ActionMap::iterator i = actions->find(key);
183         if(i!=actions->end())
184         {
185                 delete i->second;
186                 i->second = act;
187         }
188         else
189                 (*actions)[key] = act;
190 }
191
192 void Loader::add_auxiliary_loader(Loader &ldr)
193 {
194         aux_loaders.push_back(&ldr);
195 }
196
197 bool Loader::has_action(const StatementKey &key) const
198 {
199         if(!actions)
200                 return false;
201
202         ActionMap::const_iterator i = actions->lower_bound(StatementKey(key.keyword, string()));
203         for(; (i!=actions->end() && i->first.keyword==key.keyword); ++i)
204                 if(signature_match(key.signature, i->first.signature))
205                         return true;
206         return false;
207 }
208
209 LoaderAction *Loader::find_action(const StatementKey &key) const
210 {
211         if(!actions)
212                 return 0;
213
214         ActionMap::const_iterator begin = actions->lower_bound(StatementKey(key.keyword, string()));
215         ActionMap::const_iterator end = actions->upper_bound(StatementKey(key.keyword, "~"));
216
217         if(begin==end)
218                 throw unknown_keyword(key.keyword);
219
220         LoaderAction *act = 0;
221         int match = 0;
222         for(ActionMap::const_iterator i=begin; i!=end; ++i)
223         {
224                 int m = signature_match(key.signature, i->first.signature);
225                 if(m>match)
226                 {
227                         act = i->second;
228                         match = m;
229                 }
230         }
231
232         if(!act)
233                 throw invalid_signature(key.keyword, key.signature);
234
235         return act;
236 }
237
238 const string &Loader::get_source() const
239 {
240         if(!cur_st)
241                 throw logic_error("no current statement");
242         return cur_st->source;
243 }
244
245 const string &Loader::get_keyword() const
246 {
247         if(!cur_st)
248                 throw logic_error("no current statement");
249         return cur_st->keyword;
250 }
251
252 } // namespace DataFile
253 } // namespace Msp