2010-04-12 05:04:27 +02:00
/*
Binding - pattern defining a specific attachment to the Advice system
2010-12-17 23:28:49 +01:00
2010-04-12 05:04:27 +02:00
Copyright ( C ) Lumiera . org
2010 , Hermann Vosseler < Ichthyostega @ web . de >
2010-12-17 23:28:49 +01:00
2010-04-12 05:04:27 +02:00
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License as
2010-12-17 23:28:49 +01:00
published by the Free Software Foundation ; either version 2 of
the License , or ( at your option ) any later version .
2010-04-12 05:04:27 +02:00
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 .
2010-12-17 23:28:49 +01:00
2010-04-12 05:04:27 +02:00
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 0213 9 , USA .
2010-12-17 23:28:49 +01:00
2010-04-12 05:04:27 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-06-04 20:10:46 +02:00
# include "lib/util.hpp"
2012-12-01 08:44:07 +01:00
# include "lib/symbol.hpp"
# include "common/advice/binding.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-06-04 20:10:46 +02:00
using util : : isnil ;
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
2012-12-01 08:44:07 +01:00
namespace lumiera {
2010-04-12 05:04:27 +02:00
namespace advice {
2010-04-15 05:53:59 +02:00
2010-04-16 04:28:02 +02:00
LUMIERA_ERROR_DEFINE ( BINDING_PATTERN_SYNTAX , " Unable to parse the given binding pattern definition " ) ;
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
2010-04-16 04:28:02 +02:00
const string matchSym = " ( \\ w+(?:[ \\ . \\ -] \\ w+)*) " ;
2010-04-14 07:02:40 +02:00
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 ) ;
2010-04-16 04:28:02 +02:00
string : : const_iterator end_of_last_match = def . begin ( ) ;
2010-04-14 07:02:40 +02:00
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 ] ) ) ;
2010-04-16 04:28:02 +02:00
end_of_last_match = match [ 0 ] . second ;
2010-04-14 07:02:40 +02:00
+ + pos ;
}
2010-04-16 04:28:02 +02:00
if ( end_of_last_match ! = def . end ( )
& & * end_of_last_match ! = ' . '
) // if the match did *not stop at the end of the pattern definition list
throw lumiera : : error : : Invalid ( " Trailing garbage in binding pattern definition " ///////////////TICKET #197 should include the garbage, i.e. where the parsing stops
, LUMIERA_ERROR_BINDING_PATTERN_SYNTAX ) ;
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-06-04 20:10:46 +02:00
if ( ! isnil ( spec ) )
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-16 04:28:02 +02:00
/** bindings are considered equivalent if,
* after normalisation , their respective definitions are identical .
2010-04-14 07:02:40 +02:00
* @ 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
2010-04-16 04:28:02 +02:00
* form \ c pred ( < constant_value > ) ////TICKET #615 not yet implemented
2010-04-14 07:02:40 +02:00
*/
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
2012-12-01 08:44:07 +01:00
} } // namespace lumiera::advice