forked from souffle-lang/souffle
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProgram.h
308 lines (248 loc) · 9.63 KB
/
Program.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
/*
* Souffle - A Datalog Compiler
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved
* Licensed under the Universal Permissive License v 1.0 as shown at:
* - https://opensource.org/licenses/UPL
* - <souffle root>/licenses/SOUFFLE-UPL.txt
*/
/************************************************************************
*
* @file Program.h
*
* Defines the program class
*
***********************************************************************/
#pragma once
#include "Global.h"
#include "ast/Clause.h"
#include "ast/Component.h"
#include "ast/ComponentInit.h"
#include "ast/Directive.h"
#include "ast/FunctorDeclaration.h"
#include "ast/Node.h"
#include "ast/Pragma.h"
#include "ast/QualifiedName.h"
#include "ast/Relation.h"
#include "ast/Type.h"
#include "ast/utility/Utils.h"
#include "souffle/utility/FunctionalUtil.h"
#include "souffle/utility/Visitor.h"
#include "souffle/utility/span.h"
#include <iosfwd>
#include <vector>
namespace souffle {
class ParserDriver;
namespace ast {
class Atom;
class Program;
namespace transform {
class ComponentInstantiationTransformer;
}
} // namespace ast
// very common case optimisation: visiting every `Clause`
template <typename F, typename = detail::visitor_enable_if_arg0<F, ast::Clause>>
void visit(ast::Program&, F&&);
template <typename F, typename = detail::visitor_enable_if_arg0<F, ast::Clause>>
void visit(ast::Program const&, F&&);
} // namespace souffle
namespace souffle::ast {
/**
* @class Program
* @brief The program class consists of relations, clauses and types.
*/
class Program : public Node {
public:
// Requirements for storing top-level nodes:
// 1) remove-by-identity needs to be at least `O(lg n)`
// 2) traversal order must be stable (at least for pretty printing)
//
// This implies that top-level nodes need to be stored in a linked-set structure.
// Linked for stable traversal, and set for `O(lg n)` remove-by-identity.
//
// Furthermore, lookup of `Relation`, `Clause`, and `Directive` by name is a
// common operation.
// This is handled by storing `Relation`s, `Clause`s, and `Directive`s in a
// map keyed by the relation name. The remove-by-identity time is linear,
// but the size is much smaller, and this allows lookup by name w/o needing
// an analysis and avoids the issue of the analysis results becoming stale
// after common manipulations (e.g. `Clause` insertion).
//
// The downside is that the name must not be changed after the
// node is added to the program. This is sanchecked by assertions.
struct RelationInfo {
// A well formed program has exactly one declaration per relation.
// TODO: Reject duplicate relation declarations in `SemanticChecker` instead of in the parser.
VecOwn<Relation> decls;
VecOwn<Clause> clauses;
VecOwn<Directive> directives;
};
using RelationInfoMap = std::map<QualifiedName, RelationInfo>;
RelationInfoMap& getRelationInfo() {
return relations;
}
RelationInfoMap const& getRelationInfo() const {
return relations;
}
RelationInfo* getRelationInfo(QualifiedName const& name) {
auto it = relations.find(name);
return it == relations.end() ? nullptr : &it->second;
}
RelationInfo const* getRelationInfo(QualifiedName const& name) const {
auto it = relations.find(name);
return it == relations.end() ? nullptr : &it->second;
}
/** Return types */
std::vector<Type*> getTypes() const;
/** Return relations */
std::vector<Relation*> getRelations() const;
/** Returns the first `Relation` declartion for a given name, if any */
Relation* getRelation(QualifiedName const&) const;
Relation* getRelation(Atom const&) const;
Relation* getRelation(Clause const&) const;
Relation* getRelation(Directive const&) const;
/**
* Returns all `Relation` declartions for a given name.
* If the program contains multiple declarations for a given name then it is malformed
* and it is reasonable to only consider the first declations.
*/
std::vector<Relation*> getRelationAll(QualifiedName const&) const;
/** Return clauses */
std::vector<Clause*> getClauses() const;
/** Return clauses for a given relation */
std::vector<Clause*> getClauses(QualifiedName const&) const;
/** Return clauses for a given relation */
auto getClauses(Relation const& r) const {
return getClauses(r.getQualifiedName());
}
/** Return functor declarations */
std::vector<FunctorDeclaration*> getFunctorDeclarations() const;
/** Return relation directives */
std::vector<Directive*> getDirectives() const;
/** Return relation directives for a relation */
std::vector<Directive*> getDirectives(QualifiedName const&) const;
/** Return relation directives for a relation */
auto getDirectives(Relation const& r) const {
return getDirectives(r.getQualifiedName());
}
/** Add relation directive */
void addDirective(Own<Directive> directive);
/** Return pragma directives */
const VecOwn<Pragma>& getPragmaDirectives() const {
return pragmas;
}
/* Add relation */
void addRelation(Own<Relation> relation);
/**
* Remove a relation entirely, including the declaration(s), clauses, and directives.
* @return true IFF the relation was found and removed
*/
bool removeRelation(QualifiedName const&);
/**
* Remove a relation by identity. The relation must be owned by the program.
* It is not expected that there are useful cases where some are not owned, and it is often
* symptomatic of a bug to try to remove a clause that isn't part of the program.
*/
void removeRelation(Relation const&);
/** Add a clause */
void addClause(Own<Clause> clause);
// Common case helper.
void addClauses(VecOwn<Clause> clauses);
/** Add a type declaration */
void addType(Own<Type> type);
/**
* Remove a clause by identity. The clause must be owned by the program.
* It is not expected that there are useful cases where some are not owned, and it is often
* symptomatic of a bug to try to remove a clause that isn't part of the program.
*/
void removeClause(const Clause&);
/**
* Remove multiple clauses by identity. All of these clauses must be owned by the program.
* It is not expected that there are useful cases where some are not owned, and it is often
* symptomatic of a bug to try to remove a clause that isn't part of the program.
*/
void removeClauses(span<Clause const* const>);
/**
* Remove a directive by identity.
* @return true IFF the directive was found and removed
*/
void removeDirective(const Directive&);
/** Return components */
std::vector<Component*> getComponents() const;
/** Return component instantiation */
std::vector<ComponentInit*> getComponentInstantiations() const;
/** Remove components and components' instantiations */
void clearComponents();
void apply(const NodeMapper& map) override;
protected:
void print(std::ostream& os) const override;
NodeVec getChildren() const override;
friend class souffle::ParserDriver;
void addPragma(Own<Pragma> pragma);
void addFunctorDeclaration(Own<FunctorDeclaration> functor);
/** Add component */
void addComponent(Own<Component> component);
/** Add component instantiation */
void addInstantiation(Own<ComponentInit> instantiation);
private:
bool equal(const Node& node) const override;
Program* cloning() const override;
private:
/** Program types */
VecOwn<Type> types;
/** Program relation declartions, clauses, and directives */
RelationInfoMap relations;
/** External Functors */
VecOwn<FunctorDeclaration> functors;
/** Component definitions */
VecOwn<Component> components;
/** Component instantiations */
VecOwn<ComponentInit> instantiations;
/** Pragmas */
VecOwn<Pragma> pragmas;
#ifndef NDEBUG
// SANCHECK - used to assert that the set of clauses isn't mutated mid visit
// (easy extra check b/c `visit` is specialised for `Program` and `Clause`s)
mutable uint32_t clause_visit_in_progress = 0;
#endif
template <typename F, typename>
friend void souffle::visit(Program&, F&&);
template <typename F, typename>
friend void souffle::visit(Program const&, F&&);
};
} // namespace souffle::ast
namespace souffle {
template <typename F, typename>
void visit(ast::Program& program, F&& go) {
#ifndef NDEBUG
program.clause_visit_in_progress++;
#endif
for ([[maybe_unused]] auto&& [k, info] : program.relations)
for (auto&& cl : info.clauses) {
assert(k == ast::getName(*cl));
go(*cl);
// post-condition verify isn't robust; other `visit` calls could inadvertently modify head name
// e.g. `visit(program, [](Atom&) {})`
assert(k == ast::getName(*cl));
}
#ifndef NDEBUG
program.clause_visit_in_progress--;
#endif
}
template <typename F, typename>
void visit(ast::Program const& program, F&& go) {
#ifndef NDEBUG
program.clause_visit_in_progress++;
#endif
for ([[maybe_unused]] auto&& [k, info] : program.relations)
for (auto&& cl : info.clauses) {
assert(k == ast::getName(*cl));
go(static_cast<ast::Clause const&>(*cl));
// post-condition verify isn't robust; other `visit` calls could inadvertently modify head name
// e.g. `visit(program, [](Atom&) {})`
assert(k == ast::getName(*cl));
}
#ifndef NDEBUG
program.clause_visit_in_progress--;
#endif
}
} // namespace souffle