diff --git a/src/common/query.hpp b/src/common/query.hpp index bb9de33fc..1b2486c28 100644 --- a/src/common/query.hpp +++ b/src/common/query.hpp @@ -98,6 +98,7 @@ namespace lumiera { using lib::IxID; using lib::Symbol; using lib::Literal; + using util::isnil; using util::unConst; using boost::lexical_cast; using std::string; @@ -132,6 +133,7 @@ namespace lumiera { { EMPTY = 0 , GENERIC = 1 , DISCOVERY + , PLACEMENT }; struct QueryID @@ -258,6 +260,12 @@ namespace lumiera { * of specific resolution mechanisms. This way, clients may retrieve a set of results, * each representing a possible solution to the posed query. * + * @remarks lumiera::Query is an interface, but can be used as-is to represent a generic query. + * Specialised subclasses are required to provide a syntactic representation, but are + * free to do so only on demand. In this case, generate an \em empty lib::QueryText + * definition and implement the Query#buildSyntacticRepresentation function. + * Every fundamentally different kind of query needs to be listed in Goal::Kind. + * * @note until really integrating a rules based system * this is largely dummy placeholder implementation. * Some more specific query resolvers are available already, @@ -273,7 +281,7 @@ namespace lumiera { : public Goal { /** generic syntactical definition */ - lib::QueryText def_; + mutable lib::QueryText def_; protected: static QueryID @@ -283,6 +291,33 @@ namespace lumiera { return id; } + /** + * Extension point to generate a generic query definition on demand. + * Some specialised kinds of queries, intended to be treated by a specific resolver, + * may choose skip constructing a generic query representation, but are then bound + * to supplement such a generic definition through this function when required. + * The generated query definition must be sufficient to reconstruct the query + * in all respects. + * @return a complete definition of this query in predicate form + * @retval bottom token to indicate failure to comply to this requirement. + */ + virtual lib::QueryText + buildSyntacticRepresentation() const + { + WARN (query, "internal query not outfitted with a suitable query definition"); + return string("bottom"); + } + + /** access the complete syntactical representation of this query. + * May trigger on-demand initialisation */ + lib::QueryText + getQueryDefinition() const + { + if (isnil(this->def_)) + def_ = this->buildSyntacticRepresentation(); + return def_; + } + class Builder; @@ -348,7 +383,7 @@ namespace lumiera { friend size_t hash_value (Query const& q) { - return taggedHash (hash_value(q.def_), q.id_); + return taggedHash (hash_value(q.getQueryDefinition()), q.id_); } }; @@ -370,12 +405,14 @@ namespace lumiera { QueryKey (Goal::QueryID id, lib::QueryText q) : id_(id) , def_(q) - { } + { + ENSURE (!isnil(def_)); + } /** the empty or bottom query key */ QueryKey() : id_() - , def_("NIL") + , def_("false") { } // default copyable @@ -544,7 +581,7 @@ namespace lumiera { inline typename Query::Builder Query::rebuild() const { - return Builder(this->id_, this->def_); + return Builder(this->id_, getQueryDefinition()); } @@ -566,7 +603,7 @@ namespace lumiera { inline bool Query::usesPredicate (Symbol predicate) const { - return lib::query::hasTerm(predicate, this->def_); + return lib::query::hasTerm(predicate, getQueryDefinition()); } @@ -579,7 +616,7 @@ namespace lumiera { inline Query::operator QueryKey() const { - return QueryKey (this->id_, this->def_); + return QueryKey (this->id_, getQueryDefinition()); } diff --git a/src/include/logging.h b/src/include/logging.h index 6fd024b97..4595050d7 100644 --- a/src/include/logging.h +++ b/src/include/logging.h @@ -164,6 +164,9 @@ NOBUG_CPP_DEFINE_FLAG_PARENT ( plugins, progress); /** base channel flag to track overall working of the render engine */ NOBUG_CPP_DEFINE_FLAG_PARENT ( render, logging); NOBUG_CPP_DEFINE_FLAG_PARENT ( config, logging); //TODO: here seems to be an ambiguity weather "config" should denote the global config channel or the config-loder internals +NOBUG_CPP_DEFINE_FLAG_PARENT ( rules, config); +NOBUG_CPP_DEFINE_FLAG_PARENT ( query, config); +NOBUG_CPP_DEFINE_FLAG_PARENT ( resolver, config); /** base flag for software testing */ NOBUG_CPP_DEFINE_FLAG_PARENT ( test, logging); diff --git a/src/proc/mobject/session/scope-query.hpp b/src/proc/mobject/session/scope-query.hpp index 535668f1e..9c0e5b300 100644 --- a/src/proc/mobject/session/scope-query.hpp +++ b/src/proc/mobject/session/scope-query.hpp @@ -44,6 +44,7 @@ #include "proc/mobject/placement.hpp" #include "common/query/query-resolver.hpp" +#include "lib/format-string.hpp" #include @@ -97,7 +98,7 @@ namespace session { DiscoveryQuery () : _Query (_Query::defineQueryTypeID (Goal::DISCOVERY) - , lib::QueryText("TODO")) /////////////////////////////////////////////TODO: generate syntactic representation + , lib::QueryText("")) // syntactic representation supplied on demand { } private: @@ -189,6 +190,22 @@ namespace session { { return bind (&PlacementMO::isCompatible, _1 ); } + + /** supplement a syntactic representation (as generic query in predicate form). + * Building this representation is done on demand for performance reasons; + * typically a ScopeQuery is issued immediately into a known sub scope + * of the Session/Model and resolved by the PlacementIndex + * @todo we need a readable and sensible representation as generic query ///////////////////TICKET #901 + */ + lib::QueryText + buildSyntacticRepresentation() const + { + using util::_Fmt; + TODO ("valid syntactic representation of scope queries"); + return lib::QueryText (_Fmt ("scope(X, %08X), scopeRelation(X, %d)") + % hash_value(searchScope()) ////////TODO how to represent a placement in queries + % uint(searchDirection())); ////////TODO how to translate that in textual terms + } };