dlvhex  2.5.0
src/FunctionPlugin.cpp
Go to the documentation of this file.
00001 /* dlvhex -- Answer-Set Programming with external interfaces.
00002  * Copyright (C) 2005-2007 Roman Schindlauer
00003  * Copyright (C) 2006-2015 Thomas Krennwallner
00004  * Copyright (C) 2009-2016 Peter Schüller
00005  * Copyright (C) 2011-2016 Christoph Redl
00006  * Copyright (C) 2015-2016 Tobias Kaminski
00007  * Copyright (C) 2015-2016 Antonius Weinzierl
00008  *
00009  * This file is part of dlvhex.
00010  *
00011  * dlvhex is free software; you can redistribute it and/or modify it
00012  * under the terms of the GNU Lesser General Public License as
00013  * published by the Free Software Foundation; either version 2.1 of
00014  * the License, or (at your option) any later version.
00015  *
00016  * dlvhex is distributed in the hope that it will be useful, but
00017  * WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  * Lesser General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Lesser General Public
00022  * License along with dlvhex; if not, write to the Free Software
00023  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00024  * 02110-1301 USA.
00025  */
00026 
00034 #ifdef HAVE_CONFIG_H
00035 #include "config.h"
00036 #endif                           // HAVE_CONFIG_H
00037 
00038 //#define BOOST_SPIRIT_DEBUG
00039 
00040 #include "dlvhex2/FunctionPlugin.h"
00041 #include "dlvhex2/PlatformDefinitions.h"
00042 #include "dlvhex2/ProgramCtx.h"
00043 #include "dlvhex2/Registry.h"
00044 #include "dlvhex2/Printer.h"
00045 #include "dlvhex2/Printhelpers.h"
00046 #include "dlvhex2/PredicateMask.h"
00047 #include "dlvhex2/Logger.h"
00048 #include "dlvhex2/HexParser.h"
00049 #include "dlvhex2/HexParserModule.h"
00050 #include "dlvhex2/HexGrammar.h"
00051 #include "dlvhex2/LiberalSafetyChecker.h"
00052 
00053 #include <boost/algorithm/string/predicate.hpp>
00054 #include <boost/lexical_cast.hpp>
00055 
00056 DLVHEX_NAMESPACE_BEGIN
00057 
00058 namespace spirit = boost::spirit;
00059 namespace qi = boost::spirit::qi;
00060 
00061 FunctionPlugin::CtxData::CtxData():
00062 maxArity(1), rewrite(false), parser(false)
00063 {
00064 }
00065 
00066 
00067 FunctionPlugin::FunctionPlugin():
00068 PluginInterface()
00069 {
00070     setNameVersion("dlvhex-functionplugin[internal]", 2, 0, 0);
00071 }
00072 
00073 
00074 FunctionPlugin::~FunctionPlugin()
00075 {
00076 }
00077 
00078 
00079 // output help message for this plugin
00080 void FunctionPlugin::printUsage(std::ostream& o) const
00081 {
00082     //    123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-
00083     o << "     --function-maxarity=<N>" << std::endl
00084         << "                      Maximum number of output terms in functionDecompose." << std::endl
00085         << "     --function-rewrite" << std::endl
00086         << "                      Rewrite function symbols to external atoms." << std::endl;
00087 //        << "     --function-functionals" << std::endl
00088 //        << "                      Enable support for functionals (experimental).";
00089 }
00090 
00091 
00092 // accepted options: --exists-enable
00093 //
00094 // processes options for this plugin, and removes recognized options from pluginOptions
00095 // (do not free the pointers, the const char* directly come from argv)
00096 void FunctionPlugin::processOptions(
00097 std::list<const char*>& pluginOptions,
00098 ProgramCtx& ctx)
00099 {
00100     FunctionPlugin::CtxData& ctxdata = ctx.getPluginData<FunctionPlugin>();
00101 
00102     typedef std::list<const char*>::iterator Iterator;
00103     Iterator it;
00104     WARNING("create (or reuse, maybe from potassco?) cmdline option processing facility")
00105         it = pluginOptions.begin();
00106     while( it != pluginOptions.end() ) {
00107         bool processed = false;
00108         const std::string str(*it);
00109         if( boost::starts_with(str, "--function-maxarity=") ) {
00110             ctxdata.maxArity = boost::lexical_cast<int>(str.substr(std::string("--function-maxarity=").length()));
00111             processed = true;
00112         }
00113         if( boost::starts_with(str, "--function-rewrite") ) {
00114             ctxdata.rewrite = true;
00115             processed = true;
00116         }
00117         if( boost::starts_with(str, "--function-functionals") ) {
00118             ctxdata.parser = true;
00119             processed = true;
00120         }
00121 
00122         if( processed ) {
00123             // return value of erase: element after it, maybe end()
00124             DBGLOG(DBG,"FunctionPlugin successfully processed option " << str);
00125             it = pluginOptions.erase(it);
00126         }
00127         else {
00128             it++;
00129         }
00130     }
00131 }
00132 
00133 
00134 class FunctionRewriter:
00135 public PluginRewriter
00136 {
00137     private:
00138         FunctionPlugin::CtxData& ctxdata;
00139     public:
00140         FunctionRewriter(FunctionPlugin::CtxData& ctxdata) : ctxdata(ctxdata) {}
00141         virtual ~FunctionRewriter() {}
00142 
00143         ID composeTerm(ProgramCtx& ctx, ID composedTerm, Rule& rule);
00144         ID decomposeTerm(ProgramCtx& ctx, ID composedTerm, Rule& rule);
00145         virtual void rewrite(ProgramCtx& ctx);
00146 };
00147 
00148 ID FunctionRewriter::composeTerm(ProgramCtx& ctx, ID composedTerm, Rule& rule)
00149 {
00150 
00151     if (!composedTerm.isNestedTerm()) return composedTerm;
00152 
00153     RegistryPtr reg = ctx.registry();
00154     Term term = reg->terms.getByID(composedTerm);
00155 
00156     ID newVar = reg->getAuxiliaryVariableSymbol('F', composedTerm);
00157 
00158     ExternalAtom eatom(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_EXTERNAL);
00159     std::stringstream composeStr;
00160     composeStr << "functionCompose";
00161     Term exPred(ID::MAINKIND_TERM | ID::SUBKIND_TERM_CONSTANT, composeStr.str());
00162     eatom.predicate = reg->storeTerm(exPred);
00163 
00164     BOOST_FOREACH (ID sub, term.arguments) {
00165         eatom.inputs.push_back(composeTerm(ctx, sub, rule));
00166     }
00167     eatom.tuple.push_back(newVar);
00168 
00169     ID composeAtomID = ID::posLiteralFromAtom(reg->eatoms.storeAndGetID(eatom));
00170     rule.kind |= ID::PROPERTY_RULE_EXTATOMS;
00171     rule.body.push_back(composeAtomID);
00172 
00173     return newVar;
00174 }
00175 
00176 
00177 ID FunctionRewriter::decomposeTerm(ProgramCtx& ctx, ID composedTerm, Rule& rule)
00178 {
00179 
00180     if (!composedTerm.isNestedTerm()) return composedTerm;
00181 
00182     RegistryPtr reg = ctx.registry();
00183     Term term = reg->terms.getByID(composedTerm);
00184 
00185     ID newVar = reg->getAuxiliaryVariableSymbol('F', composedTerm);
00186 
00187     ExternalAtom eatom(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_EXTERNAL);
00188     std::stringstream composeStr;
00189     composeStr << "functionDecompose" << (term.arguments.size() - 1);
00190     Term exPred(ID::MAINKIND_TERM | ID::SUBKIND_TERM_CONSTANT, composeStr.str());
00191     eatom.predicate = reg->storeTerm(exPred);
00192 
00193     BOOST_FOREACH (ID sub, term.arguments) {
00194         eatom.tuple.push_back(composeTerm(ctx, sub, rule));
00195     }
00196     eatom.inputs.push_back(newVar);
00197 
00198     ID composeAtomID = ID::posLiteralFromAtom(reg->eatoms.storeAndGetID(eatom));
00199     rule.kind |= ID::PROPERTY_RULE_EXTATOMS;
00200     rule.body.push_back(composeAtomID);
00201 
00202     return newVar;
00203 }
00204 
00205 
00206 void FunctionRewriter::rewrite(ProgramCtx& ctx)
00207 {
00208     RegistryPtr reg = ctx.registry();
00209 
00210     std::vector<ID> newIdb;
00211     BOOST_FOREACH (ID ruleID, ctx.idb) {
00212         const Rule& rule = reg->rules.getByID(ruleID);
00213 
00214         Rule newRule(rule.kind);
00215         BOOST_FOREACH (ID h, rule.head) {
00216             if (h.isOrdinaryAtom()) {
00217                 const OrdinaryAtom& oatom = reg->lookupOrdinaryAtom(h);
00218                 OrdinaryAtom newAtom(oatom.kind);
00219 
00220                 BOOST_FOREACH (ID term, oatom.tuple) {
00221                     newAtom.tuple.push_back(composeTerm(ctx, term, newRule));
00222                     if (newAtom.tuple[newAtom.tuple.size() - 1].isVariableTerm()) {
00223                         newAtom.kind &= (ID::ALL_ONES - ID::SUBKIND_MASK);
00224                         newAtom.kind |= ID::SUBKIND_ATOM_ORDINARYN;
00225                     }
00226                 }
00227                 newRule.head.push_back(reg->storeOrdinaryAtom(newAtom));
00228             }
00229         }
00230         BOOST_FOREACH (ID b, rule.body) {
00231             if (b.isOrdinaryAtom()) {
00232                 const OrdinaryAtom& oatom = reg->lookupOrdinaryAtom(b);
00233                 OrdinaryAtom newAtom(oatom.kind);
00234 
00235                 BOOST_FOREACH (ID term, oatom.tuple) {
00236                     newAtom.tuple.push_back(decomposeTerm(ctx, term, newRule));
00237                     if (newAtom.tuple[newAtom.tuple.size() - 1].isVariableTerm()) {
00238                         newAtom.kind &= (ID::ALL_ONES - ID::SUBKIND_MASK);
00239                         newAtom.kind |= ID::SUBKIND_ATOM_ORDINARYN;
00240                     }
00241                 }
00242                 if (b.isNaf()) newRule.body.push_back(ID::nafLiteralFromAtom(reg->storeOrdinaryAtom(newAtom)));
00243                 else newRule.body.push_back(ID::posLiteralFromAtom(reg->storeOrdinaryAtom(newAtom)));
00244             }
00245             else if (b.isExternalAtom()) {
00246                 const ExternalAtom& eatom = reg->eatoms.getByID(b);
00247                 ExternalAtom newAtom(eatom.kind);
00248 
00249                 newAtom.predicate = eatom.predicate;
00250                 BOOST_FOREACH (ID term, eatom.inputs) {
00251                     newAtom.inputs.push_back(composeTerm(ctx, term, newRule));
00252                 }
00253                 BOOST_FOREACH (ID term, eatom.tuple) {
00254                     newAtom.tuple.push_back(decomposeTerm(ctx, term, newRule));
00255                 }
00256                 if (b.isNaf()) newRule.body.push_back(ID::nafLiteralFromAtom(reg->eatoms.storeAndGetID(newAtom)));
00257                 else newRule.body.push_back(ID::posLiteralFromAtom(reg->eatoms.storeAndGetID(newAtom)));
00258             }
00259             else {
00260                 newRule.body.push_back(b);
00261             }
00262         }
00263         ID rid = reg->storeRule(newRule);
00264         newIdb.push_back(rid);
00265         /*
00266         a.
00267         p(f(b)) :- a.
00268         */
00269     }
00270     ctx.idb = newIdb;
00271 }
00272 
00273 
00274 // rewrite program by adding auxiliary query rules
00275 PluginRewriterPtr FunctionPlugin::createRewriter(ProgramCtx& ctx)
00276 {
00277     FunctionPlugin::CtxData& ctxdata = ctx.getPluginData<FunctionPlugin>();
00278     if( !ctxdata.rewrite )
00279         return PluginRewriterPtr();
00280 
00281     return PluginRewriterPtr(new FunctionRewriter(ctxdata));
00282 }
00283 
00284 
00285 class FunctionComposeAtom : public PluginAtom
00286 {
00287     public:
00288 
00289         FunctionComposeAtom() : PluginAtom("functionCompose", true) {
00290             prop.functional = true;
00291 
00292             addInputTuple();
00293 
00294             setOutputArity(1);
00295         }
00296 
00297         virtual void
00298         retrieve(const Query& query, Answer& answer) throw (PluginError) {
00299             Registry &registry = *getRegistry();
00300 
00301             Term t(ID::MAINKIND_TERM | ID::SUBKIND_TERM_NESTED, query.input, getRegistry());
00302             ID tid = registry.terms.getIDByString(t.symbol);
00303             if (tid == ID_FAIL) tid = registry.terms.storeAndGetID(t);
00304             Tuple tuple;
00305             tuple.push_back(tid);
00306             answer.get().push_back(tuple);
00307         }
00308 };
00309 
00310 class FunctionDecomposeAtom : public PluginAtom
00311 {
00312     private:
00313         int arity;
00314         std::string getName(std::string f, int ar) {
00315             std::stringstream ss;
00316             ss << f << ar;
00317             return ss.str();
00318         }
00319 
00320     public:
00321         FunctionDecomposeAtom(int arity) : PluginAtom(getName("functionDecompose", arity), true), arity(arity) {
00322             prop.functional = true;
00323             for (int i = 0; i <= arity; ++i) {
00324                 prop.wellorderingStrlen.insert(std::pair<int, int>(0, i));
00325             }
00326 
00327             addInputConstant();
00328 
00329             setOutputArity(arity + 1);
00330         }
00331 
00332         virtual void
00333         retrieve(const Query& query, Answer& answer) throw (PluginError) {
00334             Registry &registry = *getRegistry();
00335 
00336             const Term& t = registry.terms.getByID(query.input[0]);
00337             if (t.isNestedTerm() && t.arguments.size() == arity + 1) {
00338                 Tuple tuple;
00339                 BOOST_FOREACH (ID id, t.arguments) {
00340                     tuple.push_back(id);
00341                 }
00342                 answer.get().push_back(tuple);
00343             }
00344         }
00345 };
00346 
00347 class IsFunctionTermAtom : public PluginAtom
00348 {
00349     public:
00350         IsFunctionTermAtom() : PluginAtom("isFunctionTerm", true) {
00351             prop.functional = true;
00352 
00353             addInputConstant();
00354 
00355             setOutputArity(0);
00356         }
00357 
00358         virtual void
00359         retrieve(const Query& query, Answer& answer) throw (PluginError) {
00360             Registry &registry = *getRegistry();
00361 
00362             const Term& t = registry.terms.getByID(query.input[0]);
00363             if (t.isNestedTerm()) {
00364                 Tuple tuple;
00365                 answer.get().push_back(tuple);
00366             }
00367         }
00368 };
00369 
00370 class GetArityAtom : public PluginAtom
00371 {
00372     public:
00373         GetArityAtom() : PluginAtom("getArity", true) {
00374             prop.functional = true;
00375 
00376             addInputConstant();
00377 
00378             setOutputArity(1);
00379         }
00380 
00381         virtual void
00382         retrieve(const Query& query, Answer& answer) throw (PluginError) {
00383             Registry &registry = *getRegistry();
00384 
00385             const Term& t = registry.terms.getByID(query.input[0]);
00386             if (t.isNestedTerm()) {
00387                 Tuple tuple;
00388                 tuple.push_back(ID::termFromInteger(t.arguments.size() - 1));
00389                 answer.get().push_back(tuple);
00390             }
00391         }
00392 };
00393 
00394 class FunctionDecomposeGeneralAtom : public PluginAtom
00395 {
00396     public:
00397         FunctionDecomposeGeneralAtom() : PluginAtom("functionDecompose", true) {
00398             prop.functional = true;
00399             prop.wellorderingStrlen.insert(std::pair<int, int>(0, 0));
00400 
00401             addInputConstant();
00402             addInputConstant();
00403 
00404             setOutputArity(1);
00405         }
00406 
00407         virtual void
00408         retrieve(const Query& query, Answer& answer) throw (PluginError) {
00409             Registry &registry = *getRegistry();
00410 
00411             const Term& t = registry.terms.getByID(query.input[0]);
00412             if (t.isNestedTerm()) {
00413                 if (!query.input[1].isIntegerTerm() || query.input[1].address >= t.arguments.size()) throw PluginError("Argument position out of bounds");
00414                 Tuple tuple;
00415                 tuple.push_back(t.arguments[query.input[1].address]);
00416                 answer.get().push_back(tuple);
00417             }
00418         }
00419 };
00420 
00421 class FunctionInterprete : public PluginAtom
00422 {
00423     private:
00424         ProgramCtx* ctx;
00425 
00426         bool containsPlaceholder(const Term& t){
00427             for (int i = 0; i < t.arguments.size(); ++i){
00428                 if (t.arguments[i].isTerm() && t.arguments[i].isNestedTerm() ) {
00429                     if (containsPlaceholder(getRegistry()->terms.getByID(t.arguments[i]))) return true;
00430                 }else if (t.arguments[i].isTerm() && t.arguments[i].isConstantTerm()){
00431                     if (getRegistry()->terms.getByID(t.arguments[i]).getUnquotedString()[0] == '#') return true;
00432                 }
00433             }
00434             return false;
00435         }
00436    
00437     public:
00438         FunctionInterprete(ProgramCtx* ctx) : PluginAtom("functionInterprete", true), ctx(ctx) {
00439             addInputConstant();
00440             addInputTuple();
00441 
00442             setOutputArity(1);
00443         }
00444 
00445         virtual void
00446         retrieve(const Query& query, Answer& answer) throw (PluginError) {
00447             Registry &registry = *getRegistry();
00448 
00449             if (query.input[0].isTerm() && query.input[0].isNestedTerm()) {
00450                 // evaluate arguments recursively
00451                 Term tres = registry.terms.getByID(query.input[0]);
00452                 Tuple args;
00453                 for (int i = 1; i < registry.terms.getByID(query.input[0]).arguments.size(); ++i) {
00454                     Query query2 = query;
00455                     query2.input[0] = registry.terms.getByID(query.input[0]).arguments[i];
00456                     Answer answer2;
00457                     retrieve(query2, answer2);
00458                     args.push_back(answer2.get()[0][0]);
00459                     tres.arguments[i] = args[i - 1];
00460                 }
00461                 tres.updateSymbolOfNestedTerm(&registry);
00462                 ID tresID = registry.storeTerm(tres);
00463 
00464                 // if no term in args contains an atom of kind aux_f, then evaluate the outermost function
00465                 tres = registry.terms.getByID(tresID);    // make sure that nested terms are analyzed appropriately
00466                 if (!containsPlaceholder(tres)) {
00467                     // call function
00468                     std::string functionName = registry.terms.getByID(registry.terms.getByID(query.input[0]).arguments[0]).symbol;
00469                     if (this->ctx->pluginAtomMap().find(functionName) == this->ctx->pluginAtomMap().end()) {
00470                         throw PluginError("Function \"" + functionName + "\" is not defined");
00471                     }
00472                     PluginAtomPtr pa = this->ctx->pluginAtomMap().find(functionName)->second;
00473                     Tuple empty;
00474                     PluginAtom::Query nquery(query.ctx, query.interpretation, args, empty, ID_FAIL, query.predicateInputMask, query.assigned, query.changed);
00475                     PluginAtom::Answer nanswer;
00476                     pa->retrieveFacade(nquery, nanswer, NogoodContainerPtr(), query.ctx->config.getOption("UseExtAtomCache"));
00477 
00478                     // transfer answer
00479                     if (nanswer.get().size() != 1) throw PluginError("Function must return exactly one value");
00480                     answer.get().push_back(nanswer.get()[0]);
00481                 }else{
00482                     // keep the outermost function unresolved
00483                     Tuple t;
00484                     t.push_back(registry.storeTerm(tres));
00485                     answer.get().push_back(t);
00486                 }
00487             }else if (query.input[0].isConstantTerm() && registry.terms.getByID(query.input[0]).getUnquotedString()[0] == '#'){
00488                 std::string placeholder = registry.terms.getByID(query.input[0]).getUnquotedString().substr(1);
00489                 int placeholderInt;
00490                 try{
00491                     placeholderInt = boost::lexical_cast<int>(placeholder);
00492                 }catch(const boost::bad_lexical_cast&) {
00493                     throw PluginError("Invalid function parameter: " + placeholder);
00494                 }
00495                 Tuple t;
00496                 if (placeholderInt >= query.input.size()){
00497                     // reference to parameter which does not exist --> introduce new parameter
00498                     WARNING("Function parameter undefined: #" + placeholder);
00499                     std::stringstream ss;
00500                     ss << "\"#" << (placeholderInt - (query.input.size() - 1)) << "\"";
00501                     t.push_back(registry.storeConstantTerm(ss.str()));
00502                 }else{
00503                     t.push_back(query.input[placeholderInt]);
00504                 }
00505                 answer.get().push_back(t);
00506             }else if (query.input[0].isTerm() && (query.input[0].isConstantTerm() || (query.input[0].isIntegerTerm()))){
00507                 Tuple t;
00508                 t.push_back(query.input[0]);
00509                 answer.get().push_back(t);
00510             }else{
00511                 assert(false && "Error: Unknown parameter type");
00512             }
00513         }
00514 };
00515 
00516 
00517 class FunctionParserModuleTermSemantics:
00518 public HexGrammarSemantics
00519 {
00520     public:
00521         FunctionPlugin::CtxData& ctxdata;
00522 
00523     public:
00524         FunctionParserModuleTermSemantics(ProgramCtx& ctx):
00525         HexGrammarSemantics(ctx),
00526         ctxdata(ctx.getPluginData<FunctionPlugin>()) {
00527         }
00528 
00529         // use SemanticActionBase to redirect semantic action call into globally
00530         // specializable sem<T> struct space
00531         struct functionTermConstruct:
00532         SemanticActionBase<FunctionParserModuleTermSemantics, ID, functionTermConstruct>
00533         {
00534             functionTermConstruct(FunctionParserModuleTermSemantics& mgr):
00535             functionTermConstruct::base_type(mgr) {
00536             }
00537         };
00538 };
00539 
00540 // create semantic handler for above semantic action
00541 // (needs to be in globally specializable struct space)
00542 template<>
00543 struct sem<FunctionParserModuleTermSemantics::functionTermConstruct>
00544 {
00545     void operator()(
00546         FunctionParserModuleTermSemantics& mgr,
00547         const boost::fusion::vector3<
00548             dlvhex::ID,
00549             dlvhex::ID,
00550             boost::optional<dlvhex::Tuple>
00551             >& source,
00552         ID& target) {
00553         RegistryPtr reg = mgr.ctx.registry();
00554 
00555         ExternalAtom functionInterprete(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_EXTERNAL);
00556         Term exPred(ID::MAINKIND_TERM | ID::SUBKIND_TERM_CONSTANT, "functionInterprete");
00557         functionInterprete.predicate = reg->storeTerm(exPred);
00558 
00559         functionInterprete.tuple.push_back(boost::fusion::at_c<0>(source)); // output term
00560         functionInterprete.inputs.push_back(boost::fusion::at_c<1>(source)); // function object
00561         Tuple tup;
00562         if (!!boost::fusion::at_c<2>(source)) tup = boost::fusion::at_c<2>(source).get(); // arguments
00563         BOOST_FOREACH (ID inp, tup){
00564             functionInterprete.inputs.push_back(inp);
00565         }
00566 
00567         target = reg->eatoms.storeAndGetID(functionInterprete);
00568     }
00569 };
00570 
00571 class FunctionParserModuleAtomSemantics:
00572 public HexGrammarSemantics
00573 {
00574     public:
00575         FunctionPlugin::CtxData& ctxdata;
00576 
00577     public:
00578         FunctionParserModuleAtomSemantics(ProgramCtx& ctx):
00579         HexGrammarSemantics(ctx),
00580         ctxdata(ctx.getPluginData<FunctionPlugin>()) {
00581         }
00582 
00583         // use SemanticActionBase to redirect semantic action call into globally
00584         // specializable sem<T> struct space
00585         struct functionTermEval:
00586         SemanticActionBase<FunctionParserModuleAtomSemantics, ID, functionTermEval>
00587         {
00588             functionTermEval(FunctionParserModuleAtomSemantics& mgr):
00589             functionTermEval::base_type(mgr) {
00590             }
00591         };
00592 };
00593 
00594 // create semantic handler for above semantic action
00595 // (needs to be in globally specializable struct space)
00596 template<>
00597 struct sem<FunctionParserModuleAtomSemantics::functionTermEval>
00598 {
00599     void operator()(
00600         FunctionParserModuleAtomSemantics& mgr,
00601         const boost::fusion::vector4<
00602             dlvhex::ID,
00603             dlvhex::ID,
00604             boost::optional<boost::optional<dlvhex::Tuple> >,
00605             boost::optional<boost::optional<std::vector<std::vector<std::string> > > >
00606             >& source,
00607         ID& target) {
00608         RegistryPtr reg = mgr.ctx.registry();
00609 
00610         ExternalAtom functionInterprete(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_EXTERNAL);
00611         Term exPred(ID::MAINKIND_TERM | ID::SUBKIND_TERM_CONSTANT, "functionInterprete");
00612         functionInterprete.predicate = reg->storeTerm(exPred);
00613 
00614         functionInterprete.tuple.push_back(boost::fusion::at_c<0>(source)); // output term
00615         functionInterprete.inputs.push_back(boost::fusion::at_c<1>(source)); // function object
00616         Tuple tup;
00617         if (!!boost::fusion::at_c<2>(source) && !!boost::fusion::at_c<2>(source).get()) tup = boost::fusion::at_c<2>(source).get().get(); // arguments
00618         BOOST_FOREACH (ID inp, tup){
00619             functionInterprete.inputs.push_back(inp);
00620         }
00621         if (!!boost::fusion::at_c<3>(source) && !!boost::fusion::at_c<3>(source).get()) {
00622             functionInterprete.prop.interpretProperties(mgr.ctx.registry(), functionInterprete, boost::fusion::at_c<3>(source).get().get());
00623         }
00624 
00625         target = reg->eatoms.storeAndGetID(functionInterprete);
00626     }
00627 };
00628 
00629 namespace
00630 {
00631     template<typename Iterator, typename Skipper>
00632         struct FunctionParserModuleAtomGrammarBase:
00633     // we derive from the original hex grammar
00634     // -> we can reuse its rules
00635     public HexGrammarBase<Iterator, Skipper>
00636     {
00637         typedef HexGrammarBase<Iterator, Skipper> Base;
00638 
00639         FunctionParserModuleAtomSemantics& sem;
00640 
00641         FunctionParserModuleAtomGrammarBase(FunctionParserModuleAtomSemantics& sem):
00642         Base(sem),
00643         sem(sem) {
00644             typedef FunctionParserModuleAtomSemantics Sem;
00645 
00646             functionTermEval
00647                 = (Base::primitiveTerm >> qi::lit('=') >> qi::lit('$') >> Base::term >> -(qi::lit('(') >> -Base::terms >> qi::lit(')')) >> -(qi::lit('<') > -Base::externalAtomProperties >> qi::lit('>'))) [ Sem::functionTermEval(sem) ];
00648 
00649             #ifdef BOOST_SPIRIT_DEBUG
00650             BOOST_SPIRIT_DEBUG_NODE(functionTermEval);
00651             #endif
00652         }
00653 
00654         qi::rule<Iterator, ID(), Skipper> functionTermEval;
00655     };
00656 
00657     struct FunctionParserModuleAtomGrammar:
00658     FunctionParserModuleAtomGrammarBase<HexParserIterator, HexParserSkipper>,
00659     // required for interface
00660     // note: HexParserModuleGrammar =
00661     //       boost::spirit::qi::grammar<HexParserIterator, HexParserSkipper>
00662         HexParserModuleGrammar
00663     {
00664         typedef FunctionParserModuleAtomGrammarBase<HexParserIterator, HexParserSkipper> GrammarBase;
00665         typedef HexParserModuleGrammar QiBase;
00666 
00667         FunctionParserModuleAtomGrammar(FunctionParserModuleAtomSemantics& sem):
00668         GrammarBase(sem),
00669         QiBase(GrammarBase::functionTermEval) {
00670         }
00671     };
00672     typedef boost::shared_ptr<FunctionParserModuleAtomGrammar>
00673         FunctionParserModuleAtomGrammarPtr;
00674 
00675     template<enum HexParserModule::Type moduletype>
00676     class FunctionParserModuleAtom:
00677     public HexParserModule
00678     {
00679         public:
00680             // the semantics manager is stored/owned by this module!
00681             FunctionParserModuleAtomSemantics sem;
00682             // we also keep a shared ptr to the grammar module here
00683             FunctionParserModuleAtomGrammarPtr grammarModule;
00684 
00685             FunctionParserModuleAtom(ProgramCtx& ctx):
00686             HexParserModule(moduletype),
00687             sem(ctx) {
00688                 LOG(INFO,"constructed FunctionParserModuleAtom");
00689             }
00690 
00691             virtual HexParserModuleGrammarPtr createGrammarModule() {
00692                 assert(!grammarModule && "for simplicity (storing only one grammarModule pointer) we currently assume this will be called only once .. should be no problem to extend");
00693                 grammarModule.reset(new FunctionParserModuleAtomGrammar(sem));
00694                 LOG(INFO,"created FunctionParserModuleAtomGrammar");
00695                 return grammarModule;
00696             }
00697     };
00698 
00699 }                                // anonymous namespace
00700 
00701 
00702 // create parser modules that extend and the basic hex grammar
00703 // this parser also stores the query information into the plugin
00704 std::vector<HexParserModulePtr>
00705 FunctionPlugin::createParserModules(ProgramCtx& ctx)
00706 {
00707     DBGLOG(DBG,"FunctionPlugin::createParserModules()");
00708     std::vector<HexParserModulePtr> ret;
00709 
00710     FunctionPlugin::CtxData& ctxdata = ctx.getPluginData<FunctionPlugin>();
00711     if( ctxdata.parser ) {
00712         ret.push_back(HexParserModulePtr(
00713             new FunctionParserModuleAtom<HexParserModule::BODYATOM>(ctx)));
00714     }
00715 
00716     return ret;
00717 }
00718 
00719 std::vector<PluginAtomPtr> FunctionPlugin::createAtoms(ProgramCtx& ctx) const
00720 {
00721     std::vector<PluginAtomPtr> ret;
00722 
00723     // we have to do the program rewriting already here because it creates some side information that we need
00724     FunctionPlugin::CtxData& ctxdata = ctx.getPluginData<FunctionPlugin>();
00725 
00726     // return smart pointer with deleter (i.e., delete code compiled into this plugin)
00727     ret.push_back(PluginAtomPtr(new FunctionComposeAtom(), PluginPtrDeleter<PluginAtom>()));
00728     DBGLOG(DBG, "Adding functional atom with an input arity of up to " << ctxdata.maxArity);
00729     for (int i = 0; i <= ctxdata.maxArity; ++i) {
00730         ret.push_back(PluginAtomPtr(new FunctionDecomposeAtom(i), PluginPtrDeleter<PluginAtom>()));
00731     }
00732     ret.push_back(PluginAtomPtr(new IsFunctionTermAtom(), PluginPtrDeleter<PluginAtom>()));
00733     ret.push_back(PluginAtomPtr(new GetArityAtom(), PluginPtrDeleter<PluginAtom>()));
00734     ret.push_back(PluginAtomPtr(new FunctionDecomposeGeneralAtom(), PluginPtrDeleter<PluginAtom>()));
00735     ret.push_back(PluginAtomPtr(new FunctionInterprete(&ctx), PluginPtrDeleter<PluginAtom>()));
00736 
00737     return ret;
00738 }
00739 
00740 
00741 void FunctionPlugin::setupProgramCtx(ProgramCtx& ctx)
00742 {
00743     FunctionPlugin::CtxData& ctxdata = ctx.getPluginData<FunctionPlugin>();
00744     RegistryPtr reg = ctx.registry();
00745 }
00746 
00747 
00748 DLVHEX_NAMESPACE_END
00749 
00750 // this would be the code to use this plugin as a "real" plugin in a .so file
00751 // but we directly use it in dlvhex.cpp
00752 #if 0
00753 FunctionPlugin theFunctionPlugin;
00754 
00755 // return plain C type s.t. all compilers and linkers will like this code
00756 extern "C"
00757 void * PLUGINIMPORTFUNCTION()
00758 {
00759     return reinterpret_cast<void*>(& DLVHEX_NAMESPACE theFunctionPlugin);
00760 }
00761 #endif
00762 
00763 
00764 // vim:expandtab:ts=4:sw=4:
00765 // mode: C++
00766 // End: