souffle  2.0.2-371-g6315b36
IOAttributes.h
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2020, The Souffle Developers. 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 IOAttributes.h
12  *
13  * Defines AST transformation to set attribute names and types in IO
14  * operations.
15  *
16  ***********************************************************************/
17 
18 #pragma once
19 
20 #include "Global.h"
21 #include "ast/AlgebraicDataType.h"
22 #include "ast/Attribute.h"
23 #include "ast/Directive.h"
24 #include "ast/Program.h"
25 #include "ast/QualifiedName.h"
26 #include "ast/RecordType.h"
27 #include "ast/Relation.h"
28 #include "ast/TranslationUnit.h"
29 #include "ast/Type.h"
30 #include "ast/analysis/AuxArity.h"
34 #include "ast/utility/Utils.h"
35 #include "ast/utility/Visitor.h"
39 #include "souffle/utility/json11.h"
40 #include <algorithm>
41 #include <cstddef>
42 #include <map>
43 #include <string>
44 #include <type_traits>
45 #include <utility>
46 #include <vector>
47 
48 namespace souffle::ast::transform {
49 
50 /**
51  * Transformation pass to set attribute names and types in IO operations.
52  */
53 class IOAttributesTransformer : public Transformer {
54 public:
55  std::string getName() const override {
56  return "IOAttributesTransformer";
57  }
58 
59  IOAttributesTransformer* clone() const override {
61  }
62 
63 private:
64  bool transform(TranslationUnit& translationUnit) override {
65  bool changed = false;
66 
67  changed |= setAttributeNames(translationUnit);
68  changed |= setAttributeTypes(translationUnit);
69  changed |= setAttributeParams(translationUnit);
70 
71  return changed;
72  }
73 
74  bool setAttributeParams(TranslationUnit& translationUnit) {
75  bool changed = false;
76  Program& program = translationUnit.getProgram();
77  auto auxArityAnalysis = translationUnit.getAnalysis<analysis::AuxiliaryArityAnalysis>();
78 
79  for (Directive* io : program.getDirectives()) {
80  if (io->getType() == ast::DirectiveType::limitsize) {
81  continue;
82  }
83  Relation* rel = getRelation(program, io->getQualifiedName());
84  // Prepare type system information.
85  std::vector<std::string> attributesParams;
86 
87  for (const auto* attribute : rel->getAttributes()) {
88  attributesParams.push_back(attribute->getName());
89  }
90 
91  // Casting due to json11.h type requirements.
92  long long arity{static_cast<long long>(rel->getArity() - auxArityAnalysis->getArity(rel))};
93  long long auxArity{static_cast<long long>(auxArityAnalysis->getArity(rel))};
94 
95  json11::Json relJson = json11::Json::object{{"arity", arity}, {"auxArity", auxArity},
96  {"params", json11::Json::array(attributesParams.begin(), attributesParams.end())}};
97 
99  {"relation", relJson}, {"records", getRecordsParams(translationUnit)}};
100 
101  io->addParameter("params", params.dump());
102  changed = true;
103  }
104  return changed;
105  }
106 
107  bool setAttributeNames(TranslationUnit& translationUnit) {
108  bool changed = false;
109  Program& program = translationUnit.getProgram();
110  for (Directive* io : program.getDirectives()) {
111  if (io->getType() == ast::DirectiveType::limitsize) {
112  continue;
113  }
114  if (io->hasParameter("attributeNames")) {
115  continue;
116  }
117  Relation* rel = getRelation(program, io->getQualifiedName());
118  std::string delimiter("\t");
119  if (io->hasParameter("delimiter")) {
120  delimiter = io->getParameter("delimiter");
121  }
122 
123  std::vector<std::string> attributeNames;
124  for (const auto* attribute : rel->getAttributes()) {
125  attributeNames.push_back(attribute->getName());
126  }
127 
128  if (Global::config().has("provenance")) {
129  auto auxArityAnalysis = translationUnit.getAnalysis<analysis::AuxiliaryArityAnalysis>();
130  std::vector<std::string> originalAttributeNames(
131  attributeNames.begin(), attributeNames.end() - auxArityAnalysis->getArity(rel));
132  io->addParameter("attributeNames", toString(join(originalAttributeNames, delimiter)));
133  } else {
134  io->addParameter("attributeNames", toString(join(attributeNames, delimiter)));
135  }
136  changed = true;
137  }
138  return changed;
139  }
140 
141  bool setAttributeTypes(TranslationUnit& translationUnit) {
142  bool changed = false;
143  Program& program = translationUnit.getProgram();
144  auto auxArityAnalysis = translationUnit.getAnalysis<analysis::AuxiliaryArityAnalysis>();
145  auto typeEnv =
146  &translationUnit.getAnalysis<analysis::TypeEnvironmentAnalysis>()->getTypeEnvironment();
147 
148  for (Directive* io : program.getDirectives()) {
149  Relation* rel = getRelation(program, io->getQualifiedName());
150  // Prepare type system information.
151  std::vector<std::string> attributesTypes;
152 
153  for (const auto* attribute : rel->getAttributes()) {
154  auto typeName = attribute->getTypeName();
155  auto type = getTypeQualifier(typeEnv->getType(typeName));
156  attributesTypes.push_back(type);
157  }
158 
159  // Casting due to json11.h type requirements.
160  long long arity{static_cast<long long>(rel->getArity() - auxArityAnalysis->getArity(rel))};
161  long long auxArity{static_cast<long long>(auxArityAnalysis->getArity(rel))};
162 
163  json11::Json relJson = json11::Json::object{{"arity", arity}, {"auxArity", auxArity},
164  {"types", json11::Json::array(attributesTypes.begin(), attributesTypes.end())}};
165 
167  json11::Json::object{{"relation", relJson}, {"records", getRecordsTypes(translationUnit)},
168  {"ADTs", getAlgebraicDataTypes(translationUnit)}};
169 
170  io->addParameter("types", types.dump());
171  changed = true;
172  }
173  return changed;
174  }
175 
176  std::string getRelationName(const Directive* node) {
177  return toString(join(node->getQualifiedName().getQualifiers(), "."));
178  }
179 
180  /**
181  * Get sum types info for IO.
182  * If they don't exists - create them.
183  *
184  * The structure of JSON is approximately:
185  * {"ADTs" : {ADT_NAME : {"branches" : [branch..]}, {"arity": ...}}}
186  * branch = {{"types": [types ...]}, ["name": ...]}
187  */
188  json11::Json getAlgebraicDataTypes(TranslationUnit& translationUnit) const {
189  static json11::Json sumTypesInfo;
190 
191  // Check if the types were already constructed
192  if (!sumTypesInfo.is_null()) {
193  return sumTypesInfo;
194  }
195 
196  Program& program = translationUnit.getProgram();
197  auto& typeEnv =
198  translationUnit.getAnalysis<analysis::TypeEnvironmentAnalysis>()->getTypeEnvironment();
199 
200  std::map<std::string, json11::Json> sumTypes;
201 
202  visitDepthFirst(program.getTypes(), [&](const AlgebraicDataType& astAlgebraicDataType) {
203  auto& sumType =
204  dynamic_cast<const analysis::AlgebraicDataType&>(typeEnv.getType(astAlgebraicDataType));
205 
206  auto& branches = sumType.getBranches();
207 
208  std::vector<json11::Json> branchesInfo;
209 
210  for (const auto& branch : branches) {
211  std::vector<json11::Json> branchTypes;
212  for (auto* type : branch.types) {
213  branchTypes.push_back(getTypeQualifier(*type));
214  }
215 
216  auto branchInfo =
217  json11::Json::object{{{"types", std::move(branchTypes)}, {"name", branch.name}}};
218  branchesInfo.push_back(std::move(branchInfo));
219  }
220 
221  auto typeQualifier = analysis::getTypeQualifier(sumType);
222  auto&& sumInfo = json11::Json::object{{{"branches", std::move(branchesInfo)},
223  {"arity", static_cast<long long>(branches.size())}, {"enum", isADTEnum(sumType)}}};
224  sumTypes.emplace(std::move(typeQualifier), std::move(sumInfo));
225  });
226 
227  sumTypesInfo = json11::Json(sumTypes);
228  return sumTypesInfo;
229  }
230 
231  json11::Json getRecordsTypes(TranslationUnit& translationUnit) const {
232  static json11::Json ramRecordTypes;
233  // Check if the types where already constructed
234  if (!ramRecordTypes.is_null()) {
235  return ramRecordTypes;
236  }
237 
238  Program& program = translationUnit.getProgram();
239  auto typeEnv =
240  &translationUnit.getAnalysis<analysis::TypeEnvironmentAnalysis>()->getTypeEnvironment();
241  std::vector<std::string> elementTypes;
242  std::map<std::string, json11::Json> records;
243 
244  // Iterate over all record types in the program populating the records map.
245  for (auto* astType : program.getTypes()) {
246  const auto& type = typeEnv->getType(*astType);
247  if (isA<analysis::RecordType>(type)) {
248  elementTypes.clear();
249 
250  for (const analysis::Type* field : as<analysis::RecordType>(type)->getFields()) {
251  elementTypes.push_back(getTypeQualifier(*field));
252  }
253  const size_t recordArity = elementTypes.size();
254  json11::Json recordInfo = json11::Json::object{
255  {"types", std::move(elementTypes)}, {"arity", static_cast<long long>(recordArity)}};
256  records.emplace(getTypeQualifier(type), std::move(recordInfo));
257  }
258  }
259 
260  ramRecordTypes = json11::Json(records);
261  return ramRecordTypes;
262  }
263 
264  json11::Json getRecordsParams(TranslationUnit& translationUnit) const {
265  static json11::Json ramRecordParams;
266  // Check if the types where already constructed
267  if (!ramRecordParams.is_null()) {
268  return ramRecordParams;
269  }
270 
271  Program& program = translationUnit.getProgram();
272  std::vector<std::string> elementParams;
273  std::map<std::string, json11::Json> records;
274 
275  // Iterate over all record types in the program populating the records map.
276  for (auto* astType : program.getTypes()) {
277  if (isA<ast::RecordType>(astType)) {
278  elementParams.clear();
279 
280  for (const auto field : as<ast::RecordType>(astType)->getFields()) {
281  elementParams.push_back(field->getName());
282  }
283  const size_t recordArity = elementParams.size();
284  json11::Json recordInfo = json11::Json::object{
285  {"params", std::move(elementParams)}, {"arity", static_cast<long long>(recordArity)}};
286  records.emplace(astType->getQualifiedName().toString(), std::move(recordInfo));
287  }
288  }
289 
290  ramRecordParams = json11::Json(records);
291  return ramRecordParams;
292  }
293 };
294 
295 } // namespace souffle::ast::transform
souffle::ast::transform::IOAttributesTransformer::getRecordsTypes
json11::Json getRecordsTypes(TranslationUnit &translationUnit) const
Definition: IOAttributes.h:245
TranslationUnit.h
json11::Json::dump
void dump(std::string &out) const
Definition: json11.h:370
souffle::ast::transform::IOAttributesTransformer::getName
std::string getName() const override
Definition: IOAttributes.h:69
souffle::ast::transform::IOAttributesTransformer::setAttributeNames
bool setAttributeNames(TranslationUnit &translationUnit)
Definition: IOAttributes.h:121
Directive.h
types
std::vector< Own< ast::Type > > types
Definition: ComponentInstantiation.cpp:64
Transformer.h
souffle::ast::Relation
Defines a relation with a name, attributes, qualifiers, and internal representation.
Definition: Relation.h:49
json11.h
json11::Json::object
std::map< std::string, Json > object
Definition: json11.h:94
souffle::ast::analysis::Type
An abstract base class for types to be covered within a type environment.
Definition: TypeSystem.h:51
Relation.h
Utils.h
souffle::ast::transform::IOAttributesTransformer
Transformation pass to set attribute names and types in IO operations.
Definition: IOAttributes.h:60
souffle::ast::transform::IOAttributesTransformer::setAttributeParams
bool setAttributeParams(TranslationUnit &translationUnit)
Definition: IOAttributes.h:88
Global.h
Attribute.h
souffle::ast::analysis::TypeEnvironmentAnalysis
Definition: TypeEnvironment.h:38
souffle::toString
const std::string & toString(const std::string &str)
A generic function converting strings into strings (trivial case).
Definition: StringUtil.h:234
AuxArity.h
souffle::ast::Program
The program class consists of relations, clauses and types.
Definition: Program.h:52
souffle::ast::transform::IOAttributesTransformer::setAttributeTypes
bool setAttributeTypes(TranslationUnit &translationUnit)
Definition: IOAttributes.h:155
souffle::ast::Directive
a directive has a type (e.g. input/output/printsize/limitsize), qualified relation name,...
Definition: Directive.h:56
ContainerUtil.h
souffle::ast::getRelation
Relation * getRelation(const Program &program, const QualifiedName &name)
Returns the relation with the given name in the program.
Definition: Utils.cpp:101
souffle::join
detail::joined_sequence< Iter, Printer > join(const Iter &a, const Iter &b, const std::string &sep, const Printer &p)
Creates an object to be forwarded to some output stream for printing sequences of elements interspers...
Definition: StreamUtil.h:175
StringUtil.h
souffle::ast::TranslationUnit
Translation unit class for the translation pipeline.
Definition: TranslationUnit.h:51
souffle::ast::transform::IOAttributesTransformer::transform
bool transform(TranslationUnit &translationUnit) override
Definition: IOAttributes.h:78
souffle::ast::transform
Definition: Program.h:45
json11::Json::array
std::vector< Json > array
Definition: json11.h:93
Type.h
json11::Json
Definition: json11.h:87
souffle::ast::Program::getDirectives
std::vector< Directive * > getDirectives() const
Return relation directives.
Definition: Program.h:75
souffle::ast::Program::getTypes
std::vector< Type * > getTypes() const
Return types.
Definition: Program.h:55
souffle::ast::TranslationUnit::getAnalysis
Analysis * getAnalysis() const
get analysis: analysis is generated on the fly if not present
Definition: TranslationUnit.h:60
souffle::Global::config
static MainConfig & config()
Definition: Global.h:141
souffle::ast::transform::IOAttributesTransformer::clone
IOAttributesTransformer * clone() const override
Definition: IOAttributes.h:73
QualifiedName.h
souffle::ast::analysis::AlgebraicDataType
Aggregates types using sums and products.
Definition: TypeSystem.h:199
json11::Json::is_null
bool is_null() const
Definition: json11.h:135
Program.h
RecordType.h
souffle::ast::transform::IOAttributesTransformer::getRecordsParams
json11::Json getRecordsParams(TranslationUnit &translationUnit) const
Definition: IOAttributes.h:278
souffle::ast::transform::IOAttributesTransformer::getAlgebraicDataTypes
json11::Json getAlgebraicDataTypes(TranslationUnit &translationUnit) const
Get sum types info for IO.
Definition: IOAttributes.h:202
StreamUtil.h
souffle::ast::DirectiveType::limitsize
@ limitsize
Visitor.h
souffle::ast::analysis::AuxiliaryArityAnalysis
Determine the auxiliary arity for relations.
Definition: AuxArity.h:38
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
AlgebraicDataType.h
souffle::ast::analysis::getTypeQualifier
std::string getTypeQualifier(const Type &type)
Returns full type qualifier for a given type.
Definition: TypeSystem.cpp:204
souffle::ast::transform::IOAttributesTransformer::getRelationName
std::string getRelationName(const Directive *node)
Definition: IOAttributes.h:190
rel
void rel(size_t limit, bool showLimit=true)
Definition: Tui.h:1086
TypeEnvironment.h
souffle::ast::TranslationUnit::getProgram
Program & getProgram() const
Return the program.
Definition: TranslationUnit.h:84
std::type
ElementType type
Definition: span.h:640
TypeSystem.h