2023-08-30 18:06:26 +00:00
|
|
|
#include "StaticPass.hpp"
|
|
|
|
#include "lib/Node.hpp"
|
2023-08-30 22:31:19 +00:00
|
|
|
#include "TypeResolver.hpp"
|
2023-08-30 18:06:26 +00:00
|
|
|
|
|
|
|
namespace roza
|
|
|
|
{
|
|
|
|
/*explicit*/ StaticPass::StaticPass(StatusLog& log)
|
2023-08-31 19:25:00 +00:00
|
|
|
: StaticPass (log, SymTable {})
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/*explicit*/ StaticPass::StaticPass(StatusLog& log, SymTable const& sym_table)
|
2023-08-30 18:06:26 +00:00
|
|
|
: m_log { log }
|
2023-08-31 19:25:00 +00:00
|
|
|
, m_sym { SymTable(sym_table) }
|
2023-08-30 18:06:26 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/*virtual*/ StaticPass::~StaticPass()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void StaticPass::check(std::shared_ptr<Node> root)
|
|
|
|
{
|
2023-08-30 22:31:19 +00:00
|
|
|
TypeResolver resolver {m_log};
|
2023-08-31 19:25:00 +00:00
|
|
|
assert(root);
|
2023-08-30 22:31:19 +00:00
|
|
|
|
2023-08-30 18:06:26 +00:00
|
|
|
switch (root->type())
|
|
|
|
{
|
2023-09-01 20:38:12 +00:00
|
|
|
case NODE_FUN: {
|
|
|
|
//SymTable fun_sym;
|
|
|
|
//StaticPass pass {m_log, fun_sym};
|
|
|
|
m_sym.enter_scope();
|
|
|
|
auto params = root->child(0);
|
|
|
|
|
|
|
|
for (size_t i=0; i<params->size(); i++)
|
|
|
|
{
|
|
|
|
auto name = params->child(i)->child(0)->repr();
|
|
|
|
auto node = params->child(i)->child(1);
|
|
|
|
|
|
|
|
m_sym.declare_mut(name, node);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_outer_fun_ret = root->child(1)->child(0);
|
|
|
|
check(root->child(2)->child(0));
|
|
|
|
m_outer_fun_ret = nullptr;
|
|
|
|
m_sym.leave_scope();
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_RETURN: {
|
|
|
|
check_children(root);
|
|
|
|
|
|
|
|
auto actual_ty = resolver.find(root->child(0), m_sym);
|
|
|
|
auto fun_ty = resolver.find(m_outer_fun_ret, m_sym);
|
|
|
|
|
|
|
|
check_types(root, fun_ty, actual_ty);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_CALL: {
|
|
|
|
check_children(root);
|
|
|
|
|
|
|
|
std::string fname = root->child(0)->repr();
|
|
|
|
auto args = root->child(1);
|
|
|
|
auto entry = m_sym.find(fname);
|
|
|
|
auto params = entry.node->child(0);
|
|
|
|
|
|
|
|
if (args->size() != params->size())
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << "function '"<< fname << "' expects " << params->size();
|
|
|
|
ss << " arguments,";
|
|
|
|
ss << " got " << args->size();
|
|
|
|
|
|
|
|
m_log.fatal(root->loc(), ss.str());
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i=0; i<args->size(); i++)
|
|
|
|
{
|
|
|
|
auto arg = args->child(i);
|
|
|
|
auto param = params->child(i);
|
|
|
|
|
|
|
|
auto arg_ty = resolver.find(arg, m_sym);
|
|
|
|
auto param_ty = resolver.find(param->child(1), m_sym);
|
|
|
|
|
|
|
|
check_types(root, param_ty, arg_ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
} break;
|
|
|
|
|
2023-08-31 23:22:51 +00:00
|
|
|
case NODE_IF: {
|
|
|
|
m_sym.enter_scope();
|
|
|
|
auto cond_type = resolver.find(root->child(0), m_sym);
|
|
|
|
check_types(root, std::make_shared<Type>(TY_BOOL), cond_type);
|
|
|
|
check_children(root);
|
|
|
|
m_sym.leave_scope();
|
|
|
|
} break;
|
|
|
|
|
2023-09-01 20:38:12 +00:00
|
|
|
case NODE_ARGS:
|
2023-08-31 23:22:51 +00:00
|
|
|
case NODE_THEN:
|
|
|
|
case NODE_ELSE: {
|
|
|
|
check_children(root);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
2023-08-31 19:25:00 +00:00
|
|
|
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:
|
2023-08-31 12:41:43 +00:00
|
|
|
case NODE_ASSERT_STATIC_FAIL:
|
2023-08-31 09:07:03 +00:00
|
|
|
case NODE_INT:
|
|
|
|
case NODE_BOOL:
|
|
|
|
break;
|
|
|
|
|
2023-08-31 09:37:13 +00:00
|
|
|
case NODE_EQ:
|
|
|
|
case NODE_NE: {
|
|
|
|
check_children(root);
|
2023-08-31 19:25:00 +00:00
|
|
|
auto lhs = resolver.find(root->child(0), m_sym);
|
|
|
|
auto rhs = resolver.find(root->child(1), m_sym);
|
2023-08-31 09:37:13 +00:00
|
|
|
check_types(root, lhs, rhs);
|
|
|
|
} break;
|
|
|
|
|
2023-08-31 09:07:03 +00:00
|
|
|
case NODE_IMP:
|
|
|
|
case NODE_OR:
|
|
|
|
case NODE_AND: {
|
|
|
|
check_children(root);
|
2023-08-31 19:25:00 +00:00
|
|
|
auto lhs = resolver.find(root->child(0), m_sym);
|
|
|
|
auto rhs = resolver.find(root->child(1), m_sym);
|
2023-08-31 09:07:03 +00:00
|
|
|
check_types(root, lhs, std::make_shared<Type>(TY_BOOL));
|
|
|
|
check_types(root, lhs, rhs);
|
|
|
|
} break;
|
|
|
|
|
2023-08-31 12:41:43 +00:00
|
|
|
case NODE_ASSERT:
|
2023-08-31 09:07:03 +00:00
|
|
|
case NODE_NOT: {
|
|
|
|
check_children(root);
|
2023-08-31 19:25:00 +00:00
|
|
|
auto lhs = resolver.find(root->child(0), m_sym);
|
2023-08-31 09:07:03 +00:00
|
|
|
check_types(root, lhs, std::make_shared<Type>(TY_BOOL));
|
|
|
|
} break;
|
2023-08-30 18:06:26 +00:00
|
|
|
|
2023-08-31 09:37:13 +00:00
|
|
|
case NODE_LT:
|
|
|
|
case NODE_LE:
|
|
|
|
case NODE_GT:
|
|
|
|
case NODE_GE:
|
2023-08-30 22:31:19 +00:00
|
|
|
case NODE_ADD:
|
|
|
|
case NODE_SUB:
|
|
|
|
case NODE_MUL:
|
|
|
|
case NODE_DIV:
|
|
|
|
case NODE_MOD:
|
|
|
|
case NODE_POW: {
|
2023-08-31 09:07:03 +00:00
|
|
|
check_children(root);
|
2023-08-31 19:25:00 +00:00
|
|
|
auto lhs = resolver.find(root->child(0), m_sym);
|
|
|
|
auto rhs = resolver.find(root->child(1), m_sym);
|
|
|
|
|
2023-08-31 09:07:03 +00:00
|
|
|
check_types(root, lhs, std::make_shared<Type>(TY_INT));
|
|
|
|
check_types(root, lhs, rhs);
|
2023-08-30 22:31:19 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_UADD:
|
|
|
|
case NODE_USUB: {
|
2023-08-31 09:07:03 +00:00
|
|
|
check_children(root);
|
2023-08-31 19:25:00 +00:00
|
|
|
auto lhs = resolver.find(root->child(0), m_sym);
|
2023-08-31 12:41:43 +00:00
|
|
|
check_types(root, lhs, std::make_shared<Type>(TY_INT));
|
2023-08-30 22:31:19 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case NODE_PROG: {
|
2023-08-31 09:07:03 +00:00
|
|
|
check_children(root);
|
2023-08-30 18:06:26 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
m_log.fatal(root->loc(), "cannot check node '" + root->string() + "'");
|
|
|
|
}
|
|
|
|
}
|
2023-08-31 09:07:03 +00:00
|
|
|
|
|
|
|
void StaticPass::check_children(std::shared_ptr<Node> root)
|
|
|
|
{
|
|
|
|
for (size_t i=0; i<root->size(); i++)
|
|
|
|
{
|
|
|
|
check(root->child(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void StaticPass::check_types(std::shared_ptr<Node> root,
|
|
|
|
std::shared_ptr<Type> lhs,
|
|
|
|
std::shared_ptr<Type> rhs)
|
|
|
|
{
|
2023-08-31 19:25:00 +00:00
|
|
|
assert(lhs);
|
|
|
|
assert(rhs);
|
|
|
|
|
2023-08-31 09:07:03 +00:00
|
|
|
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<Node> root,
|
|
|
|
std::shared_ptr<Type> lhs,
|
|
|
|
std::vector<std::shared_ptr<Type>> 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());
|
|
|
|
}
|
|
|
|
|
2023-08-30 18:06:26 +00:00
|
|
|
}
|