2010-04-12 05:04:27 +02:00
|
|
|
/*
|
|
|
|
|
Binding - pattern defining a specific attachment to the Advice system
|
|
|
|
|
|
|
|
|
|
Copyright (C) Lumiera.org
|
|
|
|
|
2010, Hermann Vosseler <Ichthyostega@web.de>
|
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU General Public License as
|
|
|
|
|
published by the Free Software Foundation; either version 2 of the
|
|
|
|
|
License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
|
|
* *****************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/advice/binding.hpp"
|
2010-04-14 07:02:40 +02:00
|
|
|
#include "lib/symbol.hpp"
|
2010-04-12 05:04:27 +02:00
|
|
|
|
2010-04-13 06:37:21 +02:00
|
|
|
#include <boost/functional/hash.hpp>
|
|
|
|
|
#include <boost/lexical_cast.hpp>
|
2010-04-14 07:02:40 +02:00
|
|
|
#include <boost/regex.hpp>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using lib::Literal;
|
2010-04-13 06:37:21 +02:00
|
|
|
|
2010-04-14 07:02:40 +02:00
|
|
|
using boost::regex;
|
|
|
|
|
using boost::smatch;
|
|
|
|
|
using boost::sregex_iterator;
|
|
|
|
|
using boost::match_continuous;
|
2010-04-13 06:37:21 +02:00
|
|
|
using boost::hash_combine;
|
2010-04-15 05:53:59 +02:00
|
|
|
using boost::lexical_cast;
|
2010-04-12 05:04:27 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace lib {
|
|
|
|
|
namespace advice {
|
2010-04-15 05:53:59 +02:00
|
|
|
|
|
|
|
|
|
2010-04-12 05:04:27 +02:00
|
|
|
|
2010-04-13 06:37:21 +02:00
|
|
|
|
2010-04-14 07:02:40 +02:00
|
|
|
/////////////////////TICKET #613 : centralise generally useful RegExps
|
|
|
|
|
namespace{ // Implementation details
|
|
|
|
|
|
|
|
|
|
const string matchSym = "(\\w[\\w_\\.\\-]*)";
|
|
|
|
|
const string matchArg = "\\(\\s*"+matchSym+"?\\s*\\)";
|
|
|
|
|
regex findPredicate ("\\s*"+matchSym+"("+matchArg+")?\\s*,?"); ///< \c sym(arg), groups: [symbol, parenthesis, argument symbol]
|
|
|
|
|
|
|
|
|
|
/** detect the \em arity of an predicate, as matched by #findPredicate.
|
|
|
|
|
* Currently, we don't really parse predicate logic notation and thus we
|
|
|
|
|
* just distinguish nullary predicates (no argument) and predicates with
|
|
|
|
|
* one single constant argument. */
|
|
|
|
|
inline uint
|
|
|
|
|
detectArity (smatch const& match)
|
|
|
|
|
{
|
|
|
|
|
if (!match[2].matched) return 0; // no parenthesis at all
|
|
|
|
|
if (!match[3].matched) return 0; // empty parenthesis
|
|
|
|
|
|
|
|
|
|
// later we could analyse the argument in detail here...
|
|
|
|
|
return 1; // but now we just accept a single constant symbol
|
|
|
|
|
}
|
2010-04-12 05:04:27 +02:00
|
|
|
}
|
|
|
|
|
|
2010-04-13 06:37:21 +02:00
|
|
|
|
|
|
|
|
void
|
2010-04-14 07:02:40 +02:00
|
|
|
Binding::parse_and_append (Literal lit)
|
|
|
|
|
{
|
|
|
|
|
string def(lit);
|
|
|
|
|
sregex_iterator end;
|
|
|
|
|
sregex_iterator pos (def.begin(),def.end(), findPredicate,
|
|
|
|
|
match_continuous); // continuous: don't allow garbage *not* matched by the RegExp
|
|
|
|
|
while (pos != end)
|
|
|
|
|
{
|
|
|
|
|
smatch match = *pos;
|
|
|
|
|
atoms_.insert (Atom (match[1], detectArity(match), match[3]));
|
|
|
|
|
++pos;
|
|
|
|
|
}
|
2010-04-13 06:37:21 +02:00
|
|
|
}
|
2010-04-14 07:02:40 +02:00
|
|
|
|
2010-04-13 06:37:21 +02:00
|
|
|
|
|
|
|
|
Binding::Binding ()
|
|
|
|
|
: atoms_()
|
|
|
|
|
{ }
|
|
|
|
|
|
2010-04-12 05:04:27 +02:00
|
|
|
Binding::Binding (Literal spec)
|
|
|
|
|
{
|
2010-04-14 07:02:40 +02:00
|
|
|
REQUIRE (spec);
|
2010-04-13 06:37:21 +02:00
|
|
|
parse_and_append (spec);
|
2010-04-12 05:04:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
Binding::addPredicate (Literal spec)
|
|
|
|
|
{
|
2010-04-14 07:02:40 +02:00
|
|
|
REQUIRE (spec);
|
2010-04-13 06:37:21 +02:00
|
|
|
parse_and_append (spec);
|
2010-04-12 05:04:27 +02:00
|
|
|
}
|
2010-04-15 05:53:59 +02:00
|
|
|
|
|
|
|
|
|
2010-04-12 05:04:27 +02:00
|
|
|
|
|
|
|
|
Binding::operator string() const
|
|
|
|
|
{
|
2010-04-14 07:02:40 +02:00
|
|
|
string repr("Binding[");
|
|
|
|
|
typedef NormalisedAtoms::const_iterator AIter;
|
|
|
|
|
AIter end = atoms_.end();
|
|
|
|
|
AIter pos = atoms_.begin();
|
|
|
|
|
for ( ; pos!=end ; ++pos)
|
|
|
|
|
repr += string(*pos)+", ";
|
|
|
|
|
|
|
|
|
|
if (0 < atoms_.size())
|
|
|
|
|
repr.resize(repr.size()-2);
|
|
|
|
|
|
|
|
|
|
repr += "]";
|
|
|
|
|
return repr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Binding::Atom::operator string() const
|
|
|
|
|
{
|
|
|
|
|
return sym_+"/"+lexical_cast<string> (ari_)
|
|
|
|
|
+"("+arg_+")";
|
2010-04-12 05:04:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HashVal
|
|
|
|
|
Binding::calculateHash() const
|
|
|
|
|
{
|
2010-04-13 06:37:21 +02:00
|
|
|
HashVal hash=0;
|
|
|
|
|
|
|
|
|
|
typedef NormalisedAtoms::const_iterator AIter;
|
|
|
|
|
AIter pos = atoms_.begin();
|
|
|
|
|
AIter end = atoms_.end();
|
|
|
|
|
for ( ; pos!=end ; ++pos)
|
|
|
|
|
{
|
|
|
|
|
hash_combine (hash, pos->sym());
|
|
|
|
|
hash_combine (hash, pos->arity());
|
2010-04-15 05:53:59 +02:00
|
|
|
hash_combine (hash, pos->arg()); //////////////TICKET #615 : not in final version with variable arguments
|
2010-04-13 06:37:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return hash;
|
2010-04-12 05:04:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-04-14 07:02:40 +02:00
|
|
|
/** bindings are considered equivalent if, after normalisation,
|
|
|
|
|
* their respective definitions are identical.
|
|
|
|
|
* @note for bindings without variable arguments, equivalence and matching
|
|
|
|
|
* always yield the same results. Contrary to this, two bindings with
|
|
|
|
|
* some variable arguments could match, without being defined identically.
|
|
|
|
|
* For example \c pred(X) matches \c pred(u) or any other binding of the
|
|
|
|
|
* form \c pred(<constant_value>)
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
operator== (Binding const& b1, Binding const& b2)
|
|
|
|
|
{
|
|
|
|
|
if (b1.atoms_.size() != b2.atoms_.size())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
ASSERT (b1.atoms_.size() == b2.atoms_.size());
|
|
|
|
|
|
|
|
|
|
typedef Binding::NormalisedAtoms::const_iterator Iter;
|
|
|
|
|
Iter end = b1.atoms_.end();
|
|
|
|
|
Iter p1 = b1.atoms_.begin();
|
|
|
|
|
Iter p2 = b2.atoms_.begin();
|
|
|
|
|
|
|
|
|
|
for ( ; p1!=end; ++p1, ++p2 )
|
|
|
|
|
if (! p1->identical(*p2))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-04-12 05:04:27 +02:00
|
|
|
|
|
|
|
|
}} // namespace lib::advice
|