]> git.tdb.fi Git - libs/datafile.git/commitdiff
Allow overloading keywords with different signatures
authorMikko Rasa <tdb@tdb.fi>
Thu, 4 Feb 2010 13:17:48 +0000 (13:17 +0000)
committerMikko Rasa <tdb@tdb.fi>
Thu, 4 Feb 2010 13:17:48 +0000 (13:17 +0000)
source/loader.cpp
source/loader.h
source/loaderaction.h

index 655514e5057c57a3c062317241abeeff5f9a08bb..6da8599ba550e373828ea96af9bd81942216180c 100644 (file)
@@ -1,14 +1,53 @@
 /* $Id$
 
 This file is part of libmspdatafile
-Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
+Copyright © 2006-2008, 2010  Mikko Rasa, Mikkosoft Productions
 Distributed under the LGPL
 */
 
+#include <msp/strings/formatter.h>
 #include "loader.h"
+#include "type.h"
 
 using namespace std;
 
+namespace {
+
+bool signature_match(char s, char a)
+{
+       if(s==a)
+               return true;
+       if(s==Msp::DataFile::IntType::signature && a==Msp::DataFile::FloatType::signature)
+               return true;
+       return false;
+}
+
+bool signature_match(const string &st_sig, const string &act_sig)
+{
+       if(act_sig=="*")
+               return true;
+       else if(act_sig.size()==2 && act_sig[1]=='*')
+       {
+               for(string::const_iterator i=st_sig.begin(); i!=st_sig.end(); ++i)
+                       if(*i!=act_sig[0])
+                               return false;
+
+               return true;
+       }
+       else if(st_sig.size()==act_sig.size())
+       {
+               for(unsigned i=0; i<st_sig.size(); ++i)
+                       if(!signature_match(st_sig[i], act_sig[i]))
+                               return false;
+
+               return true;
+       }
+       else
+               return false;
+}
+
+}
+
 namespace Msp {
 namespace DataFile {
 
@@ -39,22 +78,22 @@ void Loader::load(const Statement &st)
 void Loader::load_statement(const Statement &st)
 {
        cur_st = &st;
-       ActionMap::iterator j = actions.find(st.keyword);
-       if(j==actions.end())
-               throw_at(KeyError("Unknown keyword", st.keyword), st.get_location());
-       if(j->second)
+
+       try
+       {
+               LoaderAction *act = find_action(ActionKey(st.keyword, st.get_signature()));
+               if(act)
+                       act->execute(*this, st);
+       }
+       catch(Exception &e)
        {
-               try
-               {
-                       j->second->execute(*this, st);
-               }
-               catch(Exception &e)
-               {
-                       if(!e.where()[0])
-                               e.at(st.get_location());
-                       throw;
-               }
+               cur_st = 0;
+               if(!e.where()[0])
+                       e.at(st.get_location());
+
+               throw;
        }
+
        cur_st = 0;
 }
 
@@ -66,16 +105,45 @@ void Loader::load_sub_with(Loader &ldr)
        ldr.load(*cur_st);
 }
 
-void Loader::add(const string &k, LoaderAction *a)
+void Loader::add(const string &kwd, LoaderAction *act)
 {
-       ActionMap::iterator i = actions.find(k);
+       ActionKey key(kwd, act->get_signature());
+       ActionMap::iterator i = actions.find(key);
        if(i!=actions.end())
        {
                delete i->second;
-               i->second = a;
+               i->second = act;
        }
        else
-               actions[k] = a;
+               actions[key] = act;
+}
+
+LoaderAction *Loader::find_action(const ActionKey &key) const
+{
+       ActionMap::const_iterator begin = actions.lower_bound(ActionKey(key.keyword, string()));
+       ActionMap::const_iterator end = actions.upper_bound(ActionKey(key.keyword, "~"));
+
+       if(begin==end)
+               throw KeyError("Unknown keyword", key.keyword);
+
+       for(ActionMap::const_iterator i=begin; i!=end; ++i)
+               if(signature_match(key.signature, i->first.signature))
+                       return i->second;
+
+       throw KeyError(format("Keyword '%s' does not accept signature '%s'", key.keyword, key.signature));
+}
+
+
+Loader::ActionKey::ActionKey(const string &k, const string &s):
+       keyword(k),
+       signature(s)
+{ }
+
+bool Loader::ActionKey::operator<(const ActionKey &other) const
+{
+       if(keyword!=other.keyword)
+               return keyword<other.keyword;
+       return signature<other.signature;
 }
 
 } // namespace DataFile
index 57481cff28d36fca44b19db0c91784e7ecc54573..5c8726a179683c841e6439e57fd3cfa4772394e2 100644 (file)
@@ -1,7 +1,7 @@
 /* $Id$
 
 This file is part of libmspdatafile
-Copyright © 2006-2008  Mikko Rasa, Mikkosoft Productions
+Copyright © 2006-2008, 2010  Mikko Rasa, Mikkosoft Productions
 Distributed under the LGPL
 */
 
@@ -44,7 +44,17 @@ See also classes BasicLoader and BasicLoader2.
 class Loader
 {
 private:
-       typedef std::map<std::string, LoaderAction *> ActionMap;
+       struct ActionKey
+       {
+               std::string keyword;
+               std::string signature;
+
+               ActionKey(const std::string &, const std::string &);
+
+               bool operator<(const ActionKey &) const;
+       };
+
+       typedef std::map<ActionKey, LoaderAction *> ActionMap;
 
        ActionMap       actions;
        const Statement *cur_st;
@@ -128,6 +138,8 @@ protected:
 private:
        void add(const std::string &, LoaderAction *);
 
+       LoaderAction *find_action(const ActionKey &) const;
+
 protected:
        /** Returns the source of the statement being processed.  This can be used
        to implement relative paths in include-like statements.  Note that the
index 6eebeccc76f47c8144fac9f5ceeb93a35dff0a93..cfbe281f399c4071df30e12b17f53f6d99843d18 100644 (file)
@@ -28,6 +28,8 @@ public:
 
        /** Called to process a statement. */
        virtual void execute(Loader &, const Statement &) const = 0;
+
+       virtual std::string get_signature() const = 0;
 };
 
 
@@ -50,6 +52,9 @@ public:
                if(st.args.size()!=0) throw TypeError("Wrong number of arguments");
                (dynamic_cast<L &>(l).*func)();
        };
+
+       virtual std::string get_signature() const
+       { return std::string(); }
 };
 
 
@@ -72,6 +77,9 @@ public:
                if(st.args.size()!=1) throw TypeError("Wrong number of arguments");
                (dynamic_cast<L &>(l).*func)(st.args[0].get<A0>());
        }
+
+       virtual std::string get_signature() const
+       { return std::string(1, TypeInfo<A0>::signature); }
 };
 
 
@@ -97,6 +105,14 @@ public:
                        values.push_back(i->get<A0>());
                (dynamic_cast<L &>(l).*func)(values);
        }
+
+       virtual std::string get_signature() const
+       {
+               std::string result;
+               result += TypeInfo<A0>::signature;
+               result += '*';
+               return result;
+       }
 };
 
 
@@ -118,6 +134,9 @@ public:
        {
                (dynamic_cast<L &>(l).*func)(st);
        }
+
+       virtual std::string get_signature() const
+       { return "*"; }
 };
 
 
@@ -137,6 +156,14 @@ public:
                if(st.args.size()!=2) throw TypeError("Wrong number of arguments");
                (dynamic_cast<L &>(l).*func)(st.args[0].get<A0>(), st.args[1].get<A1>());
        }
+
+       virtual std::string get_signature() const
+       {
+               std::string result;
+               result += TypeInfo<A0>::signature;
+               result += TypeInfo<A1>::signature;
+               return result;
+       }
 };
 
 
@@ -156,6 +183,15 @@ public:
                if(st.args.size()!=3) throw TypeError("Wrong number of arguments");
                (dynamic_cast<L &>(l).*func)(st.args[0].get<A0>(), st.args[1].get<A1>(), st.args[2].get<A2>());
        }
+
+       virtual std::string get_signature() const
+       {
+               std::string result;
+               result += TypeInfo<A0>::signature;
+               result += TypeInfo<A1>::signature;
+               result += TypeInfo<A2>::signature;
+               return result;
+       }
 };
 
 
@@ -175,6 +211,16 @@ public:
                if(st.args.size()!=4) throw TypeError("Wrong number of arguments");
                (dynamic_cast<L &>(l).*func)(st.args[0].get<A0>(), st.args[1].get<A1>(), st.args[2].get<A2>(), st.args[3].get<A3>());
        }
+
+       virtual std::string get_signature() const
+       {
+               std::string result;
+               result += TypeInfo<A0>::signature;
+               result += TypeInfo<A1>::signature;
+               result += TypeInfo<A2>::signature;
+               result += TypeInfo<A3>::signature;
+               return result;
+       }
 };
 
 
@@ -194,6 +240,17 @@ public:
                if(st.args.size()!=5) throw TypeError("Wrong number of arguments");
                (dynamic_cast<L &>(l).*func)(st.args[0].get<A0>(), st.args[1].get<A1>(), st.args[2].get<A2>(), st.args[3].get<A3>(), st.args[4].get<A4>());
        }
+
+       virtual std::string get_signature() const
+       {
+               std::string result;
+               result += TypeInfo<A0>::signature;
+               result += TypeInfo<A1>::signature;
+               result += TypeInfo<A2>::signature;
+               result += TypeInfo<A3>::signature;
+               result += TypeInfo<A4>::signature;
+               return result;
+       }
 };
 
 
@@ -213,6 +270,9 @@ public:
                if(st.args.size()!=1) throw TypeError("Wrong number of arguments");
                dynamic_cast<typename L::Loader &>(l).get_object().*ptr0=st.args[0].get<T0>();
        }
+
+       virtual std::string get_signature() const
+       { return std::string(1, TypeInfo<T0>::signature); }
 };
 
 
@@ -233,6 +293,9 @@ public:
                typename L::Loader &ldr=dynamic_cast<typename L::Loader &>(l);
                ldr.get_object().*ptr0=ldr.get_collection().template get<T0>(st.args[0].get<std::string>());
        }
+
+       virtual std::string get_signature() const
+       { return std::string(1, TypeInfo<std::string>::signature); }
 };
 
 
@@ -255,6 +318,14 @@ public:
                dynamic_cast<typename L::Loader &>(l).get_object().*ptr0=st.args[0].get<T0>();
                dynamic_cast<typename L::Loader &>(l).get_object().*ptr1=st.args[1].get<T1>();
        }
+
+       virtual std::string get_signature() const
+       {
+               std::string result;
+               result += TypeInfo<T0>::signature;
+               result += TypeInfo<T1>::signature;
+               return result;
+       }
 };
 
 } // namespace DataFile