/
AstConstraint.h
139 lines (119 loc) · 4.65 KB
/
AstConstraint.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
/*
* Souffle - A Datalog Compiler
* Copyright (c) 2019, The Souffle Developers. 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 AstConstraint.h
*
* Contains AST Constraint Analysis Infrastructure for doing constraint analysis on AST objects
*
***********************************************************************/
#pragma once
#include "Constraints.h"
#include "ast/AstAbstract.h"
#include "ast/AstArgument.h"
#include "ast/AstClause.h"
#include "ast/AstNode.h"
#include "ast/AstVisitor.h"
#include <map>
#include <memory>
#include <ostream>
#include <string>
#include <utility>
namespace souffle {
/**
* A variable type to be utilized by AST constraint analysis. Each such variable is
* associated with an AstArgument which's property it is describing.
*
* @tparam PropertySpace the property space associated to the analysis
*/
template <typename PropertySpace>
struct AstConstraintAnalysisVar : public Variable<const AstArgument*, PropertySpace> {
explicit AstConstraintAnalysisVar(const AstArgument* arg)
: Variable<const AstArgument*, PropertySpace>(arg) {}
explicit AstConstraintAnalysisVar(const AstArgument& arg)
: Variable<const AstArgument*, PropertySpace>(&arg) {}
/** adds print support */
void print(std::ostream& out) const override {
out << "var(" << *(this->id) << ")";
}
};
/**
* A base class for AstConstraintAnalysis collecting constraints for an analysis
* by visiting every node of a given AST. The collected constraints are
* then utilized to obtain the desired analysis result.
*
* @tparam AnalysisVar the type of variable (and included property space)
* to be utilized by this analysis.
*/
template <typename AnalysisVar>
class AstConstraintAnalysis : public AstVisitor<void> {
public:
using value_type = typename AnalysisVar::property_space::value_type;
using constraint_type = std::shared_ptr<Constraint<AnalysisVar>>;
using solution_type = std::map<const AstArgument*, value_type>;
virtual void collectConstraints(const AstClause& clause) {
visitDepthFirstPreOrder(clause, *this);
}
/**
* Runs this constraint analysis on the given clause.
*
* @param clause the close to be analysed
* @param debug a flag enabling the printing of debug information
* @return an assignment mapping a property to each argument in the given clause
*/
solution_type analyse(const AstClause& clause, std::ostream* debugOutput = nullptr) {
collectConstraints(clause);
assignment = constraints.solve();
// print debug information if desired
if (debugOutput != nullptr) {
*debugOutput << "Clause: " << clause << "\n";
*debugOutput << "Problem:\n" << constraints << "\n";
*debugOutput << "Solution:\n" << assignment << "\n";
}
// convert assignment to result
solution_type solution;
visitDepthFirst(clause, [&](const AstArgument& arg) { solution[&arg] = assignment[getVar(arg)]; });
return solution;
}
protected:
/**
* A utility function mapping an AstArgument to its associated analysis variable.
*
* @param arg the AST argument to be mapped
* @return the analysis variable representing its associated value
*/
AnalysisVar getVar(const AstArgument& arg) {
const auto* var = dynamic_cast<const AstVariable*>(&arg);
if (var == nullptr) {
// no mapping required
return AnalysisVar(arg);
}
// filter through map => always take the same variable
auto res = variables.insert({var->getName(), AnalysisVar(var)}).first;
return res->second;
}
/**
* A utility function mapping an AstArgument to its associated analysis variable.
*
* @param arg the AST argument to be mapped
* @return the analysis variable representing its associated value
*/
AnalysisVar getVar(const AstArgument* arg) {
return getVar(*arg);
}
/** Adds another constraint to the internally maintained list of constraints */
void addConstraint(const constraint_type& constraint) {
constraints.add(constraint);
}
Assignment<AnalysisVar> assignment;
/** The list of constraints making underlying this analysis */
Problem<AnalysisVar> constraints;
/** A map mapping variables to unique instances to facilitate the unification of variables */
std::map<std::string, AnalysisVar> variables;
};
} // end of namespace souffle