]> git.tdb.fi Git - libs/datafile.git/blob - source/loader.cpp
Make ignored keywords work properly
[libs/datafile.git] / source / loader.cpp
1 /* $Id$
2
3 This file is part of libmspdatafile
4 Copyright © 2006-2008, 2010  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #include <msp/strings/formatter.h>
9 #include "loader.h"
10 #include "type.h"
11
12 using namespace std;
13
14 namespace {
15
16 bool signature_match(char s, char a)
17 {
18         if(s==a)
19                 return true;
20         if(s==Msp::DataFile::IntType::signature && a==Msp::DataFile::FloatType::signature)
21                 return true;
22         return false;
23 }
24
25 bool signature_match(const string &st_sig, const string &act_sig)
26 {
27         if(act_sig=="*")
28                 return true;
29         else if(act_sig.size()==2 && act_sig[1]=='*')
30         {
31                 for(string::const_iterator i=st_sig.begin(); i!=st_sig.end(); ++i)
32                         if(*i!=act_sig[0])
33                                 return false;
34
35                 return true;
36         }
37         else if(st_sig.size()==act_sig.size())
38         {
39                 for(unsigned i=0; i<st_sig.size(); ++i)
40                         if(!signature_match(st_sig[i], act_sig[i]))
41                                 return false;
42
43                 return true;
44         }
45         else
46                 return false;
47 }
48
49 }
50
51 namespace Msp {
52 namespace DataFile {
53
54 Loader::Loader():
55         cur_st(0),
56         allow_pointer_reload(true),
57         check_sub_loads(false)
58 { }
59
60 Loader::~Loader()
61 {
62         for(ActionMap::iterator i = actions.begin(); i!=actions.end(); ++i)
63                 delete i->second;
64 }
65
66 void Loader::load(Parser &p)
67 {
68         while(p)
69         {
70                 Statement st = p.parse();
71                 if(st.valid)
72                         load_statement(st);
73         }
74         finish();
75 }
76
77 void Loader::load(const Statement &st)
78 {
79         for(list<Statement>::const_iterator i = st.sub.begin(); i!=st.sub.end(); ++i)
80                 load_statement(*i);
81         finish();
82 }
83
84 void Loader::load_statement(const Statement &st)
85 {
86         cur_st = &st;
87
88         try
89         {
90                 LoaderAction *act = find_action(ActionKey(st.keyword, st.get_signature()));
91                 if(act)
92                 {
93                         sub_loaded = false;
94                         act->execute(*this, st);
95                         if(check_sub_loads && !st.sub.empty() && !sub_loaded)
96                                 throw Exception("Substatements were not loaded");
97                 }
98         }
99         catch(Exception &e)
100         {
101                 cur_st = 0;
102                 if(!e.where()[0])
103                         e.at(st.get_location());
104
105                 throw;
106         }
107
108         cur_st = 0;
109 }
110
111 void Loader::load_sub_with(Loader &ldr)
112 {
113         if(!cur_st)
114                 throw InvalidState("load_sub called without current statement");
115
116         ldr.load(*cur_st);
117         sub_loaded = true;
118 }
119
120 void Loader::add(const string &kwd, LoaderAction *act)
121 {
122         ActionKey key(kwd, (act ? act->get_signature() : "*"));
123         ActionMap::iterator i = actions.find(key);
124         if(i!=actions.end())
125         {
126                 delete i->second;
127                 i->second = act;
128         }
129         else
130                 actions[key] = act;
131 }
132
133 LoaderAction *Loader::find_action(const ActionKey &key) const
134 {
135         ActionMap::const_iterator begin = actions.lower_bound(ActionKey(key.keyword, string()));
136         ActionMap::const_iterator end = actions.upper_bound(ActionKey(key.keyword, "~"));
137
138         if(begin==end)
139                 throw KeyError("Unknown keyword", key.keyword);
140
141         for(ActionMap::const_iterator i=begin; i!=end; ++i)
142                 if(signature_match(key.signature, i->first.signature))
143                         return i->second;
144
145         throw KeyError(format("Keyword '%s' does not accept signature '%s'", key.keyword, key.signature));
146 }
147
148
149 Loader::ActionKey::ActionKey(const string &k, const string &s):
150         keyword(k),
151         signature(s)
152 { }
153
154 bool Loader::ActionKey::operator<(const ActionKey &other) const
155 {
156         if(keyword!=other.keyword)
157                 return keyword<other.keyword;
158         return signature<other.signature;
159 }
160
161 } // namespace DataFile
162 } // namespace Msp