#include "Compiler.hpp" #include "lib/Node.hpp" #include "lib/TypeResolver.hpp" #include "lib/opcodes.hpp" #include "StaticPass.hpp" namespace roza { /*explicit*/ Compiler::Compiler(StatusLog& log) : m_log { log } { } /*virtual*/ Compiler::~Compiler() { } std::shared_ptr Compiler::compile(std::shared_ptr root, std::shared_ptr sym) { auto program = std::make_shared(); compile_node(root, program, sym); return program; } void Compiler::compile_node(std::shared_ptr root, std::shared_ptr prog, std::shared_ptr sym) { switch (root->type()) { case NODE_FUN: { auto params = root->child(0); auto ret = root->child(1); auto body = root->child(2); TypeResolver resolver {m_log}; auto ty = resolver.find(root, *sym); auto fun = std::make_shared(ty); for (size_t i=0; isize(); i++) { auto param = params->child(i); std::string name = param->child(0)->repr(); auto node = param->child(1); fun->sym()->declare_mut(name, node); } m_fun_stack.push_back(fun); compile_node(body, fun->program(), fun->sym()); m_fun_stack.pop_back(); auto value = std::make_shared(fun, root->loc()); prog->push_instr(OP_PUSH_CONST, prog->push_value(value)); } break; case NODE_RETURN: { compile_node(root->child(0), prog, sym); prog->push_instr(OP_RET); } break; case NODE_CALL: { auto fun_addr = sym->find(root->child(0)->repr()).addr; prog->push_instr(OP_PUSH_CONST, fun_addr); compile_children(root->child(1), prog, sym); prog->push_instr(OP_CALL, root->child(1)->size()); } break; case NODE_IF: { sym->enter_scope(); std::vector to_end; std::function)> f = [&](std::shared_ptr n){ auto cond = n->child(0); auto then = n->child(1); compile_node(cond, prog, sym); size_t cond_addr = prog->size(); prog->push_instr(OP_BRF, 0); compile_node(then, prog, sym); to_end.push_back(prog->size()); prog->push_instr(OP_BR, 0); prog->set_param(cond_addr, prog->size()); if (n->size() > 2) { auto next = n->child(2); compile_node(next, prog, sym); } }; f(root); for (auto addr: to_end) { prog->set_param(addr, prog->size()); } sym->leave_scope(); } break; case NODE_BODY: case NODE_ELSE: case NODE_THEN: { compile_children(root, prog, sym); } break; case NODE_ASSERT: { compile_children(root, prog, sym); prog->push_instr(OP_ASSERT); } break; case NODE_ASSERT_STATIC_FAIL: { bool failed = false; try { StaticPass static_pass {m_log, *sym}; static_pass.check_children(root); compile_children(root, prog, sym); failed = true; } catch(...) { } if (failed) { m_log.fatal(root->loc(), "static assertion failed"); } } break; case NODE_IDENT: { SymEntry const& entry = sym->find(root->repr()); if (m_fun_stack.empty()) { prog->push_instr(OP_LOAD_GLOBAL, entry.addr); } else { prog->push_instr(OP_LOAD_LOCAL, entry.addr); } } break; case NODE_VARDECL: { std::string name = root->child(0)->repr(); compile_node(root->child(1), prog, sym); int addr = sym->declare_mut(name, root->child(1)); if (m_fun_stack.empty()) { prog->push_instr(OP_STORE_GLOBAL, addr); } else { prog->push_instr(OP_STORE_LOCAL, addr); } } break; case NODE_CONSTDECL: { std::string name = root->child(0)->repr(); compile_node(root->child(1), prog, sym); int addr = sym->declare(name, root->child(1)); if (m_fun_stack.empty()) { prog->push_instr(OP_STORE_GLOBAL, addr); } else { prog->push_instr(OP_STORE_LOCAL, addr); } } break; case NODE_ASSIGN: { int addr = sym->find(root->child(0)->repr()).addr; compile_node(root->child(1), prog, sym); if (m_fun_stack.empty()) { prog->push_instr(OP_STORE_GLOBAL, addr); } else { prog->push_instr(OP_STORE_LOCAL, addr); } } break; case NODE_INT: { auto value = std::make_shared(std::stoi(root->repr()), root->loc()); prog->push_instr(OP_PUSH_CONST, prog->push_value(value)); } break; case NODE_BOOL: { auto value = std::make_shared(root->repr() == "true", root->loc()); prog->push_instr(OP_PUSH_CONST, prog->push_value(value)); } break; case NODE_EQ: { compile_children(root, prog, sym); prog->push_instr(OP_EQ); } break; case NODE_NE: { compile_children(root, prog, sym); prog->push_instr(OP_EQ); prog->push_instr(OP_NOT); } break; case NODE_LT: { compile_children(root, prog, sym); prog->push_instr(OP_ILT); } break; case NODE_GT: { compile_children(root, prog, sym); prog->push_instr(OP_IGT); } break; case NODE_LE: { compile_children(root, prog, sym); prog->push_instr(OP_IGT); prog->push_instr(OP_NOT); } break; case NODE_GE: { compile_children(root, prog, sym); prog->push_instr(OP_ILT); prog->push_instr(OP_NOT); } break; case NODE_IMP: { compile_children(root, prog, sym); prog->push_instr(OP_IMP); } break; case NODE_AND: { compile_children(root, prog, sym); prog->push_instr(OP_AND); } break; case NODE_OR: { compile_children(root, prog, sym); prog->push_instr(OP_OR); } break; case NODE_NOT: { compile_children(root, prog, sym); prog->push_instr(OP_NOT); } break; case NODE_ADD: { compile_children(root, prog, sym); prog->push_instr(OP_IADD); } break; case NODE_SUB: { compile_children(root, prog, sym); prog->push_instr(OP_ISUB); } break; case NODE_MUL: { compile_children(root, prog, sym); prog->push_instr(OP_IMUL); } break; case NODE_DIV: { compile_children(root, prog, sym); prog->push_instr(OP_IDIV); } break; case NODE_MOD: { compile_children(root, prog, sym); prog->push_instr(OP_IMOD); } break; case NODE_POW: { compile_children(root, prog, sym); prog->push_instr(OP_IPOW); } break; case NODE_UADD: { compile_children(root, prog, sym); prog->push_instr(OP_IUADD); } break; case NODE_USUB: { compile_children(root, prog, sym); prog->push_instr(OP_IUSUB); } break; case NODE_PROG: { compile_children(root, prog, sym); } break; default: m_log.fatal(root->loc(), "cannot compile node '" + root->string() + "'."); } } void Compiler::compile_children(std::shared_ptr root, std::shared_ptr prog, std::shared_ptr sym) { for (size_t i=0; isize(); i++) { compile_node(root->child(i), prog, sym); } } }