From b34b46788d69853eabdbbd9e71ca82f2f5c09df8 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 4 Feb 2010 13:17:48 +0000 Subject: [PATCH] Allow overloading keywords with different signatures --- source/loader.cpp | 106 ++++++++++++++++++++++++++++++++++-------- source/loader.h | 16 ++++++- source/loaderaction.h | 71 ++++++++++++++++++++++++++++ 3 files changed, 172 insertions(+), 21 deletions(-) diff --git a/source/loader.cpp b/source/loader.cpp index 655514e..6da8599 100644 --- a/source/loader.cpp +++ b/source/loader.cpp @@ -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 #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; isecond) + + 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 ActionMap; + struct ActionKey + { + std::string keyword; + std::string signature; + + ActionKey(const std::string &, const std::string &); + + bool operator<(const ActionKey &) const; + }; + + typedef std::map 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 diff --git a/source/loaderaction.h b/source/loaderaction.h index 6eebecc..cfbe281 100644 --- a/source/loaderaction.h +++ b/source/loaderaction.h @@ -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).*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).*func)(st.args[0].get()); } + + virtual std::string get_signature() const + { return std::string(1, TypeInfo::signature); } }; @@ -97,6 +105,14 @@ public: values.push_back(i->get()); (dynamic_cast(l).*func)(values); } + + virtual std::string get_signature() const + { + std::string result; + result += TypeInfo::signature; + result += '*'; + return result; + } }; @@ -118,6 +134,9 @@ public: { (dynamic_cast(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).*func)(st.args[0].get(), st.args[1].get()); } + + virtual std::string get_signature() const + { + std::string result; + result += TypeInfo::signature; + result += TypeInfo::signature; + return result; + } }; @@ -156,6 +183,15 @@ public: if(st.args.size()!=3) throw TypeError("Wrong number of arguments"); (dynamic_cast(l).*func)(st.args[0].get(), st.args[1].get(), st.args[2].get()); } + + virtual std::string get_signature() const + { + std::string result; + result += TypeInfo::signature; + result += TypeInfo::signature; + result += TypeInfo::signature; + return result; + } }; @@ -175,6 +211,16 @@ public: if(st.args.size()!=4) throw TypeError("Wrong number of arguments"); (dynamic_cast(l).*func)(st.args[0].get(), st.args[1].get(), st.args[2].get(), st.args[3].get()); } + + virtual std::string get_signature() const + { + std::string result; + result += TypeInfo::signature; + result += TypeInfo::signature; + result += TypeInfo::signature; + result += TypeInfo::signature; + return result; + } }; @@ -194,6 +240,17 @@ public: if(st.args.size()!=5) throw TypeError("Wrong number of arguments"); (dynamic_cast(l).*func)(st.args[0].get(), st.args[1].get(), st.args[2].get(), st.args[3].get(), st.args[4].get()); } + + virtual std::string get_signature() const + { + std::string result; + result += TypeInfo::signature; + result += TypeInfo::signature; + result += TypeInfo::signature; + result += TypeInfo::signature; + result += TypeInfo::signature; + return result; + } }; @@ -213,6 +270,9 @@ public: if(st.args.size()!=1) throw TypeError("Wrong number of arguments"); dynamic_cast(l).get_object().*ptr0=st.args[0].get(); } + + virtual std::string get_signature() const + { return std::string(1, TypeInfo::signature); } }; @@ -233,6 +293,9 @@ public: typename L::Loader &ldr=dynamic_cast(l); ldr.get_object().*ptr0=ldr.get_collection().template get(st.args[0].get()); } + + virtual std::string get_signature() const + { return std::string(1, TypeInfo::signature); } }; @@ -255,6 +318,14 @@ public: dynamic_cast(l).get_object().*ptr0=st.args[0].get(); dynamic_cast(l).get_object().*ptr1=st.args[1].get(); } + + virtual std::string get_signature() const + { + std::string result; + result += TypeInfo::signature; + result += TypeInfo::signature; + return result; + } }; } // namespace DataFile -- 2.43.0