From 3ea87967c9fe9ea0989a790dc5f5cca9e710b7bc Mon Sep 17 00:00:00 2001 From: Benjamin Kaufmann Date: Fri, 23 Feb 2024 14:28:50 +0100 Subject: [PATCH] Reduce duplication in gringo options. * GringoApp, ClingoApp, and ClingoLib all provide a set of gringo options. Extract GringoOptions struct and provide common function for registering options with a command-line option group. --- libclingo/CMakeLists.txt | 2 + libclingo/clingo/clingocontrol.hh | 79 +------------- libclingo/clingo/gringo_options.hh | 56 ++++++++++ libclingo/src/clingo_app.cc | 58 +--------- libclingo/src/clingocontrol.cc | 43 +------- libclingo/src/gringo_app.cc | 160 +++------------------------- libclingo/src/gringo_options.cc | 165 +++++++++++++++++++++++++++++ 7 files changed, 241 insertions(+), 322 deletions(-) create mode 100644 libclingo/clingo/gringo_options.hh create mode 100644 libclingo/src/gringo_options.cc diff --git a/libclingo/CMakeLists.txt b/libclingo/CMakeLists.txt index cd33dcd52..30d34a8bf 100644 --- a/libclingo/CMakeLists.txt +++ b/libclingo/CMakeLists.txt @@ -9,6 +9,7 @@ set(header-group-clingo "${CMAKE_CURRENT_SOURCE_DIR}/clingo/clingo_app.hh" "${CMAKE_CURRENT_SOURCE_DIR}/clingo/clingocontrol.hh" "${CMAKE_CURRENT_SOURCE_DIR}/clingo/control.hh" + "${CMAKE_CURRENT_SOURCE_DIR}/clingo/gringo_options.hh" "${CMAKE_CURRENT_SOURCE_DIR}/clingo/incmode.hh" "${CMAKE_CURRENT_SOURCE_DIR}/clingo/scripts.hh") source_group("${ide_header_group}\\clingo" FILES ${header-group-clingo}) @@ -28,6 +29,7 @@ set(source-group "${CMAKE_CURRENT_SOURCE_DIR}/src/clingocontrol.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/control.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/gringo_app.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/src/gringo_options.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/incmode.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/scripts.cc") source_group("${ide_source_group}" FILES ${source-group}) diff --git a/libclingo/clingo/clingocontrol.hh b/libclingo/clingo/clingocontrol.hh index 324c055ca..bf4c93aaf 100644 --- a/libclingo/clingo/clingocontrol.hh +++ b/libclingo/clingo/clingocontrol.hh @@ -28,6 +28,7 @@ #include "clingo.h" #include #include +#include #include #include #include @@ -42,7 +43,6 @@ #include #include #include -#include #include #include @@ -82,81 +82,7 @@ private: }; // {{{1 declaration of ClingoOptions - -struct ClingoOptions { - using SigVec = std::vector; - std::vector defines; - Output::OutputOptions outputOptions; - Output::OutputFormat outputFormat = Output::OutputFormat::INTERMEDIATE; - bool verbose = false; - bool wNoOperationUndefined = false; - bool wNoAtomUndef = false; - bool wNoFileIncluded = false; - bool wNoGlobalVariable = false; - bool wNoOther = false; - bool rewriteMinimize = false; - bool keepFacts = false; - bool singleShot = false; - SigVec sigvec; -}; - -inline void enableAll(ClingoOptions& out, bool enable) { - out.wNoAtomUndef = !enable; - out.wNoFileIncluded = !enable; - out.wNoOperationUndefined = !enable; - out.wNoGlobalVariable = !enable; - out.wNoOther = !enable; -} - -inline bool parseWarning(const std::string& str, ClingoOptions& out) { - if (str == "none") { enableAll(out, false); return true; } - if (str == "all") { enableAll(out, true); return true; } - if (str == "no-atom-undefined") { out.wNoAtomUndef = true; return true; } - if (str == "atom-undefined") { out.wNoAtomUndef = false; return true; } - if (str == "no-file-included") { out.wNoFileIncluded = true; return true; } - if (str == "file-included") { out.wNoFileIncluded = false; return true; } - if (str == "no-operation-undefined") { out.wNoOperationUndefined = true; return true; } - if (str == "operation-undefined") { out.wNoOperationUndefined = false; return true; } - if (str == "no-global-variable") { out.wNoGlobalVariable = true; return true; } - if (str == "global-variable") { out.wNoGlobalVariable = false; return true; } - if (str == "no-other") { out.wNoOther = true; return true; } - if (str == "other") { out.wNoOther = false; return true; } - return false; -} - -inline bool parsePreserveFacts(const std::string& str, ClingoOptions& out) { - if (str == "none") { out.keepFacts = false; out.outputOptions.preserveFacts = false; return true; } - if (str == "body") { out.keepFacts = true; out.outputOptions.preserveFacts = false; return true; } - if (str == "symtab") { out.keepFacts = false; out.outputOptions.preserveFacts = true; return true; } - if (str == "all") { out.keepFacts = true; out.outputOptions.preserveFacts = true; return true; } - return false; -} - -inline std::vector split(std::string const &source, char const *delimiter = " ", bool keepEmpty = false) { - std::vector results; - size_t prev = 0; - size_t next = 0; - while ((next = source.find_first_of(delimiter, prev)) != std::string::npos) { - if (keepEmpty || (next - prev != 0)) { results.push_back(source.substr(prev, next - prev)); } - prev = next + 1; - } - if (prev < source.size()) { results.push_back(source.substr(prev)); } - return results; -} - -inline bool parseSigVec(const std::string& str, ClingoOptions::SigVec& sigvec) { - for (auto &x : split(str, ",")) { - auto y = split(x, "/"); - if (y.size() != 2) { return false; } - unsigned a; - if (!Potassco::string_cast(y[1], a)) { return false; } - bool sign = !y[0].empty() && y[0][0] == '-'; - if (sign) { y[0] = y[0].substr(1); } - sigvec.emplace_back(y[0].c_str(), a, sign); - } - return true; -} - +using ClingoOptions = GringoOptions; // {{{1 declaration of ClingoControl class ClingoPropagatorLock : public Clasp::ClingoPropagatorLock { @@ -271,7 +197,6 @@ public: ClingoControl(Scripts &scripts, bool clingoMode, Clasp::ClaspFacade *clasp, Clasp::Cli::ClaspCliConfig &claspConfig, PostGroundFunc pgf, PreSolveFunc psf, Logger::Printer printer, unsigned messageLimit); ~ClingoControl() noexcept override; void prepare(Assumptions ass); - void commitExternals(); void parse(); void parse(const StringVec& files, const ClingoOptions& opts, Clasp::Asp::LogicProgram* out, bool addStdIn = true); void main(IClingoApp &app, StringVec const &files, const ClingoOptions& opts, Clasp::Asp::LogicProgram* out); diff --git a/libclingo/clingo/gringo_options.hh b/libclingo/clingo/gringo_options.hh new file mode 100644 index 000000000..24a20fc99 --- /dev/null +++ b/libclingo/clingo/gringo_options.hh @@ -0,0 +1,56 @@ +// {{{ MIT License + +// Copyright 2024 + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +// }}} + +#ifndef CLINGO_GRINGO_OPTIONS_HH +#define CLINGO_GRINGO_OPTIONS_HH + +#include +#include +#include +#include +namespace Gringo { + +struct GringoOptions { + enum class AppType {Gringo, Clingo, Lib}; + using SigVec = std::vector; + std::vector defines; + Output::OutputOptions outputOptions; + Output::OutputFormat outputFormat = Output::OutputFormat::INTERMEDIATE; + bool verbose = false; + bool wNoOperationUndefined = false; + bool wNoAtomUndef = false; + bool wNoFileIncluded = false; + bool wNoGlobalVariable = false; + bool wNoOther = false; + bool rewriteMinimize = false; + bool keepFacts = false; + bool singleShot = false; + SigVec sigvec; +}; + +void registerOptions(Potassco::ProgramOptions::OptionGroup& group, GringoOptions& opts, GringoOptions::AppType type); + +} // namespace Gringo + +#endif // CLINGO_GRINGO_OPTIONS_HH diff --git a/libclingo/src/clingo_app.cc b/libclingo/src/clingo_app.cc index 2fa0d2dc4..1d69785cb 100644 --- a/libclingo/src/clingo_app.cc +++ b/libclingo/src/clingo_app.cc @@ -33,68 +33,12 @@ namespace Gringo { ClingoApp::ClingoApp(UIClingoApp app) : app_{std::move(app)} { } -static bool parseConst(const std::string& str, std::vector& out) { - out.push_back(str); - return true; -} - -static bool parseText(const std::string&, ClingoOptions& out) { - out.outputFormat = Gringo::Output::OutputFormat::TEXT; - return true; -} - void ClingoApp::initOptions(Potassco::ProgramOptions::OptionContext& root) { using namespace Potassco::ProgramOptions; BaseType::initOptions(root); - grOpts_.defines.clear(); - grOpts_.verbose = false; OptionGroup gringo("Gringo Options"); - gringo.addOptions() - ("text", storeTo(grOpts_, parseText)->flag(), "Print plain text format") - ("const,c", storeTo(grOpts_.defines, parseConst)->composing()->arg("="), "Replace term occurrences of with ") - ("output,o,@1", storeTo(grOpts_.outputFormat = Gringo::Output::OutputFormat::INTERMEDIATE, values() - ("intermediate", Gringo::Output::OutputFormat::INTERMEDIATE) - ("text", Gringo::Output::OutputFormat::TEXT) - ("reify", Gringo::Output::OutputFormat::REIFY) - ("smodels", Gringo::Output::OutputFormat::SMODELS)), "Choose output format:\n" - " intermediate: print intermediate format\n" - " text : print plain text format\n" - " reify : print program as reified facts\n" - " smodels : print smodels format\n" - " (only supports basic features)") - ("output-debug,@1", storeTo(grOpts_.outputOptions.debug = Gringo::Output::OutputDebug::NONE, values() - ("none", Gringo::Output::OutputDebug::NONE) - ("text", Gringo::Output::OutputDebug::TEXT) - ("translate", Gringo::Output::OutputDebug::TRANSLATE) - ("all", Gringo::Output::OutputDebug::ALL)), "Print debug information during output:\n" - " none : no additional info\n" - " text : print rules as plain text (prefix %%)\n" - " translate: print translated rules as plain text (prefix %%%%)\n" - " all : combines text and translate") - ("warn,W,@1" , storeTo(grOpts_, parseWarning)->arg("")->composing(), "Enable/disable warnings:\n" - " none : disable all warnings\n" - " all : enable all warnings\n" - " [no-]atom-undefined : a :- b.\n" - " [no-]file-included : #include \"a.lp\". #include \"a.lp\".\n" - " [no-]operation-undefined: p(1/0).\n" - " [no-]global-variable : :- #count { X } = 1, X = 1.\n" - " [no-]other : clasp related and uncategorized warnings") - ("rewrite-minimize,@1" , flag(grOpts_.rewriteMinimize = false), "Rewrite minimize constraints into rules") - // for backward compatibility - ("keep-facts,@3" , flag(grOpts_.keepFacts = false), "Do not remove facts from normal rules") - ("preserve-facts,@1" , storeTo(grOpts_, parsePreserveFacts), - "Preserve facts in output:\n" - " none : do not preserve\n" - " body : do not preserve\n" - " symtab: do not preserve\n" - " all : preserve all facts") - ("reify-sccs,@1" , flag(grOpts_.outputOptions.reifySCCs = false), "Calculate SCCs for reified output") - ("reify-steps,@1" , flag(grOpts_.outputOptions.reifySteps = false), "Add step numbers to reified output") - ("show-preds,@1" , storeTo(grOpts_.sigvec, parseSigVec), "Show the given signatures") - ("single-shot,@2" , flag(grOpts_.singleShot = false), "Force single-shot solving mode") - ; + registerOptions(gringo, grOpts_, GringoOptions::AppType::Clingo); root.add(gringo); - OptionGroup basic("Basic Options"); basic.addOptions() ("mode", storeTo(mode_ = mode_clingo, values() diff --git a/libclingo/src/clingocontrol.cc b/libclingo/src/clingocontrol.cc index 43a6d6e5c..31ef50b4f 100644 --- a/libclingo/src/clingocontrol.cc +++ b/libclingo/src/clingocontrol.cc @@ -899,51 +899,10 @@ ClingoLib::ClingoLib(Scripts &scripts, int argc, char const * const *argv, Logge parse({}, grOpts_, lp, false); } - -static bool parseConst(const std::string& str, std::vector& out) { - out.push_back(str); - return true; -} - void ClingoLib::initOptions(Potassco::ProgramOptions::OptionContext& root) { using namespace Potassco::ProgramOptions; - grOpts_.defines.clear(); - grOpts_.verbose = false; OptionGroup gringo("Gringo Options"); - gringo.addOptions() - ("verbose,V" , flag(grOpts_.verbose = false), "Enable verbose output") - ("const,c" , storeTo(grOpts_.defines, parseConst)->composing()->arg("="), "Replace term occurrences of with ") - ("output-debug" , storeTo(grOpts_.outputOptions.debug = Output::OutputDebug::NONE, values() - ("none", Output::OutputDebug::NONE) - ("text", Output::OutputDebug::TEXT) - ("translate", Output::OutputDebug::TRANSLATE) - ("all", Output::OutputDebug::ALL)), - "Print debug information during output:\n" - " none : no additional info\n" - " text : print rules as plain text (prefix %%)\n" - " translate: print translated rules as plain text (prefix %%%%)\n" - " all : combines text and translate") - ("warn,W" , storeTo(grOpts_, parseWarning)->arg("")->composing(), - "Enable/disable warnings:\n" - " none : disable all warnings\n" - " all : enable all warnings\n" - " [no-]atom-undefined : a :- b.\n" - " [no-]file-included : #include \"a.lp\". #include \"a.lp\".\n" - " [no-]operation-undefined: p(1/0).\n" - " [no-]global-variable : :- #count { X } = 1, X = 1.\n" - " [no-]other : clasp related and uncategorized warnings") - ("rewrite-minimize" , flag(grOpts_.rewriteMinimize = false), "Rewrite minimize constraints into rules") - // for backward compatibility - ("keep-facts" , flag(grOpts_.keepFacts = false), "Preserve facts in rule bodies") - ("preserve-facts" , storeTo(grOpts_, parsePreserveFacts), - "Preserve facts in output:\n" - " none : do not preserve\n" - " body : do not preserve\n" - " symtab: do not preserve\n" - " all : preserve all facts") - ("single-shot" , flag(grOpts_.singleShot = false), "Force single-shot solving mode") - ("show-preds" , storeTo(grOpts_.sigvec, parseSigVec), "Show the given signatures") - ; + registerOptions(gringo, grOpts_, GringoOptions::AppType::Lib); root.add(gringo); claspConfig_.addOptions(root); } diff --git a/libclingo/src/gringo_app.cc b/libclingo/src/gringo_app.cc index 74eea9eb9..c4a768af8 100644 --- a/libclingo/src/gringo_app.cc +++ b/libclingo/src/gringo_app.cc @@ -23,6 +23,7 @@ // }}} #include "clingo.h" +#include #include #include #include @@ -31,8 +32,6 @@ #include #include #include -#include -#include #include #include #include @@ -43,53 +42,9 @@ namespace Gringo { -using StrVec = std::vector; - -struct GringoOptions { - using SigVec = std::vector; - StrVec defines; - Output::OutputOptions outputOptions; - Output::OutputFormat outputFormat = Output::OutputFormat::INTERMEDIATE; - bool verbose = false; - bool wNoOperationUndefined = false; - bool wNoAtomUndef = false; - bool wNoFileIncluded = false; - bool wNoGlobalVariable = false; - bool wNoOther = false; - bool rewriteMinimize = false; - bool keepFacts = false; - bool singleShot = false; - SigVec sigvec; -}; - -static inline std::vector split(std::string const &source, char const *delimiter = " ", bool keepEmpty = false) { - std::vector results; - size_t prev = 0; - size_t next = 0; - while ((next = source.find_first_of(delimiter, prev)) != std::string::npos) { - if (keepEmpty || (next - prev != 0)) { results.push_back(source.substr(prev, next - prev)); } - prev = next + 1; - } - if (prev < source.size()) { results.push_back(source.substr(prev)); } - return results; -} - -static inline bool parseSigVec(const std::string& str, GringoOptions::SigVec& sigvec) { - for (auto &x : split(str, ",")) { - auto y = split(x, "/"); - if (y.size() != 2) { return false; } - unsigned a; - if (!Potassco::string_cast(y[1], a)) { return false; } - bool sign = !y[0].empty() && y[0][0] == '-'; - if (sign) { y[0] = y[0].substr(1); } - sigvec.emplace_back(y[0].c_str(), a, sign); - } - return true; -} - #define LOG if (opts.verbose) std::cerr struct IncrementalControl : Control, private Output::ASPIFOutBackend { - IncrementalControl(Output::OutputBase &out, StrVec const &files, GringoOptions const &opts) + IncrementalControl(Output::OutputBase &out, std::vector const &files, GringoOptions const &opts) : out(out) , scripts(g_scripts()) , pb(scripts, prg, out.outPreds, defs, opts.rewriteMinimize) @@ -246,7 +201,7 @@ struct IncrementalControl : Control, private Output::ASPIFOutBackend { void cleanup() override { } void enableCleanup(bool) override { } bool enableCleanup() const override { return false; } - virtual ~IncrementalControl() { } + ~IncrementalControl() override { } Output::DomainData const &theory() const override { return out.data; } bool beginAddBackend() override { update(); @@ -312,102 +267,15 @@ struct IncrementalControl : Control, private Output::ASPIFOutBackend { }; #undef LOG -static bool parseConst(const std::string& str, std::vector& out) { - out.push_back(str); - return true; -} - -inline void enableAll(GringoOptions& out, bool enable) { - out.wNoAtomUndef = !enable; - out.wNoFileIncluded = !enable; - out.wNoOperationUndefined = !enable; - out.wNoGlobalVariable = !enable; - out.wNoOther = !enable; -} - -inline bool parseWarning(const std::string& str, GringoOptions& out) { - if (str == "none") { enableAll(out, false); return true; } - if (str == "all") { enableAll(out, true); return true; } - if (str == "no-atom-undefined") { out.wNoAtomUndef = true; return true; } - if (str == "atom-undefined") { out.wNoAtomUndef = false; return true; } - if (str == "no-file-included") { out.wNoFileIncluded = true; return true; } - if (str == "file-included") { out.wNoFileIncluded = false; return true; } - if (str == "no-operation-undefined") { out.wNoOperationUndefined = true; return true; } - if (str == "operation-undefined") { out.wNoOperationUndefined = false; return true; } - if (str == "no-global-variable") { out.wNoGlobalVariable = true; return true; } - if (str == "global-variable") { out.wNoGlobalVariable = false; return true; } - if (str == "no-other") { out.wNoOther = true; return true; } - if (str == "other") { out.wNoOther = false; return true; } - return false; -} - -inline bool parsePreserveFacts(const std::string& str, GringoOptions& out) { - if (str == "none") { out.keepFacts = false; out.outputOptions.preserveFacts = false; return true; } - if (str == "body") { out.keepFacts = true; out.outputOptions.preserveFacts = false; return true; } - if (str == "symtab") { out.keepFacts = false; out.outputOptions.preserveFacts = true; return true; } - if (str == "all") { out.keepFacts = true; out.outputOptions.preserveFacts = true; return true; } - return false; -} - -static bool parseText(const std::string&, GringoOptions& out) { - out.outputFormat = Output::OutputFormat::TEXT; - return true; -} - struct GringoApp : public Potassco::Application { using StringSeq = std::vector; - virtual const char* getName() const { return "gringo"; } - virtual const char* getVersion() const { return clingo_version_string(); } - virtual HelpOpt getHelpOption() const { return HelpOpt("Print (flag(), "Print plain text format") - ("const,c", storeTo(grOpts_.defines, parseConst)->composing()->arg("="), "Replace term occurrences of with ") - ("output,o,@1", storeTo(grOpts_.outputFormat = Output::OutputFormat::INTERMEDIATE, values() - ("intermediate", Output::OutputFormat::INTERMEDIATE) - ("text", Output::OutputFormat::TEXT) - ("reify", Output::OutputFormat::REIFY) - ("smodels", Output::OutputFormat::SMODELS)), "Choose output format:\n" - " intermediate: print intermediate format\n" - " text : print plain text format\n" - " reify : print program as reified facts\n" - " smodels : print smodels format\n" - " (only supports basic features)") - ("output-debug,@1", storeTo(grOpts_.outputOptions.debug = Output::OutputDebug::NONE, values() - ("none", Output::OutputDebug::NONE) - ("text", Output::OutputDebug::TEXT) - ("translate", Output::OutputDebug::TRANSLATE) - ("all", Output::OutputDebug::ALL)), "Print debug information during output:\n" - " none : no additional info\n" - " text : print rules as plain text (prefix %%)\n" - " translate: print translated rules as plain text (prefix %%%%)\n" - " all : combines text and translate") - ("warn,W,@1", storeTo(grOpts_, parseWarning)->arg("")->composing(), "Enable/disable warnings:\n" - " none : disable all warnings\n" - " all : enable all warnings\n" - " [no-]atom-undefined : a :- b.\n" - " [no-]file-included : #include \"a.lp\". #include \"a.lp\".\n" - " [no-]operation-undefined: p(1/0).\n" - " [no-]global-variable : :- #count { X } = 1, X = 1.\n" - " [no-]other : uncategorized warnings") - ("rewrite-minimize,@1", flag(grOpts_.rewriteMinimize = false), "Rewrite minimize constraints into rules") - // for backward compatibility - ("keep-facts,@4", flag(grOpts_.keepFacts = false), "Preserve facts in rule bodies.") - ("preserve-facts,@1", storeTo(grOpts_, parsePreserveFacts), - "Preserve facts in output:\n" - " none : do not preserve\n" - " body : do not preserve\n" - " symtab: do not preserve\n" - " all : preserve all facts") - ("reify-sccs,@1", flag(grOpts_.outputOptions.reifySCCs = false), "Calculate SCCs for reified output") - ("reify-steps,@1", flag(grOpts_.outputOptions.reifySteps = false), "Add step numbers to reified output") - ("show-preds,@1", storeTo(grOpts_.sigvec, parseSigVec), "Show the given signatures") - ("single-shot,@2", flag(grOpts_.singleShot = false), "Force single-shot grounding mode") - ; + registerOptions(gringo, grOpts_, GringoOptions::AppType::Gringo); root.add(gringo); OptionGroup basic("Basic Options"); basic.addOptions() @@ -415,15 +283,15 @@ struct GringoApp : public Potassco::Application { ; root.add(basic); } - virtual void validateOptions(const Potassco::ProgramOptions::OptionContext&, const Potassco::ProgramOptions::ParsedOptions&, const Potassco::ProgramOptions::ParsedValues&) { } - virtual void setup() { } + void validateOptions(const Potassco::ProgramOptions::OptionContext&, const Potassco::ProgramOptions::ParsedOptions&, const Potassco::ProgramOptions::ParsedValues&) override { } + void setup() override { } static bool parsePositional(std::string const &, std::string& out) { out = "file"; return true; } - virtual Potassco::ProgramOptions::PosOption getPositional() const { return parsePositional; } + Potassco::ProgramOptions::PosOption getPositional() const override { return parsePositional; } - virtual void printHelp(const Potassco::ProgramOptions::OptionContext& root) { + void printHelp(const Potassco::ProgramOptions::OptionContext& root) override { printf("%s version %s\n", getName(), getVersion()); printUsage(); Potassco::ProgramOptions::FileOut out(stdout); @@ -433,7 +301,7 @@ struct GringoApp : public Potassco::Application { printUsage(); } - virtual void printVersion() { + void printVersion() override { char const *py_version = clingo_script_version("python"); char const *lua_version = clingo_script_version("lua"); Potassco::Application::printVersion(); @@ -466,7 +334,7 @@ struct GringoApp : public Potassco::Application { } } - virtual void run() { + void run() override { try { using namespace Gringo; grOpts_.verbose = verbose() == UINT_MAX; diff --git a/libclingo/src/gringo_options.cc b/libclingo/src/gringo_options.cc new file mode 100644 index 000000000..bbc2037df --- /dev/null +++ b/libclingo/src/gringo_options.cc @@ -0,0 +1,165 @@ +// {{{ MIT License + +// Copyright 2024 + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +// }}} +#include + +#include +#include + +namespace Gringo { + +static std::vector split(std::string const &source, char const *delimiter = " ") { + std::vector results; + size_t prev = 0; + size_t next = 0; + while ((next = source.find_first_of(delimiter, prev)) != std::string::npos) { + if (next - prev != 0) { results.push_back(source.substr(prev, next - prev)); } + prev = next + 1; + } + if (prev < source.size()) { results.push_back(source.substr(prev)); } + return results; +} + +static bool parseSigVec(const std::string& str, GringoOptions::SigVec& sigvec) { + for (auto &x : split(str, ",")) { + auto y = split(x, "/"); + if (y.size() != 2) { return false; } + unsigned a; + if (!Potassco::string_cast(y[1], a)) { return false; } + bool sign = !y[0].empty() && y[0][0] == '-'; + if (sign) { y[0] = y[0].substr(1); } + sigvec.emplace_back(y[0].c_str(), a, sign); + } + return true; +} + +static void enableAll(GringoOptions& out, bool enable) { + out.wNoAtomUndef = !enable; + out.wNoFileIncluded = !enable; + out.wNoOperationUndefined = !enable; + out.wNoGlobalVariable = !enable; + out.wNoOther = !enable; +} + +static bool parseWarning(const std::string& str, GringoOptions& out) { + if (str == "none") { enableAll(out, false); return true; } + if (str == "all") { enableAll(out, true); return true; } + if (str == "no-atom-undefined") { out.wNoAtomUndef = true; return true; } + if (str == "atom-undefined") { out.wNoAtomUndef = false; return true; } + if (str == "no-file-included") { out.wNoFileIncluded = true; return true; } + if (str == "file-included") { out.wNoFileIncluded = false; return true; } + if (str == "no-operation-undefined") { out.wNoOperationUndefined = true; return true; } + if (str == "operation-undefined") { out.wNoOperationUndefined = false; return true; } + if (str == "no-global-variable") { out.wNoGlobalVariable = true; return true; } + if (str == "global-variable") { out.wNoGlobalVariable = false; return true; } + if (str == "no-other") { out.wNoOther = true; return true; } + if (str == "other") { out.wNoOther = false; return true; } + return false; +} + +static bool parsePreserveFacts(const std::string& str, GringoOptions& out) { + if (str == "none") { out.keepFacts = false; out.outputOptions.preserveFacts = false; return true; } + if (str == "body") { out.keepFacts = true; out.outputOptions.preserveFacts = false; return true; } + if (str == "symtab") { out.keepFacts = false; out.outputOptions.preserveFacts = true; return true; } + if (str == "all") { out.keepFacts = true; out.outputOptions.preserveFacts = true; return true; } + return false; +} + +static bool parseText(const std::string&, GringoOptions& out) { + out.outputFormat = Output::OutputFormat::TEXT; + return true; +} + +void registerOptions(Potassco::ProgramOptions::OptionGroup& group, GringoOptions& opts, GringoOptions::AppType type) { + using namespace Potassco::ProgramOptions; + auto level = [&](int i) { + return type != GringoOptions::AppType::Lib ? DescriptionLevel(i) : DescriptionLevel::desc_level_default; + }; + auto name = [](const char* n, char a = 0) { + return std::pair(n, a); + }; + auto push = [&](std::pair n, Value* v, const char* desc, DescriptionLevel l = DescriptionLevel::desc_level_default) { + group.addOption(SharedOptPtr(new Option(n.first, n.second, desc, v->level(l)))); + }; + opts.defines.clear(); + opts.verbose = false; + if (type != GringoOptions::AppType::Lib) { + auto alias = char(type == GringoOptions::AppType::Gringo ? 't' : 0); + push(name("text", alias), storeTo(opts, parseText)->flag(), "Print plain text format"); + } + else { + push(name("verbose", 'V'), flag(opts.verbose = false), "Enable verbose output"); + } + push(name("const", 'c'), storeTo(opts.defines, +[](const std::string& str, std::vector& out) { + out.push_back(str); + return true; + })->composing()->arg("="),"Replace term occurrences of with "); + if (type != GringoOptions::AppType::Lib) { + push(name("output", 'o'), storeTo(opts.outputFormat = Gringo::Output::OutputFormat::INTERMEDIATE, values() + ("intermediate", Gringo::Output::OutputFormat::INTERMEDIATE) + ("text", Gringo::Output::OutputFormat::TEXT) + ("reify", Gringo::Output::OutputFormat::REIFY) + ("smodels", Gringo::Output::OutputFormat::SMODELS)), + "Choose output format:\n" + " intermediate: print intermediate format\n" + " text : print plain text format\n" + " reify : print program as reified facts\n" + " smodels : print smodels format\n" + " (only supports basic features)", level(1)); + } + push(name("output-debug"), storeTo(opts.outputOptions.debug = Output::OutputDebug::NONE, values() + ("none", Output::OutputDebug::NONE) + ("text", Output::OutputDebug::TEXT) + ("translate", Output::OutputDebug::TRANSLATE) + ("all", Output::OutputDebug::ALL)), + "Print debug information during output:\n" + " none : no additional info\n" + " text : print rules as plain text (prefix %%)\n" + " translate: print translated rules as plain text (prefix %%%%)\n" + " all : combines text and translate", level(1)); + push(name("warn", 'W'), storeTo(opts, parseWarning)->arg("")->composing(), + "Enable/disable warnings:\n" + " none : disable all warnings\n" + " all : enable all warnings\n" + " [no-]atom-undefined : a :- b.\n" + " [no-]file-included : #include \"a.lp\". #include \"a.lp\".\n" + " [no-]operation-undefined: p(1/0).\n" + " [no-]global-variable : :- #count { X } = 1, X = 1.\n" + " [no-]other : uncategorized warnings", level(1)); + push(name("rewrite-minimize"), flag(opts.rewriteMinimize = false), "Rewrite minimize constraints into rules", level(1)); + // for backward compatibility + push(name("keep-facts"), flag(opts.keepFacts = false), "Preserve facts in rule bodies.", level(5)); + push(name("preserve-facts"), storeTo(opts, parsePreserveFacts), + "Preserve facts in output:\n" + " none : do not preserve\n" + " body : do not preserve\n" + " symtab: do not preserve\n" + " all : preserve all facts", level(1)); + if (type != GringoOptions::AppType::Lib) { + push(name("reify-sccs"), flag(opts.outputOptions.reifySCCs = false), "Calculate SCCs for reified output", level(1)); + push(name("reify-steps"), flag(opts.outputOptions.reifySteps = false), "Add step numbers to reified output", level(1)); + } + push(name("show-preds"), storeTo(opts.sigvec, parseSigVec), "Show the given signatures", level(1)); + push(name("single-shot"), flag(opts.singleShot = false), "Force single-shot solving mode", level(2)); +} +} // namespace Gringo