]> git.tdb.fi Git - libs/datafile.git/blob - source/loader.cpp
Replace local RAII set utility with one from mspcore
[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         check_sub_loads(false)
75 { }
76
77 Loader::~Loader()
78 {
79         for(ActionMap::iterator i=actions.begin(); i!=actions.end(); ++i)
80                 delete i->second;
81 }
82
83 void Loader::load(Parser &p)
84 {
85         while(p)
86         {
87                 Statement st = p.parse();
88                 if(st.valid)
89                         load_statement(st);
90         }
91         finish();
92 }
93
94 void Loader::load(const Statement &st)
95 {
96         for(list<Statement>::const_iterator i=st.sub.begin(); i!=st.sub.end(); ++i)
97                 load_statement(*i);
98         finish();
99 }
100
101 void Loader::load_statement(const Statement &st)
102 {
103         SetForScope<const Statement *> set_cst(cur_st, &st);
104
105         try
106         {
107                 StatementKey key(st.keyword, st.get_signature());
108
109                 if(!aux_loaders.empty() && !has_action(key))
110                 {
111                         for(list<Loader *>::const_iterator i=aux_loaders.begin(); i!=aux_loaders.end(); ++i)
112                                 if((*i)->has_action(key))
113                                         return (*i)->load_statement(st);
114                 }
115
116                 LoaderAction *act = find_action(key);
117                 if(act)
118                 {
119                         sub_loaded = false;
120                         act->execute(*this, st);
121                         if(check_sub_loads && !st.sub.empty() && !sub_loaded)
122                                 throw logic_error("substatements ignored");
123                 }
124         }
125         catch(const data_error &)
126         {
127                 throw;
128         }
129         catch(const exception &e)
130         {
131                 throw data_error(st.source, st.line, e);
132         }
133 }
134
135 void Loader::load_sub_with(Loader &ldr)
136 {
137         if(!cur_st)
138                 throw logic_error("no current statement");
139
140         ldr.load(*cur_st);
141         sub_loaded = true;
142 }
143
144 void Loader::add(const string &kwd, LoaderAction *act)
145 {
146         StatementKey key(kwd, (act ? act->get_signature() : "*"));
147         ActionMap::iterator i = actions.find(key);
148         if(i!=actions.end())
149         {
150                 delete i->second;
151                 i->second = act;
152         }
153         else
154                 actions[key] = act;
155 }
156
157 void Loader::add_auxiliary_loader(Loader &ldr)
158 {
159         aux_loaders.push_back(&ldr);
160 }
161
162 bool Loader::has_action(const StatementKey &key) const
163 {
164         ActionMap::const_iterator i = actions.lower_bound(StatementKey(key.keyword, string()));
165         for(; (i!=actions.end() && i->first.keyword==key.keyword); ++i)
166                 if(signature_match(key.signature, i->first.signature))
167                         return true;
168         return false;
169 }
170
171 LoaderAction *Loader::find_action(const StatementKey &key) const
172 {
173         ActionMap::const_iterator begin = actions.lower_bound(StatementKey(key.keyword, string()));
174         ActionMap::const_iterator end = actions.upper_bound(StatementKey(key.keyword, "~"));
175
176         if(begin==end)
177                 throw unknown_keyword(key.keyword);
178
179         for(ActionMap::const_iterator i=begin; i!=end; ++i)
180                 if(signature_match(key.signature, i->first.signature))
181                         return i->second;
182
183         throw invalid_signature(key.keyword, key.signature);
184 }
185
186 const string &Loader::get_source() const
187 {
188         if(!cur_st)
189                 throw logic_error("no current statement");
190         return cur_st->source;
191 }
192
193 } // namespace DataFile
194 } // namespace Msp