]> git.tdb.fi Git - libs/datafile.git/blobdiff - source/loader.cpp
Prefer exact type match when looking for Loader actions
[libs/datafile.git] / source / loader.cpp
index e1a0d4abd7bcd80adfa4040c2a9bdf43ffb43ee7..a05e5f0dfe187b0060cd307f21146d7f199dbb55 100644 (file)
@@ -1,6 +1,6 @@
 #include <msp/core/raii.h>
 #include <msp/strings/format.h>
-#include "dataerror.h"
+#include "except.h"
 #include "loader.h"
 #include "type.h"
 
@@ -8,37 +8,37 @@ using namespace std;
 
 namespace {
 
-bool signature_match(char s, char a)
+int signature_match(char s, char a)
 {
        if(s==a)
-               return true;
+               return 3;
        if(s==Msp::DataFile::IntType::signature && a==Msp::DataFile::FloatType::signature)
-               return true;
-       return false;
+               return 1;
+       return 0;
 }
 
-bool signature_match(const string &st_sig, const string &act_sig)
+int signature_match(const string &st_sig, const string &act_sig)
 {
        if(act_sig=="*")
-               return true;
+               return 1;
        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;
+               int match = 3;
+               for(string::const_iterator i=st_sig.begin(); (i!=st_sig.end() && match); ++i)
+                       match = min(match, signature_match(*i, act_sig[0]));
 
-               return true;
+               return match;
        }
        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;
+               int match = 3;
+               for(unsigned i=0; (i<st_sig.size() && match); ++i)
+                       match = min(match, signature_match(st_sig[i], act_sig[i]));
 
-               return true;
+               return match ? match+1 : 0;
        }
        else
-               return false;
+               return 0;
 }
 
 }
@@ -47,28 +47,6 @@ bool signature_match(const string &st_sig, const string &act_sig)
 namespace Msp {
 namespace DataFile {
 
-class unknown_keyword: public runtime_error
-{
-public:
-       unknown_keyword(const std::string &k):
-               runtime_error(k)
-       { }
-
-       virtual ~unknown_keyword() throw() { }
-};
-
-
-class invalid_signature: public runtime_error
-{
-public:
-       invalid_signature(const std::string &k, const std::string &s):
-               runtime_error(format("%s %s", k, s))
-       { }
-
-       virtual ~invalid_signature() throw() { }
-};
-
-
 Loader::Loader():
        cur_st(0),
        direct(false),
@@ -87,7 +65,7 @@ void Loader::load(Parser &p)
        {
                if(p.peek(0))
                        load_direct(p, 0);
-               else
+               else if(p)  // Peek may have processed an __end, so recheck goodness
                {
                        // Parse in raw mode so we can peek immediately after a mode change
                        Statement st = p.parse(true);
@@ -213,11 +191,22 @@ LoaderAction *Loader::find_action(const StatementKey &key) const
        if(begin==end)
                throw unknown_keyword(key.keyword);
 
+       LoaderAction *act = 0;
+       int match = 0;
        for(ActionMap::const_iterator i=begin; i!=end; ++i)
-               if(signature_match(key.signature, i->first.signature))
-                       return i->second;
+       {
+               int m = signature_match(key.signature, i->first.signature);
+               if(m>match)
+               {
+                       act = i->second;
+                       match = m;
+               }
+       }
+
+       if(!act)
+               throw invalid_signature(key.keyword, key.signature);
 
-       throw invalid_signature(key.keyword, key.signature);
+       return act;
 }
 
 const string &Loader::get_source() const
@@ -227,5 +216,12 @@ const string &Loader::get_source() const
        return cur_st->source;
 }
 
+const string &Loader::get_keyword() const
+{
+       if(!cur_st)
+               throw logic_error("no current statement");
+       return cur_st->keyword;
+}
+
 } // namespace DataFile
 } // namespace Msp