dlvhex  2.5.0
src/ConditionalLiteralPlugin.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/ConditionalLiteralPlugin.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 ConditionalLiteralPlugin::CtxData::CtxData():
00062 enabled(false)
00063 {
00064 }
00065 
00066 
00067 ConditionalLiteralPlugin::ConditionalLiteralPlugin():
00068 PluginInterface()
00069 {
00070     setNameVersion("dlvhex-conditionalLiteralPlugin[internal]", 2, 0, 0);
00071 }
00072 
00073 
00074 ConditionalLiteralPlugin::~ConditionalLiteralPlugin()
00075 {
00076 }
00077 
00078 
00079 // output help message for this plugin
00080 void ConditionalLiteralPlugin::printUsage(std::ostream& o) const
00081 {
00082     //    123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-
00083     o << "     --conditinal-enable[=true,false]" << std::endl
00084         << "                      Enable conditional literals (default is enabled)." << std::endl;
00085 }
00086 
00087 
00088 // accepted options: --choice-enable
00089 //
00090 // processes options for this plugin, and removes recognized options from pluginOptions
00091 // (do not free the pointers, the const char* directly come from argv)
00092 void ConditionalLiteralPlugin::processOptions(
00093 std::list<const char*>& pluginOptions,
00094 ProgramCtx& ctx)
00095 {
00096     ConditionalLiteralPlugin::CtxData& ctxdata = ctx.getPluginData<ConditionalLiteralPlugin>();
00097     ctxdata.enabled = true;
00098 
00099     typedef std::list<const char*>::iterator Iterator;
00100     Iterator it;
00101     WARNING("create (or reuse, maybe from potassco?) cmdline option processing facility")
00102         it = pluginOptions.begin();
00103     while( it != pluginOptions.end() ) {
00104         bool processed = false;
00105         const std::string str(*it);
00106         if( boost::starts_with(str, "--conditional-enable" ) ) {
00107             std::string m = str.substr(std::string("--conditional-enable").length());
00108             if (m == "" || m == "=true") {
00109                 ctxdata.enabled = true;
00110             }
00111             else if (m == "=false") {
00112                 ctxdata.enabled = false;
00113             }
00114             else {
00115                 std::stringstream ss;
00116                 ss << "Unknown --conditional-enable option: " << m;
00117                 throw PluginError(ss.str());
00118             }
00119             processed = true;
00120         }
00121 
00122         if( processed ) {
00123             // return value of erase: element after it, maybe end()
00124             DBGLOG(DBG,"ConditionalLiteralPlugin successfully processed option " << str);
00125             it = pluginOptions.erase(it);
00126         }
00127         else {
00128             it++;
00129         }
00130     }
00131 }
00132 
00133 
00134 class ConditionalParserModuleSemantics:
00135 public HexGrammarSemantics
00136 {
00137     public:
00138         int varnr;
00139         ConditionalLiteralPlugin::CtxData& ctxdata;
00140 
00141     public:
00142         ConditionalParserModuleSemantics(ProgramCtx& ctx):
00143         HexGrammarSemantics(ctx),
00144             varnr(0),
00145         ctxdata(ctx.getPluginData<ConditionalLiteralPlugin>()) {
00146         }
00147 
00148         // use SemanticActionBase to redirect semantic action call into globally
00149         // specializable sem<T> struct space
00150         struct conditionalLieral:
00151         SemanticActionBase<ConditionalParserModuleSemantics, ID, conditionalLieral>
00152         {
00153             conditionalLieral(ConditionalParserModuleSemantics& mgr):
00154             conditionalLieral::base_type(mgr) {
00155             }
00156         };
00157 };
00158 
00159 template<>
00160 struct sem<ConditionalParserModuleSemantics::conditionalLieral>
00161 {
00162     void operator()(
00163         ConditionalParserModuleSemantics& mgr,
00164         const boost::fusion::vector2<
00165         dlvhex::ID,
00166         boost::optional<std::vector<dlvhex::ID> >
00167         >& source,
00168     ID& target) {
00169         RegistryPtr reg = mgr.ctx.registry();
00170 
00171         ID derivedAtomID = boost::fusion::at_c<0>(source);
00172 
00173         Rule condRule(ID::MAINKIND_RULE | ID::SUBKIND_RULE_REGULAR);
00174 
00175         // count instances of the conditional part which do not fulfill the derived part; this number must be 0
00176         DBGLOG(DBG, "Creating aggregate #count{ ... : naf derived(...), condition(...) }");
00177         AggregateAtom cnt(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_AGGREGATE);
00178         cnt.tuple[0] = ID::termFromInteger(0);
00179         cnt.tuple[1] = ID::termFromBuiltin(ID::TERM_BUILTIN_EQ);
00180         cnt.tuple[2] = ID::termFromBuiltin(ID::TERM_BUILTIN_AGGCOUNT);
00181         cnt.tuple[3] = ID_FAIL;
00182         cnt.tuple[4] = ID_FAIL;
00183         ID cntID;
00184         std::set<ID> vars;
00185         reg->getVariablesInID(derivedAtomID, vars);
00186         cnt.variables.insert(cnt.variables.end(), vars.begin(), vars.end());
00187         if (!!boost::fusion::at_c<1>(source)) cnt.literals = boost::fusion::at_c<1>(source).get();
00188         cnt.literals.push_back(ID::nafLiteralFromAtom(derivedAtomID));
00189         cntID = reg->aatoms.storeAndGetID(cnt);
00190         DBGLOG(DBG, "Result: " << printToString<RawPrinter>(cntID, reg));
00191 
00192         target = cntID;
00193     }
00194 };
00195 
00196 namespace
00197 {
00198 
00199     template<typename Iterator, typename Skipper>
00200         struct ConditionalParserModuleGrammarBase:
00201     // we derive from the original hex grammar
00202     // -> we can reuse its rules
00203     public HexGrammarBase<Iterator, Skipper>
00204     {
00205         typedef HexGrammarBase<Iterator, Skipper> Base;
00206 
00207         ConditionalParserModuleSemantics& sem;
00208 
00209         ConditionalParserModuleGrammarBase(ConditionalParserModuleSemantics& sem):
00210         Base(sem),
00211         sem(sem) {
00212             typedef ConditionalParserModuleSemantics Sem;
00213 
00214             conditionalLieral
00215             // The gringo syntax for conditional literals is as follows:
00216             //      p(X1, ..., Xn) : l1(...), ..., ln(...)
00217             // where l1, ..., ln are possibly default-negated literals.
00218             // Note that the literals in the condition are comma-separated, i.e., all l1(...), ..., ln(...) belong to the condition.
00219             // There overall conditional literal is terminated by semicolon.
00220             // Therefore, the HEX-syntax was extended such that body literals can be separated either by comma or by semicolon,
00221             // where the parser of conditional literals should greedily process literals until a semicolon appears.
00222             // Examples:
00223             // 1. x :- y : u, w; t.
00224             //    is interpreted such that the head contains the atom x, and the body contains the conditional literal y:u,w (derived atom y, conditions u and w) and the ordinary literal t.
00225             // 2. x :- r, s; t.
00226             //    is interpreted such that the head contains the atom x, and the body contains literals r, s and t.
00227             //    Since there is no conditional literal in the body, comma and semicolon have the same semantics and separate the literals of the body.
00228                 =  (
00229                 Base::classicalAtom >> qi::lit(':') >> (Base::bodyLiteral % qi::lit(',')) > qi::eps
00230                 ) [ Sem::conditionalLieral(sem) ];
00231 
00232             #ifdef BOOST_SPIRIT_DEBUG
00233             BOOST_SPIRIT_DEBUG_NODE(conditionalLieral);
00234             #endif
00235         }
00236 
00237         qi::rule<Iterator, ID(), Skipper> conditionalLieral;
00238     };
00239 
00240     struct ConditionalParserModuleGrammar:
00241     ConditionalParserModuleGrammarBase<HexParserIterator, HexParserSkipper>,
00242     // required for interface
00243     // note: HexParserModuleGrammar =
00244     //       boost::spirit::qi::grammar<HexParserIterator, HexParserSkipper>
00245         HexParserModuleGrammar
00246     {
00247         typedef ConditionalParserModuleGrammarBase<HexParserIterator, HexParserSkipper> GrammarBase;
00248         typedef HexParserModuleGrammar QiBase;
00249 
00250         ConditionalParserModuleGrammar(ConditionalParserModuleSemantics& sem):
00251         GrammarBase(sem),
00252         QiBase(GrammarBase::conditionalLieral) {
00253         }
00254     };
00255     typedef boost::shared_ptr<ConditionalParserModuleGrammar>
00256         ConditionalParserModuleGrammarPtr;
00257 
00258     // moduletype = HexParserModule::BODYATOM
00259     template<enum HexParserModule::Type moduletype>
00260     class ConditionalParserModule:
00261     public HexParserModule
00262     {
00263         public:
00264             // the semantics manager is stored/owned by this module!
00265             ConditionalParserModuleSemantics sem;
00266             // we also keep a shared ptr to the grammar module here
00267             ConditionalParserModuleGrammarPtr grammarModule;
00268 
00269             ConditionalParserModule(ProgramCtx& ctx):
00270             HexParserModule(moduletype),
00271             sem(ctx) {
00272                 LOG(INFO,"constructed ConditionalParserModule");
00273             }
00274 
00275             virtual HexParserModuleGrammarPtr createGrammarModule() {
00276                 assert(!grammarModule && "for simplicity (storing only one grammarModule pointer) we currently assume this will be called only once .. should be no problem to extend");
00277                 grammarModule.reset(new ConditionalParserModuleGrammar(sem));
00278                 LOG(INFO,"created ConditionalParserModuleGrammar");
00279                 return grammarModule;
00280             }
00281     };
00282 
00283 }                                // anonymous namespace
00284 
00285 
00286 // create parser modules that extend and the basic hex grammar
00287 // this parser also stores the query information into the plugin
00288 std::vector<HexParserModulePtr>
00289 ConditionalLiteralPlugin::createParserModules(ProgramCtx& ctx)
00290 {
00291     DBGLOG(DBG,"ConditionalLiteralPlugin::createParserModules()");
00292     std::vector<HexParserModulePtr> ret;
00293 
00294     ConditionalLiteralPlugin::CtxData& ctxdata = ctx.getPluginData<ConditionalLiteralPlugin>();
00295     if( ctxdata.enabled ) {
00296         ret.push_back(HexParserModulePtr(
00297             new ConditionalParserModule<HexParserModule::BODYATOM>(ctx)));
00298     }
00299 
00300     return ret;
00301 }
00302 
00303 
00304 std::vector<PluginAtomPtr> ConditionalLiteralPlugin::createAtoms(ProgramCtx& ctx) const
00305 {
00306     std::vector<PluginAtomPtr> ret;
00307     // we don't have external atoms, only a parer plugin and a rewriter
00308     return ret;
00309 }
00310 
00311 
00312 void ConditionalLiteralPlugin::setupProgramCtx(ProgramCtx& ctx)
00313 {
00314     ConditionalLiteralPlugin::CtxData& ctxdata = ctx.getPluginData<ConditionalLiteralPlugin>();
00315     if( !ctxdata.enabled )
00316         return;
00317 
00318     RegistryPtr reg = ctx.registry();
00319 }
00320 
00321 
00322 DLVHEX_NAMESPACE_END
00323 
00324 // this would be the code to use this plugin as a "real" plugin in a .so file
00325 // but we directly use it in dlvhex.cpp
00326 #if 0
00327 ConditionalLiteralPlugin theConditionalLiteralPlugin;
00328 
00329 // return plain C type s.t. all compilers and linkers will like this code
00330 extern "C"
00331 void * PLUGINIMPORTFUNCTION()
00332 {
00333     return reinterpret_cast<void*>(& DLVHEX_NAMESPACE theConditionalLiteralPlugin);
00334 }
00335 #endif
00336 
00337 
00338 // vim:expandtab:ts=4:sw=4:
00339 // mode: C++
00340 // End: