From 0514c24487f3822812e3faadc6684448263d7886 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 16 Apr 2010 04:28:02 +0200 Subject: [PATCH] Advice binding pattern finished, passing unit test now detecting a lot of syntax errors --- src/lib/advice/binding.cpp | 20 ++++++++--- src/lib/advice/binding.hpp | 27 +++++++++++---- tests/40components.tests | 33 +++++++++---------- tests/42query.tests | 4 +-- .../advice/advice-binding-pattern-test.cpp | 14 +++++--- 5 files changed, 64 insertions(+), 34 deletions(-) diff --git a/src/lib/advice/binding.cpp b/src/lib/advice/binding.cpp index 9500b8a50..4a8d35d29 100644 --- a/src/lib/advice/binding.cpp +++ b/src/lib/advice/binding.cpp @@ -42,13 +42,16 @@ using boost::lexical_cast; namespace lib { namespace advice { + LUMIERA_ERROR_DEFINE (BINDING_PATTERN_SYNTAX, "Unable to parse the given binding pattern definition"); + + /////////////////////TICKET #613 : centralise generally useful RegExps namespace{ // Implementation details - const string matchSym = "(\\w[\\w_\\.\\-]*)"; + 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] @@ -72,6 +75,8 @@ namespace advice { Binding::parse_and_append (Literal lit) { string def(lit); + string::const_iterator end_of_last_match = def.begin(); + sregex_iterator end; sregex_iterator pos (def.begin(),def.end(), findPredicate, match_continuous); // continuous: don't allow garbage *not* matched by the RegExp @@ -79,8 +84,15 @@ namespace advice { { smatch match = *pos; atoms_.insert (Atom (match[1], detectArity(match), match[3])); + end_of_last_match = match[0].second; ++pos; } + + 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); } @@ -147,13 +159,13 @@ namespace advice { } - /** bindings are considered equivalent if, after normalisation, - * their respective definitions are identical. + /** 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() + * form \c pred() ////TICKET #615 not yet implemented */ bool operator== (Binding const& b1, Binding const& b2) diff --git a/src/lib/advice/binding.hpp b/src/lib/advice/binding.hpp index 428caeb41..c73378c31 100644 --- a/src/lib/advice/binding.hpp +++ b/src/lib/advice/binding.hpp @@ -27,10 +27,10 @@ ** against a similar pattern associated with the attachment of a possible collaboration partner. ** Semantically, this list of atoms forms an conjunction of predicates to be resolved against ** similar predicates of the partner. Informally, when two entities attach to the Advice system, - ** each specifying a binding, they can be paired up if, when combining, the expressions in their - ** bindings all evaluate to true. + ** each specifying a binding, they can be paired up if any condition included into the binding + ** holds true for both sides. ** - ** Typically, a binding includes a \em type-guard predicate \c adviceType(xx) where \c xx is an + ** Typically, a binding includes a \em type-guard predicate \c advice.type.xx where \c xx is an ** identifier denoting a type used within an instantiation of the Advice collaboration, i.e. a type ** used as advice value in a instantiation of the PointOfAdvice template. Besides the type guard, ** a binding may narrow down the topic of the advice by providing further predicates. This allows for @@ -41,14 +41,27 @@ ** the advice type, and another client entity (the advised entity) could pick up this value ** without the need to now anything about the advisor. ** - ** Any binding can be normalised into a hash value, which plays a crucial role within the - ** implementation of the advice system. + ** \par implementation notes + ** Any binding will be normalised prior to further processing. This normalisation is based + ** on ordering by predicate symbol and arity. Patterns just comprised of constant symbols + ** (nullary atoms) can even be condensed into a single hash value, which allows for fast + ** match checking. For each pattern, we provide a matcher functor, allowing to check + ** a match against this pattern. In case of the mentioned symbol-only patterns, + ** this matcher will just hold the hash value of the normalised pattern. ** - ** TODO WIP-WIP + ** The advice system uses a binding index datastructure to keep track of any participating + ** patterns and especially of the matching pairs. Actually, this datastructure needs to store + ** only these matcher functors; thus, for a new binding to be used within the advice system, + ** the symbolic definition is parsed, then normalised and finally, after creating the matcher + ** functor, the full pattern definition can be discarded. ** ** @note as of 4/2010 this is an experimental setup and implemented just enough to work out ** the interfaces. Ichthyo expects this collaboration service to play a central role ** at various places within proc-layer. + ** @todo for now, \em only the case of a completely constant (ground) pattern is implemented. + ** Later we may consider to extend the binding patterns to allow variables, which, on match + ** could be fed as parameters to the bound advice. But this extension requires to extend + ** the simple hash-based match check to an actual unification of the patterns. ///TICKET #615 ** ** @see configrules.hpp ** @see typed-lookup.cpp corresponding implementation @@ -76,6 +89,8 @@ namespace advice { typedef size_t HashVal; + LUMIERA_ERROR_DECLARE (BINDING_PATTERN_SYNTAX); ///< Unable to parse the given binding pattern definition + /** diff --git a/tests/40components.tests b/tests/40components.tests index 38a3e34eb..d8719d0db 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -3,7 +3,7 @@ TESTING "Component Test Suite: common and basic components" ./test-lib --group=c TEST "Hello test world" HelloWorld_test 3 <Binding[] -out: aSymbol --->Binding[aSymbol/0()] -out: aSymbol followed by Garbage §&Ω%€GΩ%€ar☠☠☠bäaäääge --->Binding[Garbage/0(), aSymbol/0(), by/0(), followed/0()] -out: §&Ω%€GΩ%€ar☠☠☠baäääääge --->Binding[] -out: a, list , of ,symbols. --->Binding[a/0(), list/0(), of/0(), symbols./0()] -out: nullary(). --->Binding[nullary/0()] -out: nullary( ) --->Binding[nullary/0()] -out: nothing () --->Binding[nothing/0()] -out: predicate( with-argument ) --->Binding[predicate/1(with-argument)] -out: no (valid definition here) --->Binding[no/0()] -out: Binding[advice.type.n3lib6advice4test12_GLOBAL__N_111DummyAdviceE/0(), one/0(), three/1(four), two/0()] -out: b0==Binding[] -out: b1==Binding[cat1/0(), cat2/0()] -out: b2==Binding[cat1/0(), cat2/0()] -out: b2==Binding[advice.type.n7lumiera4TimeE/0(), cat1/0(), cat2/0(), cat3/1(zzz)] +TEST "Advice binding patterns" AdviceBindingPattern_test <Binding[] +out-lit: aSymbol --->Binding[aSymbol/0()] +out-lit: a.compound_Symbol-with-various.parts --->Binding[a.compound_Symbol-with-various.parts/0()] +out-lit: trailing Garbage allowed. ☢☢ eat ☠☠☠ atomic ☠☠☠ waste ☢☢ --->Binding[Garbage/0(), allowed/0(), trailing/0()] +out-lit: a, list , of ,symbols. --->Binding[a/0(), list/0(), of/0(), symbols/0()] +out-lit: nullary(). --->Binding[nullary/0()] +out-lit: nullary( ) --->Binding[nullary/0()] +out-lit: nullary . --->Binding[nullary/0()] +out-lit: predicate( with-argument ) --->Binding[predicate/1(with-argument)] +out-lit: Binding[advice.type.n3lib6advice4test12_GLOBAL__N_111DummyAdviceE/0(), one/0(), three/1(four), two/0()] +out-lit: b0==Binding[] +out-lit: b1==Binding[cat1/0(), cat2/0()] +out-lit: b2==Binding[cat1/0(), cat2/0()] +out-lit: b2==Binding[advice.type.n7lumiera4TimeE/0(), cat1/0(), cat2/0(), cat3/1(zzz)] return: 0 END diff --git a/tests/42query.tests b/tests/42query.tests index 5caf37bb1..98983c3b0 100644 --- a/tests/42query.tests +++ b/tests/42query.tests @@ -12,8 +12,8 @@ END TEST "normalise ID" QueryUtils_test normaliseID <(); @@ -104,7 +108,7 @@ namespace test { { Binding b0, b00; Binding b1 ("cat1(), cat2()."); - Binding b2 (" cat2 cat1 ***"); + Binding b2 (" cat2 cat1 ...."); cout << "b0==" << b0 << endl; cout << "b1==" << b1 << endl;