souffle  2.0.2-371-g6315b36
ComponentInstantiation.cpp
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved
4  * Licensed under the Universal Permissive License v 1.0 as shown at:
5  * - https://opensource.org/licenses/UPL
6  * - <souffle root>/licenses/SOUFFLE-UPL.txt
7  */
8 
9 /************************************************************************
10  *
11  * @file ComponentInstantiation.cpp
12  *
13  * Instantiate Components
14  *
15  ***********************************************************************/
16 
18 #include "ast/Atom.h"
19 #include "ast/Attribute.h"
20 #include "ast/Clause.h"
21 #include "ast/Component.h"
22 #include "ast/ComponentInit.h"
23 #include "ast/ComponentType.h"
24 #include "ast/Directive.h"
25 #include "ast/Node.h"
26 #include "ast/Program.h"
27 #include "ast/QualifiedName.h"
28 #include "ast/RecordType.h"
29 #include "ast/Relation.h"
30 #include "ast/TranslationUnit.h"
31 #include "ast/Type.h"
32 #include "ast/TypeCast.h"
33 #include "ast/UnionType.h"
35 #include "ast/utility/Visitor.h"
36 #include "reports/ErrorReport.h"
38 #include <algorithm>
39 #include <cstddef>
40 #include <map>
41 #include <memory>
42 #include <set>
43 #include <utility>
44 #include <vector>
45 
46 namespace souffle::ast::transform {
47 
48 using namespace analysis;
49 
50 namespace {
51 
52 static const unsigned int MAX_INSTANTIATION_DEPTH = 1000;
53 
54 /**
55  * A container type for the (instantiated) content of a component.
56  */
57 struct ComponentContent {
58  std::vector<Own<ast::Type>> types;
59  std::vector<Own<Relation>> relations;
60  std::vector<Own<Directive>> directives;
61  std::vector<Own<Clause>> clauses;
62 
63  void add(Own<ast::Type>& type, ErrorReport& report) {
64  // add to result content (check existence first)
65  auto foundItem = std::find_if(types.begin(), types.end(), [&](const Own<ast::Type>& element) {
66  return (element->getQualifiedName() == type->getQualifiedName());
67  });
68  if (foundItem != types.end()) {
69  Diagnostic err(Diagnostic::Type::ERROR,
70  DiagnosticMessage(
71  "Redefinition of type " + toString(type->getQualifiedName()), type->getSrcLoc()),
72  {DiagnosticMessage("Previous definition", (*foundItem)->getSrcLoc())});
73  report.addDiagnostic(err);
74  }
75  types.push_back(std::move(type));
76  }
77 
78  void add(Own<Relation>& rel, ErrorReport& report) {
79  // add to result content (check existence first)
80  auto foundItem = std::find_if(relations.begin(), relations.end(), [&](const Own<Relation>& element) {
81  return (element->getQualifiedName() == rel->getQualifiedName());
82  });
83  if (foundItem != relations.end()) {
84  Diagnostic err(Diagnostic::Type::ERROR,
85  DiagnosticMessage("Redefinition of relation " + toString(rel->getQualifiedName()),
86  rel->getSrcLoc()),
87  {DiagnosticMessage("Previous definition", (*foundItem)->getSrcLoc())});
88  report.addDiagnostic(err);
89  }
90  relations.push_back(std::move(rel));
91  }
92 
93  void add(Own<Clause>& clause, ErrorReport& /* report */) {
94  clauses.push_back(std::move(clause));
95  }
96 
97  void add(Own<Directive>& newDirective, ErrorReport& report) {
98  // Check if directive already exists
99  auto foundItem =
100  std::find_if(directives.begin(), directives.end(), [&](const Own<Directive>& directive) {
101  return directive->getQualifiedName() == newDirective->getQualifiedName();
102  });
103  // if yes, add error
104  if (foundItem != directives.end()) {
105  auto type = (*foundItem)->getType();
106  if (type == newDirective->getType() && newDirective->getType() != ast::DirectiveType::output) {
107  Diagnostic err(Diagnostic::Type::ERROR,
108  DiagnosticMessage(
109  "Redefinition I/O operation " + toString(newDirective->getQualifiedName()),
110  newDirective->getSrcLoc()),
111  {DiagnosticMessage("Previous definition", (*foundItem)->getSrcLoc())});
112  report.addDiagnostic(err);
113  }
114  }
115  // if not, add it
116  directives.push_back(std::move(newDirective));
117  }
118 };
119 
120 /**
121  * Recursively computes the set of relations (and included clauses) introduced
122  * by this init statement enclosed within the given scope.
123  */
124 ComponentContent getInstantiatedContent(Program& program, const ComponentInit& componentInit,
125  const Component* enclosingComponent, const ComponentLookupAnalysis& componentLookup,
126  std::vector<Own<Clause>>& orphans, ErrorReport& report,
127  const TypeBinding& binding = analysis::TypeBinding(),
128  unsigned int maxDepth = MAX_INSTANTIATION_DEPTH);
129 
130 /**
131  * Collects clones of all the content in the given component and its base components.
132  */
133 void collectContent(Program& program, const Component& component, const TypeBinding& binding,
134  const Component* enclosingComponent, const ComponentLookupAnalysis& componentLookup,
135  ComponentContent& res, std::vector<Own<Clause>>& orphans, const std::set<std::string>& overridden,
136  ErrorReport& report, unsigned int maxInstantiationDepth) {
137  // start with relations and clauses of the base components
138  for (const auto& base : component.getBaseComponents()) {
139  const Component* comp = componentLookup.getComponent(enclosingComponent, base->getName(), binding);
140  if (comp != nullptr) {
141  // link formal with actual type parameters
142  const auto& formalParams = comp->getComponentType()->getTypeParameters();
143  const auto& actualParams = base->getTypeParameters();
144 
145  // update type binding
146  TypeBinding activeBinding = binding.extend(formalParams, actualParams);
147 
148  for (const auto& cur : comp->getInstantiations()) {
149  // instantiate sub-component
150  ComponentContent content = getInstantiatedContent(program, *cur, enclosingComponent,
151  componentLookup, orphans, report, activeBinding, maxInstantiationDepth - 1);
152 
153  // process types
154  for (auto& type : content.types) {
155  res.add(type, report);
156  }
157 
158  // process relations
159  for (auto& rel : content.relations) {
160  res.add(rel, report);
161  }
162 
163  // process clauses
164  for (auto& clause : content.clauses) {
165  res.add(clause, report);
166  }
167 
168  // process directive directives
169  for (auto& directive : content.directives) {
170  res.add(directive, report);
171  }
172  }
173 
174  // collect definitions from base type
175  std::set<std::string> superOverridden;
176  superOverridden.insert(overridden.begin(), overridden.end());
177  superOverridden.insert(component.getOverridden().begin(), component.getOverridden().end());
178  collectContent(program, *comp, activeBinding, comp, componentLookup, res, orphans,
179  superOverridden, report, maxInstantiationDepth);
180  }
181  }
182 
183  // and continue with the local types
184  for (const auto& cur : component.getTypes()) {
185  // create a clone
186  Own<ast::Type> type(cur->clone());
187 
188  // instantiate elements of union types
189  visitDepthFirst(*type, [&](const ast::UnionType& type) {
190  for (const auto& name : type.getTypes()) {
191  QualifiedName newName = binding.find(name);
192  if (!newName.empty()) {
193  const_cast<QualifiedName&>(name) = newName;
194  }
195  }
196  });
197 
198  // instantiate elements of record types
199  visitDepthFirst(*type, [&](const ast::RecordType& type) {
200  for (const auto& field : type.getFields()) {
201  auto&& newName = binding.find(field->getTypeName());
202  if (!newName.empty()) {
203  const_cast<Attribute&>(*field).setTypeName(newName);
204  }
205  }
206  });
207 
208  // add to result list (check existence first)
209  res.add(type, report);
210  }
211 
212  // and the local relations
213  for (const auto& cur : component.getRelations()) {
214  // create a clone
215  Own<Relation> rel(cur->clone());
216 
217  // update attribute types
218  for (Attribute* attr : rel->getAttributes()) {
219  QualifiedName forward = binding.find(attr->getTypeName());
220  if (!forward.empty()) {
221  attr->setTypeName(forward);
222  }
223  }
224 
225  // add to result list (check existence first)
226  res.add(rel, report);
227  }
228 
229  // and the local directive directives
230  for (const auto& directive : component.getDirectives()) {
231  // create a clone
232  Own<Directive> instantiatedIO(directive->clone());
233 
234  res.add(instantiatedIO, report);
235  }
236 
237  // index the available relations
238  std::map<QualifiedName, Relation*> index;
239  for (const auto& cur : res.relations) {
240  index[cur->getQualifiedName()] = cur.get();
241  }
242 
243  // add the local clauses
244  // TODO: check orphans
245  for (const auto& cur : component.getClauses()) {
246  if (overridden.count(cur->getHead()->getQualifiedName().getQualifiers()[0]) == 0) {
247  Relation* rel = index[cur->getHead()->getQualifiedName()];
248  if (rel != nullptr) {
249  Own<Clause> instantiatedClause(cur->clone());
250  res.add(instantiatedClause, report);
251  } else {
252  orphans.emplace_back(cur->clone());
253  }
254  }
255  }
256 
257  // add orphan clauses at the current level if they can be resolved
258  for (auto iter = orphans.begin(); iter != orphans.end();) {
259  auto& cur = *iter;
260  Relation* rel = index[cur->getHead()->getQualifiedName()];
261  if (rel != nullptr) {
262  // add orphan to current instance and delete from orphan list
263  Own<Clause> instantiatedClause(cur->clone());
264  res.add(instantiatedClause, report);
265  iter = orphans.erase(iter);
266  } else {
267  ++iter;
268  }
269  }
270 }
271 
272 ComponentContent getInstantiatedContent(Program& program, const ComponentInit& componentInit,
273  const Component* enclosingComponent, const ComponentLookupAnalysis& componentLookup,
274  std::vector<Own<Clause>>& orphans, ErrorReport& report, const TypeBinding& binding,
275  unsigned int maxDepth) {
276  // start with an empty list
277  ComponentContent res;
278 
279  if (maxDepth == 0) {
280  report.addError("Component instantiation limit reached", componentInit.getSrcLoc());
281  return res;
282  }
283 
284  // get referenced component
285  const Component* component = componentLookup.getComponent(
286  enclosingComponent, componentInit.getComponentType()->getName(), binding);
287  if (component == nullptr) {
288  // this component is not defined => will trigger a semantic error
289  return res;
290  }
291 
292  // update type biding
293  const auto& formalParams = component->getComponentType()->getTypeParameters();
294  const auto& actualParams = componentInit.getComponentType()->getTypeParameters();
295  TypeBinding activeBinding = binding.extend(formalParams, actualParams);
296 
297  // instantiated nested components
298  for (const auto& cur : component->getInstantiations()) {
299  // get nested content
300  ComponentContent nestedContent = getInstantiatedContent(
301  program, *cur, component, componentLookup, orphans, report, activeBinding, maxDepth - 1);
302 
303  // add types
304  for (auto& type : nestedContent.types) {
305  res.add(type, report);
306  }
307 
308  // add relations
309  for (auto& rel : nestedContent.relations) {
310  res.add(rel, report);
311  }
312 
313  // add clauses
314  for (auto& clause : nestedContent.clauses) {
315  res.add(clause, report);
316  }
317 
318  // add directives
319  for (auto& directive : nestedContent.directives) {
320  res.add(directive, report);
321  }
322  }
323 
324  // collect all content in this component
325  std::set<std::string> overridden;
326  collectContent(program, *component, activeBinding, enclosingComponent, componentLookup, res, orphans,
327  overridden, report, maxDepth);
328 
329  // update type names
330  std::map<QualifiedName, QualifiedName> typeNameMapping;
331  for (const auto& cur : res.types) {
332  auto newName = componentInit.getInstanceName() + cur->getQualifiedName();
333  typeNameMapping[cur->getQualifiedName()] = newName;
334  cur->setQualifiedName(newName);
335  }
336 
337  // update relation names
338  std::map<QualifiedName, QualifiedName> relationNameMapping;
339  for (const auto& cur : res.relations) {
340  auto newName = componentInit.getInstanceName() + cur->getQualifiedName();
341  relationNameMapping[cur->getQualifiedName()] = newName;
342  cur->setQualifiedName(newName);
343  }
344 
345  // create a helper function fixing type and relation references
346  auto fixNames = [&](const Node& node) {
347  // rename attribute types in headers
348  visitDepthFirst(node, [&](const Attribute& attr) {
349  auto pos = typeNameMapping.find(attr.getTypeName());
350  if (pos != typeNameMapping.end()) {
351  const_cast<Attribute&>(attr).setTypeName(pos->second);
352  }
353  });
354 
355  // rename atoms in clauses
356  visitDepthFirst(node, [&](const Atom& atom) {
357  auto pos = relationNameMapping.find(atom.getQualifiedName());
358  if (pos != relationNameMapping.end()) {
359  const_cast<Atom&>(atom).setQualifiedName(pos->second);
360  }
361  });
362 
363  // rename directives
364  visitDepthFirst(node, [&](const Directive& directive) {
365  auto pos = relationNameMapping.find(directive.getQualifiedName());
366  if (pos != relationNameMapping.end()) {
367  const_cast<Directive&>(directive).setQualifiedName(pos->second);
368  }
369  });
370 
371  // rename field types in records
372  visitDepthFirst(node, [&](const ast::RecordType& recordType) {
373  auto&& fields = recordType.getFields();
374  for (size_t i = 0; i < fields.size(); i++) {
375  auto& field = fields[i];
376  auto pos = typeNameMapping.find(field->getTypeName());
377  if (pos != typeNameMapping.end()) {
378  const_cast<ast::RecordType&>(recordType).setFieldType(i, pos->second);
379  }
380  }
381  });
382 
383  // rename variant types in unions
384  visitDepthFirst(node, [&](const ast::UnionType& unionType) {
385  auto& variants = unionType.getTypes();
386  for (size_t i = 0; i < variants.size(); i++) {
387  auto pos = typeNameMapping.find(variants[i]);
388  if (pos != typeNameMapping.end()) {
389  const_cast<ast::UnionType&>(unionType).setType(i, pos->second);
390  }
391  }
392  });
393 
394  // rename type information in typecast
395  visitDepthFirst(node, [&](const ast::TypeCast& cast) {
396  auto pos = typeNameMapping.find(cast.getType());
397  if (pos != typeNameMapping.end()) {
398  const_cast<ast::TypeCast&>(cast).setType(pos->second);
399  }
400  });
401  };
402 
403  // rename attributes in relation decls
404  for (const auto& cur : res.relations) {
405  fixNames(*cur);
406  }
407 
408  // rename added clauses
409  for (const auto& cur : res.clauses) {
410  fixNames(*cur);
411  }
412 
413  // rename orphans
414  for (const auto& cur : orphans) {
415  fixNames(*cur);
416  }
417 
418  // rename directive directives
419  for (const auto& cur : res.directives) {
420  fixNames(*cur);
421  }
422 
423  // rename subtypes
424  for (const auto& cur : res.types) {
425  fixNames(*cur);
426  }
427 
428  return res;
429 }
430 } // namespace
431 
432 bool ComponentInstantiationTransformer::transform(TranslationUnit& translationUnit) {
433  Program& program = translationUnit.getProgram();
434  auto& report = translationUnit.getErrorReport();
435 
436  auto* componentLookup = translationUnit.getAnalysis<ComponentLookupAnalysis>();
437 
438  for (const auto* cur : program.getComponentInstantiations()) {
439  std::vector<Own<Clause>> orphans;
440 
441  auto content = getInstantiatedContent(program, *cur, nullptr, *componentLookup, orphans, report);
442  if (report.getNumErrors() != 0) continue;
443 
444  for (auto& type : content.types) {
445  program.addType(std::move(type));
446  }
447  for (auto& rel : content.relations) {
448  program.addRelation(std::move(rel));
449  }
450  for (auto& clause : content.clauses) {
451  program.addClause(std::move(clause));
452  }
453  for (auto& orphan : orphans) {
454  program.addClause(std::move(orphan));
455  }
456  for (auto& directive : content.directives) {
457  program.addDirective(std::move(directive));
458  }
459  }
460 
461  // delete components and instantiations
462  program.clearComponents();
463 
464  return true;
465 }
466 
467 } // namespace souffle::ast::transform
TranslationUnit.h
err
std::string & err
Definition: json11.h:664
Directive.h
Component.h
UnionType.h
types
std::vector< Own< ast::Type > > types
Definition: ComponentInstantiation.cpp:64
base
T & base
Definition: Reader.h:60
ComponentInit.h
relations
std::vector< Own< Relation > > relations
Definition: ComponentInstantiation.cpp:65
Relation.h
Attribute.h
souffle::toString
const std::string & toString(const std::string &str)
A generic function converting strings into strings (trivial case).
Definition: StringUtil.h:234
TypeCast.h
i
size_t i
Definition: json11.h:663
clauses
std::vector< Own< Clause > > clauses
Definition: ComponentInstantiation.cpp:67
StringUtil.h
Atom.h
ComponentLookup.h
souffle::Diagnostic::Type::ERROR
@ ERROR
souffle::ast::transform
Definition: Program.h:45
Type.h
ComponentType.h
ComponentInstantiation.h
Node.h
directives
std::vector< Own< Directive > > directives
Definition: ComponentInstantiation.cpp:66
QualifiedName.h
Program.h
RecordType.h
souffle::ast::DirectiveType::output
@ output
Visitor.h
Clause.h
souffle::ast::visitDepthFirst
void visitDepthFirst(const Node &root, Visitor< R, Ps... > &visitor, Args &... args)
A utility function visiting all nodes within the ast rooted by the given node recursively in a depth-...
Definition: Visitor.h:273
rel
void rel(size_t limit, bool showLimit=true)
Definition: Tui.h:1086
ErrorReport.h
std::type
ElementType type
Definition: span.h:640