#include "Compiler.hpp" #include "lib/Opcodes.hpp" #include "Code.hpp" namespace jk { /*explicit*/ Compiler::Compiler(Logger& logger) : m_logger(logger) { } /*virtual*/ Compiler::~Compiler() { } void Compiler::compile(std::shared_ptr node, std::shared_ptr program, std::shared_ptr sym) { switch (node->type()) { case NODE_PROG: case NODE_BODY: { for (size_t i=0; isize(); i++) { compile(node->child(i).lock(), program, sym); } } break; case NODE_FUNCALL: { for (size_t i=0; isize(); i++) { compile(node->child(i).lock(), program, sym); } program->push_instr(OPCODE_CALL, node->size() - 1); } break; case NODE_VARDECL: { std::string ident = node->child(0).lock()->repr(); auto entry = sym->find(ident); assert(entry); compile(node->child(1).lock(), program, sym); program->push_instr(OPCODE_STORE, entry->addr); } break; case NODE_LAMBDA: { auto params = node->child(0).lock(); auto body = node->child(1).lock(); auto prog = std::make_shared(); auto fun_sym = std::make_shared(m_logger, sym); for (size_t i=0; isize(); i++) { std::string param = params->child(i).lock()->repr(); fun_sym->declare(param, std::make_shared(TYPE_NIL), node->loc()); } compile(body, prog, fun_sym); prog->push_instr(OPCODE_RET); auto code = std::make_shared(prog); size_t addr = program->push_constant(Value::make_code(code)); program->push_instr(OPCODE_PUSH_CONST, addr); program->push_instr(OPCODE_MK_FUNCTION); } break; case NODE_IDENT: { std::string ident = node->repr(); auto mysym = sym->find(ident); assert(sym); OpcodeType op_load = OPCODE_LOAD; if (mysym->is_global) { op_load = OPCODE_LOAD_GLOBAL; } program->push_instr(op_load, mysym->addr); } break; case NODE_INT: { auto value = Value::make_int(std::stoi(node->repr())); size_t addr = program->push_constant(value); program->push_instr(OPCODE_PUSH_CONST, addr); } break; case NODE_BOOL: { auto value = Value::make_bool(node->repr() == "true"); size_t addr = program->push_constant(value); program->push_instr(OPCODE_PUSH_CONST, addr); } break; default: std::cerr << "cannot compile unknown node '" << NodeTypeStr[node->type()] << "'" << std::endl; abort(); } } }