Clingo
Loading...
Searching...
No Matches
parse.hh
1#pragma once
2
3#include <clingo/input/parser.hh>
4#include <clingo/input/print.hh>
5#include <clingo/input/program.hh>
6
7#include <clingo/ground/script.hh>
8
9#include <clingo/util/enum.hh>
10#include <clingo/util/type_traits.hh>
11
12#include <filesystem>
13#include <fstream>
14#include <iostream>
15#include <utility>
16
17namespace CppClingo::Control {
18
21
23enum class BuiltinIncludes : uint8_t {
24 empty = 0,
25 incmode = 1
26};
29
32
34using ProgramParams = std::pair<CppClingo::Input::Precedence, std::optional<ProgramParamVec>>;
35
40 public:
42 ParseHelper(Logger &log, SymbolStore &store, std::function<void(Input::Stm)> cb, Ground::ScriptExec *exec = nullptr,
43 ProgramBackend *prg_backend = nullptr, TheoryBackend *thy_backend = nullptr)
44 : log_{&log}, store_{&store}, exec_{exec}, parser_{log, store, prg_backend, thy_backend}, cb_{std::move(cb)} {}
45
47 auto process_string(std::string_view str) -> BuiltinIncludes {
48 parser_.init(str, *store_->string("<string>"));
49 process_();
50 auto ret = process_includes();
51 check();
52 return ret;
53 }
54
56 auto process_files(std::span<std::string_view const> const &files) -> BuiltinIncludes {
57 auto ret = BuiltinIncludes::empty;
58 if (files.empty()) {
60 ret |= process_includes();
61 }
62 for (auto const &file : files) {
63 if (file == "-") {
65 } else {
66 process_path(file);
67 }
68 ret |= process_includes();
69 }
70 check();
71 return ret;
72 }
73
76 if (!processed_stdin_) {
77 processed_stdin_ = true;
78 parser_.init(std::cin, *store_->string("-"));
79 process_(root_);
80 } else {
81 CLINGO_REPORT(*log_, info_file_included) << "file already included: -";
82 }
83 }
84
89 auto process_path(std::string_view path) -> bool { return process_path_(path, true); }
90
92 [[nodiscard]] auto process_includes() -> BuiltinIncludes {
93 auto includes = BuiltinIncludes::empty;
94 for (; !includes_.empty(); includes_.pop_front()) {
95 auto const &[parent, include] = includes_.front();
96 if (include.type() == Input::IncludeType::system) {
97 auto path = std::filesystem::path(include.value().c_str());
98 if (path.is_relative() && parent != root_) {
99 if (process_path_(parent / path, false)) {
100 continue;
101 }
102 }
103 process_path_(path, true);
104 } else {
105 if (include.value().view() == "incmode") {
106 includes |= BuiltinIncludes::incmode;
107 } else {
108 parse_error_ = true;
109 CLINGO_REPORT_LOC(*log_, error, include.loc()) << "unknown include: " << include.value();
110 }
111 }
112 }
113 return includes;
114 }
115
117 void check() const {
118 if (parse_error_) {
119 throw parse_error();
120 }
121 }
122
123 private:
125 void process_() { process_(root_); }
126
131 auto process_path_(std::filesystem::path path, bool required) -> bool {
132 if (std::filesystem::exists(path)) {
133 path = std::filesystem::canonical(path);
134 auto rel = path.root_name() == root_.root_name() ? path.lexically_relative(root_) : path;
135 if (!std::filesystem::is_directory(path)) {
136 if (seen_.emplace(path).second) {
137 fin_.open(rel);
138 parser_.init(fin_, *store_->string(rel.string()));
139 process_(path.parent_path());
140 } else {
141 CLINGO_REPORT(*log_, info_file_included) << "file already included: " << rel;
142 }
143 return true;
144 }
145 if (required) {
146 CLINGO_REPORT(*log_, error) << "cannot include directory: " << rel;
147 parse_error_ = true;
148 }
149 return false;
150 }
151 if (required) {
152 CLINGO_REPORT(*log_, error) << "file not found: " << path;
153 parse_error_ = true;
154 }
155 return false;
156 }
157
158 // NOLINTBEGIN(cppcoreguidelines-missing-std-forward,bugprone-unchecked-optional-access)
160 void process_(std::filesystem::path const &dir) {
161 bool ensure_base = true;
162 while (true) {
163 auto [stm, res] = parser_.scan();
164 parse_error_ = parse_error_ || !res;
165 if (!stm) {
166 fin_.close();
167 break;
168 }
169 std::visit(
170 [&]<class T>(T const &val) {
171 if constexpr (Util::matches<T, Input::StmInclude>) {
172 // enqueue include
173 includes_.emplace_back(dir, std::move(val));
174 } else if constexpr (Util::is_among_v<T, Input::StmScript>) {
175 // execute script statements
176 if (exec_ != nullptr) {
177 exec_->exec(val.loc(), *log_, val.type().view(), val.value().view());
178 }
179 } else if constexpr (Util::matches<T, Input::StmProgram>) {
180 // disable base injection
181 ensure_base = false;
182 is_base = val.name() == "base" && val.args().empty();
183 } else if constexpr (!Util::is_among_v<T, Input::StmShowNothing, Input::StmShowSig,
184 Input::StmProjectSig, Input::StmDefined, Input::StmConst,
185 Input::StmTheory, Input::StmParts, Input::StmComment>) {
186 // inject base part before non-meta statements
187 if (!is_base && ensure_base) {
188 cb_(Input::StmProgram{location(val), store_->string_ref("base"), StringSpan{}});
189 ensure_base = false;
190 is_base = true;
191 }
192 }
193 cb_(*std::move(stm));
194 },
195 *stm);
196 }
197 }
198 // NOLINTEND(cppcoreguidelines-missing-std-forward,bugprone-unchecked-optional-access)
199
200 Logger *log_;
201 SymbolStore *store_;
202 Ground::ScriptExec *exec_;
203 std::ifstream fin_;
204 Input::Parser parser_;
205 std::function<void(Input::Stm)> cb_;
206 std::filesystem::path root_ = std::filesystem::current_path();
207 std::deque<std::pair<std::filesystem::path, Input::StmInclude>> includes_;
208 Util::unordered_set<std::filesystem::path> seen_;
209 bool processed_stdin_ = false;
210 bool parse_error_ = false;
211 bool is_base = false;
212};
213
215
216} // namespace CppClingo::Control
A helper for parsing.
Definition parse.hh:39
void check() const
Throws if there was an error during parsing.
Definition parse.hh:117
ParseHelper(Logger &log, SymbolStore &store, std::function< void(Input::Stm)> cb, Ground::ScriptExec *exec=nullptr, ProgramBackend *prg_backend=nullptr, TheoryBackend *thy_backend=nullptr)
Construct the helper.
Definition parse.hh:42
auto process_includes() -> BuiltinIncludes
Process includes encountered while parsing.
Definition parse.hh:92
void process_stdin()
Parse a program from stdin.
Definition parse.hh:75
auto process_files(std::span< std::string_view const > const &files) -> BuiltinIncludes
Parse a program from the given files.
Definition parse.hh:56
auto process_path(std::string_view path) -> bool
Parse a program from the given path.
Definition parse.hh:89
auto process_string(std::string_view str) -> BuiltinIncludes
Parse a program from the given string.
Definition parse.hh:47
Interface to execute code in source files.
Definition script.hh:12
void exec(Location const &loc, Logger &log, std::string_view name, std::string_view code)
Execute the given code for the given script.
Definition script.hh:17
auto scan() -> std::pair< std::optional< Stm >, bool >
Scan statements.
void init(std::istream &in, String file)
Initialize parser reading from the given input stream.
Simple logger to report message to stderr or via a callback.
Definition logger.hh:63
Abstract class connecting grounder and solver.
Definition backend.hh:54
A store for symbols.
Definition symbol.hh:454
auto string(std::string_view str) -> SharedString
Construct a string.
auto string_ref(std::string_view str) -> String
Construct a string.
Abstract class connecting grounder and theory data.
Definition backend.hh:213
Exception to indicate that parsing failed.
Definition logger.hh:49
std::pair< CppClingo::Input::Precedence, std::optional< ProgramParamVec > > ProgramParams
A pair capturing a program #parts directive.
Definition parse.hh:34
BuiltinIncludes
Bitset of enabled builtin includes.
Definition parse.hh:23
@ incmode
Enable the incremental mode.
auto location(T const &x) -> Location const &
Get the location of an expression.
Definition location.hh:123
#define CLINGO_REPORT(p, id)
Report messages of the given type.
Definition logger.hh:218
#define CLINGO_REPORT_LOC(p, id, loc)
Report messages of the given type and location.
Definition logger.hh:223
@ info_file_included
Info message for undefined atoms.
std::span< String const > StringSpan
A span of strings.
Definition symbol.hh:87
std::function< void(MessageCode, std::string_view)> Logger
A callback function type for logging messages.
Definition core.hh:465
std::vector< ProgramParam > ProgramParamVec
A list of program params.
Definition statement.hh:761
std::variant< StmRule, StmTheory, StmOptimize, StmWeakConstraint, StmShow, StmShowNothing, StmShowSig, StmProject, StmProjectSig, StmDefined, StmExternal, StmEdge, StmHeuristic, StmScript, StmInclude, StmProgram, StmConst, StmParts, StmComment > Stm
Variant of available statements.
Definition statement.hh:828
#define CLINGO_ENABLE_BITSET_ENUM(E,...)
Opt-in macro for enabling bit operations for a given enum type.
Definition enum.hh:18
constexpr bool is_among_v
Check if the type S is among the types in L.
Definition type_traits.hh:11