/** ** \file type/type-checker.hh ** \brief Perform type checking and other semantical checks. */ #pragma once #include #include #include #include #include #include #include #include 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 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 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 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 void type_default(NodeType& e, const type::Type* type); /// Same as type_default, but for a created type. template 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 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 void chunk_visit(ast::Chunk& e); /// Check a Function or Type declaration header. template void visit_dec_header(D& e); /// Check a Function or Type declaration body. template void visit_dec_body(D& e); /// Generic type-checking of a routine's body. template 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 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& e); /// Visit the rhs of an ast::FunctionDec. template <> void TypeChecker::visit_dec_body(ast::FunctionDec& e); /// Visit the lhs of an ast::TypeDec. template <> void TypeChecker::visit_dec_header(ast::TypeDec& e); /// Visit the rhs of an ast::TypeDec. template <> void TypeChecker::visit_dec_body(ast::TypeDec& e); } // namespace type #include