]> git.tdb.fi Git - libs/datafile.git/blob - source/loader.cpp
c495c4cab71ed67b11d678e0cacaf02eec0bb312
[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                 LoaderAction *act = find_action(ActionKey(st.keyword, st.get_signature()));
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         ActionKey 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 LoaderAction *Loader::find_action(const ActionKey &key) const
158 {
159         ActionMap::const_iterator begin = actions.lower_bound(ActionKey(key.keyword, string()));
160         ActionMap::const_iterator end = actions.upper_bound(ActionKey(key.keyword, "~"));
161
162         if(begin==end)
163                 throw unknown_keyword(key.keyword);
164
165         for(ActionMap::const_iterator i=begin; i!=end; ++i)
166                 if(signature_match(key.signature, i->first.signature))
167                         return i->second;
168
169         throw invalid_signature(key.keyword, key.signature);
170 }
171
172 const string &Loader::get_source() const
173 {
174         if(!cur_st)
175                 throw logic_error("no current statement");
176         return cur_st->source;
177 }
178
179
180 Loader::ActionKey::ActionKey(const string &k, const string &s):
181         keyword(k),
182         signature(s)
183 { }
184
185 bool Loader::ActionKey::operator<(const ActionKey &other) const
186 {
187         if(keyword!=other.keyword)
188                 return keyword<other.keyword;
189         return signature<other.signature;
190 }
191
192 } // namespace DataFile
193 } // namespace Msp