#include "StaticPass.hpp" #include "lib/Node.hpp" #include "TypeResolver.hpp" namespace roza { /*explicit*/ StaticPass::StaticPass(StatusLog& log) : StaticPass (log, SymTable {}) { } /*explicit*/ StaticPass::StaticPass(StatusLog& log, SymTable const& sym_table) : m_log { log } , m_sym { SymTable(sym_table) } { } /*virtual*/ StaticPass::~StaticPass() { } void StaticPass::check(std::shared_ptr root) { TypeResolver resolver {m_log}; assert(root); switch (root->type()) { case NODE_CONSTDECL: { check(root->child(1)); m_sym.declare(root->child(0)->repr(), root->child(1)); } break; case NODE_VARDECL: { check(root->child(1)); m_sym.declare_mut(root->child(0)->repr(), root->child(1)); } break; case NODE_ASSIGN: { auto const& entry = m_sym.find(root->child(0)->repr()); if (!entry.is_mut) { m_log.fatal(root->child(0)->loc(), root->child(0)->repr() + " is not mutable"); } auto lhs = resolver.find(entry.node, m_sym); auto rhs = resolver.find(root->child(1), m_sym); check_types(root, lhs, rhs); } break; case NODE_IDENT: case NODE_ASSERT_STATIC_FAIL: case NODE_INT: case NODE_BOOL: break; case NODE_EQ: case NODE_NE: { check_children(root); auto lhs = resolver.find(root->child(0), m_sym); auto rhs = resolver.find(root->child(1), m_sym); check_types(root, lhs, rhs); } break; case NODE_IMP: case NODE_OR: case NODE_AND: { check_children(root); auto lhs = resolver.find(root->child(0), m_sym); auto rhs = resolver.find(root->child(1), m_sym); check_types(root, lhs, std::make_shared(TY_BOOL)); check_types(root, lhs, rhs); } break; case NODE_ASSERT: case NODE_NOT: { check_children(root); auto lhs = resolver.find(root->child(0), m_sym); check_types(root, lhs, std::make_shared(TY_BOOL)); } break; case NODE_LT: case NODE_LE: case NODE_GT: case NODE_GE: case NODE_ADD: case NODE_SUB: case NODE_MUL: case NODE_DIV: case NODE_MOD: case NODE_POW: { check_children(root); auto lhs = resolver.find(root->child(0), m_sym); auto rhs = resolver.find(root->child(1), m_sym); check_types(root, lhs, std::make_shared(TY_INT)); check_types(root, lhs, rhs); } break; case NODE_UADD: case NODE_USUB: { check_children(root); auto lhs = resolver.find(root->child(0), m_sym); check_types(root, lhs, std::make_shared(TY_INT)); } break; case NODE_PROG: { check_children(root); } break; default: m_log.fatal(root->loc(), "cannot check node '" + root->string() + "'"); } } void StaticPass::check_children(std::shared_ptr root) { for (size_t i=0; isize(); i++) { check(root->child(i)); } } void StaticPass::check_types(std::shared_ptr root, std::shared_ptr lhs, std::shared_ptr rhs) { assert(lhs); assert(rhs); if (!lhs->equals(*rhs)) { m_log.fatal(root->loc(), std::string() + "type mismatch, expected '" + lhs->string() + "', got '" + rhs->string() + "'"); } } void StaticPass::check_types(std::shared_ptr root, std::shared_ptr lhs, std::vector> const& rhs) { for (auto const& ty: rhs) { if (lhs->equals(*ty)) { return; } } std::stringstream ss; ss << "type mismatch, got '" << lhs->string() << "'"; ss << "candidates are:" << std::endl; for (auto ty: rhs) { ss << "\t-> " << ty->string() << std::endl; } m_log.fatal(root->loc(), ss.str()); } }