dlvhex
2.5.0
|
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 ®istry = *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 ®istry = *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 ®istry = *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 ®istry = *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 ®istry = *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 ®istry = *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(®istry); 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: