diff options
| author | Martial Simon <msimon_fr@hotmail.com> | 2025-09-15 01:07:58 +0200 |
|---|---|---|
| committer | Martial Simon <msimon_fr@hotmail.com> | 2025-09-15 01:07:58 +0200 |
| commit | 967be9e750221ab2ab783f95df79bb26d290a45e (patch) | |
| tree | 6802900a5e975f9f68b169f0f503f040056d6952 /tiger-compiler/src/type/type-checker.hh | |
Diffstat (limited to 'tiger-compiler/src/type/type-checker.hh')
| -rw-r--r-- | tiger-compiler/src/type/type-checker.hh | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/tiger-compiler/src/type/type-checker.hh b/tiger-compiler/src/type/type-checker.hh new file mode 100644 index 0000000..789a31f --- /dev/null +++ b/tiger-compiler/src/type/type-checker.hh @@ -0,0 +1,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> |
