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
|
/**
** \file type/type-checker.hh
** \brief Perform type checking and other semantical checks.
*/
#pragma once
#include <cassert>
#include <string>
#include <ast/default-visitor.hh>
#include <ast/non-assert-visitor.hh>
#include <ast/non-object-visitor.hh>
#include <misc/error.hh>
#include <misc/set.hh>
#include <type/fwd.hh>
namespace type
{
class TypeChecker
: public ast::DefaultVisitor
, public ast::NonObjectVisitor
, public ast::NonAssertVisitor
{
public:
using super_type = ast::DefaultVisitor;
using super_type::operator();
/// Construction.
TypeChecker();
/// The error handler.
const misc::error& error_get() const;
protected:
/// Run this visitor on \a e, and return its type.
///
/// Note that it is also guaranteed that \a type_ is set to this type.
/// More generally, using \a type allows to avoid calling \a accept
/// directly.
const Type* type(ast::Typable& e);
const Record* type(const ast::fields_type& e);
const Record* type(const ast::VarChunk& e);
// ------------------ //
// Helping routines. //
// ------------------ //
protected:
/// \name Error handling.
/// \{
/// Report an error.
void error(const ast::Ast& ast, const std::string& msg);
/// Report an error.
///
/// \param ast the node whose location is used in the error message
/// \param msg the error message
/// \param exp the culprit. It must support << output
template <typename T>
void error(const ast::Ast& ast, const std::string& msg, const T& exp);
/// Report an error, and recover from it.
///
/// \param loc the node whose location is used in the error message
/// and whose type is set to nil as an attempt to
/// recover.
/// \param msg the error message
/// \param exp the culprit. It must support << output
template <typename T, typename U>
void error_and_recover(T& loc, const std::string& msg, const U& exp);
/// Report a type_mismatch between two entities.
/// \param ast the guilty node, used to report the location.
/// \param exp1 the string denoting the first exp.
/// \param type1 its type
/// \param exp2 similarly
/// \param type2 similarly
void type_mismatch(const ast::Ast& ast,
const std::string& exp1,
const Type& type1,
const std::string& exp2,
const Type& type2);
/// \}
/// \name Checking types.
/// \{
/// \brief Check the type of an Exp.
///
/// \param e the expression/declaration to check
/// \param s the string to refer to \a e in error messages
/// (e.g., "index", "left operand" etc.).
/// \param t the expected type
///
/// On failure, report the error, and set the type of \a e to \a t.
/// This should be used for `ast::Exp` and `ast::Dec` nodes.
template <typename NodeType>
void check_type(NodeType& e, const std::string& s, const Type& t);
/** \brief Check the type compatibility.
**
** An error message is output if types are incompatible.
**
** \param loc a node which location is used to report errors
** \param exp1 the syntactic category of the first entity,
** (used in error messages)
** \param type1 the first type
** \param exp2 same as above
** \param type2 same as above
**/
void check_types(const ast::Ast& loc,
const std::string& exp1,
const Type& type1,
const std::string& exp2,
const Type& type2);
void check_types(const ast::Ast& loc,
const std::string& exp1,
ast::Typable& type1,
const std::string& exp2,
ast::Typable& type2);
/// \}
protected:
/// \name Setting types.
/// \{
/// Set the type of a node, if it isn't already set
/// (an existing type won't be overwritten).
///
/// \param e the bound node
/// \param type the type
template <typename NodeType>
void type_default(NodeType& e, const type::Type* type);
/// Same as type_default, but for a created type.
template <typename NodeType>
void created_type_default(NodeType& e, const type::Type* type);
/// Set the type of a node (overwriting allowed).
///
/// \param e the bound node
/// \param type the type
template <typename NodeType>
void type_set(NodeType& e, const type::Type* type);
/// \}
// ------------------------- //
// The core of the visitor. //
// ------------------------- //
// ---------------- //
// Visiting /Var/. //
// ---------------- //
void operator()(ast::SimpleVar& e) override;
// FIXME DONE: Some code was deleted here (Other Var nodes).
void operator()(ast::FieldVar& e) override;
void operator()(ast::SubscriptVar& e) override;
// ---------------- //
// Visiting /Exp/. //
// ---------------- //
// Literals.
void operator()(ast::NilExp&) override;
void operator()(ast::IntExp&) override;
void operator()(ast::StringExp&) override;
// Complex values.
void operator()(ast::RecordExp& e) override;
void operator()(ast::OpExp& e) override;
// FIXME DONE: Some code was deleted here (Other Exp nodes).
void operator()(ast::ArrayExp& e) override;
void operator()(ast::AssignExp& e) override;
void operator()(ast::BreakExp& e) override;
// I don't put MethodCallExp because it should be managed by CallExp
void operator()(ast::CallExp& e) override;
void operator()(ast::CastExp& e) override;
void operator()(ast::ForExp& e) override;
void operator()(ast::IfExp& e) override;
void operator()(ast::LetExp& e) override;
void operator()(ast::SeqExp& e) override;
void operator()(ast::WhileExp& e) override;
// ---------------- //
// Visiting /Dec/. //
// ---------------- //
/// \name Type and Function declarations.
/// \{
/// Be sure to read the documentation of
/// bind::Binder::chunk_visit.
///
/// When type-checking a function (or a type) we need two
/// traversals: one to register the function's type (to enable
/// mutual recursions) and a second one to check the bodies.
/// This is why there are actually three methods: chunk_visit,
/// visit_dec_header, and visit_dec_body. It turns out that
/// chunk_visit can be written for both functions and types, but of
/// course, traversals of headers and bodies differ.
/// Check a set of definitions: unique names, browse headers, then
/// bodies.
template <class D> void chunk_visit(ast::Chunk<D>& e);
/// Check a Function or Type declaration header.
template <class D> void visit_dec_header(D& e);
/// Check a Function or Type declaration body.
template <class D> void visit_dec_body(D& e);
/// Generic type-checking of a routine's body.
template <typename Routine_Type, typename Routine_Node>
void visit_routine_body(Routine_Node& e);
/// Visit a chunk of function declarations.
void operator()(ast::FunctionChunk& e) override;
/// No longer used.
void operator()(ast::FunctionDec&) override;
/// Visit a chunk of type declarations.
void operator()(ast::TypeChunk& e) override;
/// No longer used.
void operator()(ast::TypeDec&) override;
/// \}
/// Visit a single Variable Declaration.
void operator()(ast::VarDec& e) override;
// --------------- //
// Visiting /Ty/. //
// --------------- //
void operator()(ast::NameTy& e) override;
void operator()(ast::RecordTy& e) override;
void operator()(ast::ArrayTy& e) override;
protected:
/// Error handler.
misc::error error_;
/// Set of for index variable definitions, which are read only.
misc::set<const ast::VarDec*> var_read_only_;
// ------------------- //
// Custom attributes. //
// ------------------- //
// Default type to use when a node is badly typed
const Type& default_type = Int::instance();
// ------------------- //
// Custom methods. //
// ------------------- //
/**
* @brief Check that the provided FunctionDec represents a valid main_
* function, typing-wise.
* @param e Node to check. It is assumed it represents a main_ function
*/
void type_main(ast::FunctionDec* e);
};
/// Visit the lhs of an ast::FunctionDec.
template <>
void TypeChecker::visit_dec_header<ast::FunctionDec>(ast::FunctionDec& e);
/// Visit the rhs of an ast::FunctionDec.
template <>
void TypeChecker::visit_dec_body<ast::FunctionDec>(ast::FunctionDec& e);
/// Visit the lhs of an ast::TypeDec.
template <> void TypeChecker::visit_dec_header<ast::TypeDec>(ast::TypeDec& e);
/// Visit the rhs of an ast::TypeDec.
template <> void TypeChecker::visit_dec_body<ast::TypeDec>(ast::TypeDec& e);
} // namespace type
#include <type/type-checker.hxx>
|