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