193 lines
5.4 KiB
C++
193 lines
5.4 KiB
C++
#include "Compiler.hpp"
|
|
#include "Lambda.hpp"
|
|
|
|
namespace fk
|
|
{
|
|
/*explicit*/ Compiler::Compiler(std::shared_ptr<SymTable> sym)
|
|
: m_sym { sym }
|
|
{
|
|
}
|
|
|
|
/*virtual*/ Compiler::~Compiler()
|
|
{
|
|
}
|
|
|
|
void Compiler::add_macro(std::string const& name,
|
|
std::shared_ptr<NativeMacro> macro)
|
|
{
|
|
m_macros[name] = macro;
|
|
}
|
|
|
|
std::shared_ptr<Program> Compiler::compile(std::shared_ptr<Node> node)
|
|
{
|
|
auto prog = std::make_shared<Program>();
|
|
compile_prog(node, prog);
|
|
return prog;
|
|
}
|
|
|
|
void Compiler::compile_prog(std::shared_ptr<Node> node,
|
|
std::shared_ptr<Program> prog)
|
|
{
|
|
switch (node->type())
|
|
{
|
|
case NODE_MODULE: {
|
|
for (size_t i=0; i<node->size(); i++)
|
|
{
|
|
compile_prog(node->child(i), prog);
|
|
prog->add(OP_POP);
|
|
}
|
|
} break;
|
|
|
|
case NODE_BODY: {
|
|
for (size_t i=0; i<node->size(); i++)
|
|
{
|
|
compile_prog(node->child(i), prog);
|
|
|
|
if (i != node->size() - 1)
|
|
{
|
|
prog->add(OP_POP);
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case NODE_LAMBDA: {
|
|
auto params = node->child(0);
|
|
auto body = node->child(1);
|
|
|
|
m_sym->enter_scope(node);
|
|
|
|
for (size_t i=0; i<params->size(); i++)
|
|
{
|
|
std::string ident = params->child(i)->repr();
|
|
m_sym->declare_local(ident, i, node->loc());
|
|
}
|
|
|
|
Compiler compiler {m_sym};
|
|
for (auto e: m_macros)
|
|
{
|
|
compiler.add_macro(e.first, e.second);
|
|
}
|
|
|
|
auto program = compiler.compile(body);
|
|
program->add(OP_RET);
|
|
|
|
m_sym->leave_scope();
|
|
|
|
auto constant = std::make_shared<Constant>(TYPE_PROGRAM,
|
|
program,
|
|
node->loc());
|
|
prog->load_const(constant);
|
|
prog->add(OP_MAKE_FUNCTION, params->size());
|
|
} break;
|
|
|
|
case NODE_CALL: {
|
|
std::string ident = node->child(0)->repr();
|
|
|
|
if (auto itr=m_macros.find(ident);
|
|
itr != std::end(m_macros))
|
|
{
|
|
auto macro = itr->second;
|
|
macro->call(*this, node, prog);
|
|
}
|
|
else
|
|
{
|
|
for (size_t i=0; i<node->size(); i++)
|
|
{
|
|
compile_prog(node->child(i), prog);
|
|
}
|
|
|
|
if (node->child(0)->type() == NODE_LAMBDA
|
|
|| node->child(0)->type() == NODE_CALL)
|
|
{
|
|
prog->add(OP_CALL_REF, node->size() - 1);
|
|
}
|
|
else if (node->child(0)->type() == NODE_IDENT)
|
|
{
|
|
if (auto entry = m_sym->find(node->child(0)->repr());
|
|
entry && entry->is_global() == false)
|
|
{
|
|
size_t arity = entry->node()->child(0)->size();
|
|
if (arity != node->size() - 1)
|
|
{
|
|
std::stringstream ss;
|
|
ss << "arity mismatch: " << node->child(0)->repr()
|
|
<< " expect '"
|
|
<< arity
|
|
<< "' arguments, got '"
|
|
<< node->size() - 1
|
|
<< "'";
|
|
|
|
node->loc().error<compile_error>(LOG_ERROR, ss.str());
|
|
}
|
|
|
|
prog->add(OP_CALL_REF, node->size() - 1);
|
|
}
|
|
else
|
|
{
|
|
prog->add(OP_CALL_NATIVE, node->size() - 1);
|
|
}
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case NODE_IDENT: {
|
|
auto entry = m_sym->find(node->repr());
|
|
|
|
if (!entry)
|
|
{
|
|
std::stringstream ss;
|
|
ss << "'"
|
|
<< node->repr()
|
|
<< "' is undefined";
|
|
|
|
node->loc().error<compile_error>(LOG_ERROR, ss.str());
|
|
}
|
|
|
|
if (!entry->is_global())
|
|
{
|
|
prog->add(OP_LOAD_LOCAL, entry->addr());
|
|
}
|
|
else
|
|
{
|
|
prog->add(OP_LOAD_GLOBAL, entry->addr());
|
|
}
|
|
|
|
} break;
|
|
|
|
case NODE_INT: {
|
|
prog->load_const(std::make_shared<Constant>(TYPE_INT,
|
|
stoi(node->repr()),
|
|
node->loc()));
|
|
} break;
|
|
|
|
case NODE_FLOAT: {
|
|
prog->load_const(std::make_shared<Constant>(TYPE_FLOAT,
|
|
stof(node->repr()),
|
|
node->loc()));
|
|
} break;
|
|
|
|
case NODE_BOOL: {
|
|
prog->load_const(std::make_shared<Constant>(TYPE_BOOL,
|
|
node->repr() == "true",
|
|
node->loc()));
|
|
} break;
|
|
|
|
case NODE_STRING: {
|
|
std::string str = node->repr();
|
|
prog->load_const(std::make_shared<Constant>(TYPE_STRING,
|
|
str.substr(1, str.size() - 2),
|
|
node->loc()));
|
|
} break;
|
|
|
|
default: {
|
|
std::stringstream ss;
|
|
ss << "cannot compile expression '"
|
|
<< (NodeTypeStr[node->type()] + strlen("NODE_"))
|
|
<< "'";
|
|
|
|
node->loc().error<compile_error>(LOG_ERROR, ss.str());
|
|
} break;
|
|
}
|
|
}
|
|
}
|