Select Git revision
ASTSymbolInitializationChecker.cpp 5.82 KiB
#include <language/ast/ASTSymbolInitializationChecker.hpp>
#include <language/PEGGrammar.hpp>
#include <language/utils/ParseError.hpp>
#include <language/utils/SymbolTable.hpp>
void
ASTSymbolInitializationChecker::_checkSymbolInitialization(ASTNode& node)
{
if (node.is_type<language::var_declaration>()) {
auto set_is_initialized = [&](ASTNode& name_node) {
const std::string& symbol = name_node.string();
auto [i_symbol, found] = node.m_symbol_table->find(symbol, name_node.begin());
Assert(found, "unexpected error, should have been detected through declaration checking");
i_symbol->attributes().setIsInitialized();
};
auto check_correct_name_in_definition = [](ASTNode& decl_name_node, ASTNode& def_name_node) {
if (def_name_node.is_type<language::name_list>()) {
throw ParseError("unexpected variable list, expecting one identifier", std::vector{def_name_node.begin()});
}
Assert(def_name_node.is_type<language::name>());
if (decl_name_node.string() != def_name_node.string()) {
std::ostringstream os;
os << "invalid identifier, expecting '" << decl_name_node.string() << '\'';
throw ParseError(os.str(), std::vector{def_name_node.begin()});
}
};
if (node.children[0]->is_type<language::name>()) {
if (node.children.size() == 4) {
this->_checkSymbolInitialization(*node.children[3]);
check_correct_name_in_definition(*node.children[0], *node.children[2]);
set_is_initialized(*node.children[0]);
}
} else if (node.children[0]->is_type<language::name_list>()) {
if (node.children.size() == 4) {
ASTNode& decl_name_list_node = *node.children[0];
ASTNode& def_name_list_node = *node.children[2];
if (not def_name_list_node.is_type<language::name_list>()) {
throw ParseError("expecting a list of identifiers", std::vector{def_name_list_node.begin()});
}
if (decl_name_list_node.children.size() != def_name_list_node.children.size()) {
std::ostringstream os;
os << "invalid number of definition identifiers, expecting " << decl_name_list_node.children.size()
<< " found " << def_name_list_node.children.size();
throw ParseError(os.str(), std::vector{def_name_list_node.begin()});
}
ASTNode& expression_list_node = *node.children[3];
this->_checkSymbolInitialization(expression_list_node);
for (size_t i = 0; i < decl_name_list_node.children.size(); ++i) {
check_correct_name_in_definition(*decl_name_list_node.children[i], *def_name_list_node.children[i]);
set_is_initialized(*decl_name_list_node.children[i]);
}
}
}
} else if (node.is_type<language::fct_declaration>()) {
const std::string& symbol = node.children[0]->string();
auto [i_symbol, found] = node.m_symbol_table->find(symbol, node.children[0]->begin());
Assert(found, "unexpected error, should have been detected through declaration checking");
i_symbol->attributes().setIsInitialized();
auto& function_table = node.m_symbol_table->functionTable();
uint64_t function_id = std::get<uint64_t>(i_symbol->attributes().value());
auto& function_descriptor = function_table[function_id];
this->_checkSymbolInitialization(function_descriptor.definitionNode());
} else if (node.is_type<language::function_definition>()) {
this->_checkSymbolInitialization(*node.children[1]);
} else if (node.is_type<language::eq_op>()) {
// first checks for right hand side
this->_checkSymbolInitialization(*node.children[1]);
auto set_is_initialized = [&](ASTNode& name_node) {
const std::string& symbol = name_node.string();
auto [i_symbol, found] = node.m_symbol_table->find(symbol, name_node.begin());
Assert(found, "unexpected error, should have been detected through declaration checking");
i_symbol->attributes().setIsInitialized();
};
if (node.children[0]->is_type<language::name>()) {
set_is_initialized(*node.children[0]);
} else if (node.children[0]->is_type<language::subscript_expression>()) {
ASTNode& subscript_node = *node.children[0];
ASTNode& name_node = *subscript_node.children[0];
Assert(name_node.is_type<language::name>());
set_is_initialized(name_node);
} else if (node.children[0]->is_type<language::name_list>() or node.children[0]->is_type<language::lvalue_list>()) {
ASTNode& list_node = *node.children[0];
for (auto& child_node : list_node.children) {
if (child_node->is_type<language::name>()) {
set_is_initialized(*child_node);
} else {
Assert(child_node->is_type<language::subscript_expression>());
ASTNode& name_node = *child_node->children[0];
Assert(name_node.is_type<language::name>());
set_is_initialized(name_node);
}
}
}
} else if (node.is_type<language::name>()) {
auto [i_symbol, found] = node.m_symbol_table->find(node.string(), node.begin());
Assert(node.m_symbol_table->has(node.string(), node.begin()),
"unexpected error, should have been detected through declaration checking");
if (found and not i_symbol->attributes().isInitialized()) {
std::ostringstream error_message;
error_message << "uninitialized symbol '" << rang::fg::red << node.string() << rang::fg::reset << '\'';
throw ParseError(error_message.str(), std::vector{node.begin()});
}
}
if (not(node.is_type<language::var_declaration>() or node.is_type<language::fct_declaration>() or
node.is_type<language::eq_op>())) {
for (auto& child : node.children) {
this->_checkSymbolInitialization(*child);
}
}
}
ASTSymbolInitializationChecker::ASTSymbolInitializationChecker(ASTNode& root_node)
{
Assert(root_node.is_root());
this->_checkSymbolInitialization(root_node);
}