diff --git a/src/language/ASTNodeDataTypeBuilder.cpp b/src/language/ASTNodeDataTypeBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..85e610b0b3ec83e2efa9083af82bc13ee56032a8 --- /dev/null +++ b/src/language/ASTNodeDataTypeBuilder.cpp @@ -0,0 +1,134 @@ +#include <ASTNodeDataTypeBuilder.hpp> + +#include <PEGGrammar.hpp> +#include <PugsAssert.hpp> +#include <SymbolTable.hpp> + +void +ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) +{ + if (n.is<language::bloc>() or n.is<language::for_statement>()) { + for (auto& child : n.children) { + this->_buildNodeDataTypes(*child); + } + n.m_data_type = ASTNodeDataType::void_t; + } else { + if (n.has_content()) { + if (n.is<language::true_kw>() or n.is<language::false_kw>()) { + n.m_data_type = ASTNodeDataType::bool_t; + } else if (n.is<language::real>()) { + n.m_data_type = ASTNodeDataType::double_t; + } else if (n.is<language::integer>()) { + n.m_data_type = ASTNodeDataType::int_t; + } else if (n.is<language::literal>()) { + n.m_data_type = ASTNodeDataType::string_t; + } else if (n.is<language::cout_kw>() or n.is<language::cerr_kw>() or n.is<language::clog_kw>()) { + n.m_data_type = ASTNodeDataType::void_t; + } else if (n.is<language::declaration>()) { + auto& type_node = *(n.children[0]); + ASTNodeDataType data_type{ASTNodeDataType::undefined_t}; + if (type_node.is<language::B_set>()) { + data_type = ASTNodeDataType::bool_t; + } else if (type_node.is<language::Z_set>()) { + data_type = ASTNodeDataType::int_t; + } else if (type_node.is<language::N_set>()) { + data_type = ASTNodeDataType::unsigned_int_t; + } else if (type_node.is<language::R_set>()) { + data_type = ASTNodeDataType::double_t; + } else if (type_node.is<language::string_type>()) { + data_type = ASTNodeDataType::string_t; + } + if (data_type == ASTNodeDataType::undefined_t) { + throw parse_error("unexpected error: invalid datatype", type_node.begin()); + } + type_node.m_data_type = ASTNodeDataType::void_t; + n.children[1]->m_data_type = data_type; + const std::string& symbol = n.children[1]->string(); + + std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table; + + auto [i_symbol, found] = symbol_table->find(symbol); + Assert(found); + i_symbol->second.setDataType(data_type); + n.m_data_type = data_type; + } else if (n.is<language::name>()) { + std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table; + + auto [i_symbol, found] = symbol_table->find(n.string()); + Assert(found); + n.m_data_type = i_symbol->second.dataType(); + } + } + for (auto& child : n.children) { + this->_buildNodeDataTypes(*child); + } + + if (n.is<language::break_kw>() or n.is<language::continue_kw>()) { + n.m_data_type = ASTNodeDataType::void_t; + } else if (n.is<language::eq_op>() or n.is<language::multiplyeq_op>() or n.is<language::divideeq_op>() or + n.is<language::pluseq_op>() or n.is<language::minuseq_op>() or n.is<language::bit_andeq_op>() or + n.is<language::bit_xoreq_op>() or n.is<language::bit_oreq_op>()) { + n.m_data_type = n.children[0]->m_data_type; + } else if (n.is<language::for_statement>()) { + n.m_data_type = ASTNodeDataType::void_t; + } else if (n.is<language::for_post>() or n.is<language::for_init>() or n.is<language::for_statement_bloc>()) { + n.m_data_type = ASTNodeDataType::void_t; + } else if (n.is<language::for_test>()) { + n.m_data_type = ASTNodeDataType::bool_t; + } else if (n.is<language::statement_bloc>()) { + n.m_data_type = ASTNodeDataType::void_t; + } else if (n.is<language::if_statement>() or n.is<language::while_statement>()) { + n.m_data_type = ASTNodeDataType::void_t; + if ((n.children[0]->m_data_type > ASTNodeDataType::double_t) or + (n.children[0]->m_data_type < ASTNodeDataType::bool_t)) { + const ASTNodeDataType type_0 = n.children[0]->m_data_type; + std::ostringstream message; + message << "Cannot convert data type to boolean value\n" + << "note: incompatible operand '" << n.children[0]->string() << "' of type " << dataTypeName(type_0) + << std::ends; + throw parse_error(message.str(), n.children[0]->begin()); + } + } else if (n.is<language::do_while_statement>()) { + n.m_data_type = ASTNodeDataType::void_t; + if ((n.children[1]->m_data_type > ASTNodeDataType::double_t) or + (n.children[1]->m_data_type < ASTNodeDataType::bool_t)) { + const ASTNodeDataType type_0 = n.children[1]->m_data_type; + std::ostringstream message; + message << "Cannot convert data type to boolean value\n" + << "note: incompatible operand '" << n.children[1]->string() << "' of type " << dataTypeName(type_0) + << std::ends; + throw parse_error(message.str(), n.children[1]->begin()); + } + } else if (n.is<language::unary_not>() or n.is<language::lesser_op>() or n.is<language::lesser_or_eq_op>() or + n.is<language::greater_op>() or n.is<language::greater_or_eq_op>() or n.is<language::eqeq_op>() or + n.is<language::not_eq_op>() or n.is<language::and_op>() or n.is<language::or_op>() or + n.is<language::xor_op>() or n.is<language::bitand_op>() or n.is<language::bitor_op>()) { + n.m_data_type = ASTNodeDataType::bool_t; + } else if (n.is<language::unary_minus>() or n.is<language::unary_plus>() or n.is<language::unary_plusplus>() or + n.is<language::unary_minusminus>()) { + n.m_data_type = n.children[0]->m_data_type; + } else if (n.is<language::plus_op>() or n.is<language::minus_op>() or n.is<language::multiply_op>() or + n.is<language::divide_op>()) { + const ASTNodeDataType type_0 = n.children[0]->m_data_type; + const ASTNodeDataType type_1 = n.children[1]->m_data_type; + + n.m_data_type = dataTypePromotion(type_0, type_1); + if (n.m_data_type == ASTNodeDataType::undefined_t) { + std::ostringstream message; + message << "undefined binary operator\n" + << "note: incompatible operand types " << n.children[0]->string() << " (" << dataTypeName(type_0) + << ") and " << n.children[1]->string() << " (" << dataTypeName(type_1) << ')' << std::ends; + throw parse_error(message.str(), n.begin()); + } + } + } +} + +ASTNodeDataTypeBuilder::ASTNodeDataTypeBuilder(ASTNode& node) +{ + Assert(node.is_root()); + node.m_data_type = ASTNodeDataType::void_t; + + this->_buildNodeDataTypes(node); + std::cout << " - build node data types\n"; +} diff --git a/src/language/ASTNodeDataTypeBuilder.hpp b/src/language/ASTNodeDataTypeBuilder.hpp new file mode 100644 index 0000000000000000000000000000000000000000..126c8d44285a998599c14314a404ddfdab0d3591 --- /dev/null +++ b/src/language/ASTNodeDataTypeBuilder.hpp @@ -0,0 +1,15 @@ +#ifndef AST_NODE_DATA_TYPE_BUILDER_HPP +#define AST_NODE_DATA_TYPE_BUILDER_HPP + +#include <ASTNode.hpp> + +class ASTNodeDataTypeBuilder +{ + private: + void _buildNodeDataTypes(ASTNode& node); + + public: + ASTNodeDataTypeBuilder(ASTNode& root_node); +}; + +#endif // AST_NODE_DATA_TYPE_BUILDER_HPP diff --git a/src/language/CMakeLists.txt b/src/language/CMakeLists.txt index c99aa359270586271348d6e7b72a1392745baaf0..8216aeac94b8868a3dd73a2604e46e53de740ba0 100644 --- a/src/language/CMakeLists.txt +++ b/src/language/CMakeLists.txt @@ -8,6 +8,7 @@ add_library( ASTBuilder.cpp ASTDotPrinter.cpp ASTNodeDataType.cpp + ASTNodeDataTypeBuilder.cpp ASTNodeAffectationExpressionBuilder.cpp ASTNodeBinaryOperatorExpressionBuilder.cpp ASTNodeExpressionBuilder.cpp diff --git a/src/language/PugsParser.cpp b/src/language/PugsParser.cpp index 8f85044d192728a07edc34c2b8bded238ac38f2d..9f3483851420fa4e55550bc10ffbaff9e52b441c 100644 --- a/src/language/PugsParser.cpp +++ b/src/language/PugsParser.cpp @@ -19,6 +19,8 @@ #include <PEGGrammar.hpp> #include <SymbolTable.hpp> +#include <ASTNodeDataTypeBuilder.hpp> + #include <EscapedString.hpp> #include <ASTNodeExpressionBuilder.hpp> @@ -31,141 +33,6 @@ namespace language { -namespace internal -{ -void -build_node_data_types(ASTNode& n) -{ - if (n.is<language::bloc>() or n.is<for_statement>()) { - if (!n.children.empty()) { - for (auto& child : n.children) { - build_node_data_types(*child); - } - } - n.m_data_type = ASTNodeDataType::void_t; - } else { - if (n.has_content()) { - if (n.is<language::true_kw>() or n.is<language::false_kw>() or n.is<language::do_kw>()) { - n.m_data_type = ASTNodeDataType::bool_t; - } else if (n.is<language::real>()) { - n.m_data_type = ASTNodeDataType::double_t; - } else if (n.is<language::integer>()) { - n.m_data_type = ASTNodeDataType::int_t; - } else if (n.is<language::literal>()) { - n.m_data_type = ASTNodeDataType::string_t; - } else if (n.is<language::cout_kw>() or n.is<language::cerr_kw>() or n.is<language::clog_kw>()) { - n.m_data_type = ASTNodeDataType::void_t; - } else if (n.is<language::declaration>()) { - auto& type_node = *(n.children[0]); - ASTNodeDataType data_type{ASTNodeDataType::undefined_t}; - if (type_node.is<language::B_set>()) { - data_type = ASTNodeDataType::bool_t; - } else if (type_node.is<language::Z_set>()) { - data_type = ASTNodeDataType::int_t; - } else if (type_node.is<language::N_set>()) { - data_type = ASTNodeDataType::unsigned_int_t; - } else if (type_node.is<language::R_set>()) { - data_type = ASTNodeDataType::double_t; - } else if (type_node.is<language::string_type>()) { - data_type = ASTNodeDataType::string_t; - } - if (data_type == ASTNodeDataType::undefined_t) { - throw parse_error("unexpected error: invalid datatype", type_node.begin()); - } - type_node.m_data_type = ASTNodeDataType::void_t; - n.children[1]->m_data_type = data_type; - const std::string& symbol = n.children[1]->string(); - - std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table; - - auto [i_symbol, found] = symbol_table->find(symbol); - Assert(found); - i_symbol->second.setDataType(data_type); - n.m_data_type = data_type; - } else if (n.is<language::name>()) { - std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table; - - auto [i_symbol, found] = symbol_table->find(n.string()); - Assert(found); - n.m_data_type = i_symbol->second.dataType(); - } - } - for (auto& child : n.children) { - build_node_data_types(*child); - } - - if (n.is<language::break_kw>() or n.is<language::continue_kw>()) { - n.m_data_type = ASTNodeDataType::void_t; - } else if (n.is<language::eq_op>() or n.is<language::multiplyeq_op>() or n.is<language::divideeq_op>() or - n.is<language::pluseq_op>() or n.is<language::minuseq_op>() or n.is<language::bit_andeq_op>() or - n.is<language::bit_xoreq_op>() or n.is<language::bit_oreq_op>()) { - n.m_data_type = n.children[0]->m_data_type; - } else if (n.is<language::for_statement>()) { - n.m_data_type = ASTNodeDataType::void_t; - } else if (n.is<language::for_post>() or n.is<language::for_init>() or n.is<language::for_statement_bloc>()) { - n.m_data_type = ASTNodeDataType::void_t; - } else if (n.is<language::for_test>()) { - n.m_data_type = ASTNodeDataType::bool_t; - } else if (n.is<language::statement_bloc>()) { - n.m_data_type = ASTNodeDataType::void_t; - } else if (n.is<language::if_statement>() or n.is<language::while_statement>()) { - n.m_data_type = ASTNodeDataType::void_t; - if ((n.children[0]->m_data_type > ASTNodeDataType::double_t) or - (n.children[0]->m_data_type < ASTNodeDataType::bool_t)) { - const ASTNodeDataType type_0 = n.children[0]->m_data_type; - std::ostringstream message; - message << "Cannot convert data type to boolean value\n" - << "note: incompatible operand '" << n.children[0]->string() << " of type ' (" << dataTypeName(type_0) - << ')' << std::ends; - throw parse_error(message.str(), n.children[0]->begin()); - } - } else if (n.is<language::do_while_statement>()) { - n.m_data_type = ASTNodeDataType::void_t; - if ((n.children[1]->m_data_type > ASTNodeDataType::double_t) or - (n.children[1]->m_data_type < ASTNodeDataType::bool_t)) { - const ASTNodeDataType type_0 = n.children[1]->m_data_type; - std::ostringstream message; - message << "Cannot convert data type to boolean value\n" - << "note: incompatible operand '" << n.children[1]->string() << " of type ' (" << dataTypeName(type_0) - << ')' << std::ends; - throw parse_error(message.str(), n.children[1]->begin()); - } - } else if (n.is<language::unary_not>() or n.is<language::lesser_op>() or n.is<language::lesser_or_eq_op>() or - n.is<language::greater_op>() or n.is<language::greater_or_eq_op>() or n.is<language::eqeq_op>() or - n.is<language::not_eq_op>() or n.is<language::and_op>() or n.is<language::or_op>() or - n.is<language::xor_op>() or n.is<language::bitand_op>() or n.is<language::bitor_op>()) { - n.m_data_type = ASTNodeDataType::bool_t; - } else if (n.is<language::unary_minus>() or n.is<language::unary_plus>() or n.is<language::unary_plusplus>() or - n.is<language::unary_minusminus>()) { - n.m_data_type = n.children[0]->m_data_type; - } else if (n.is<language::plus_op>() or n.is<language::minus_op>() or n.is<language::multiply_op>() or - n.is<language::divide_op>()) { - const ASTNodeDataType type_0 = n.children[0]->m_data_type; - const ASTNodeDataType type_1 = n.children[1]->m_data_type; - - n.m_data_type = dataTypePromotion(type_0, type_1); - if (n.m_data_type == ASTNodeDataType::undefined_t) { - std::ostringstream message; - message << "undefined binary operator\n" - << "note: incompatible operand types " << n.children[0]->string() << " (" << dataTypeName(type_0) - << ") and " << n.children[1]->string() << " (" << dataTypeName(type_1) << ')' << std::ends; - throw parse_error(message.str(), n.begin()); - } - } - } -} -} // namespace internal - -void -build_node_data_types(ASTNode& n) -{ - Assert(n.is_root()); - n.m_data_type = ASTNodeDataType::void_t; - - internal::build_node_data_types(n); - std::cout << " - build node data types\n"; -} - namespace internal { void @@ -332,7 +199,7 @@ parser(const std::string& filename) std::cout << " AST dot file: " << dot_filename << '\n'; } - language::build_node_data_types(*root_node); + ASTNodeDataTypeBuilder{*root_node}; language::check_node_data_types(*root_node); language::build_node_values(*root_node);