muzgen/lib/Compiler.cpp

115 lines
2.5 KiB
C++

#include "Compiler.hpp"
#include "Constant.hpp"
#include "Sine.hpp"
namespace muz
{
/*explicit*/ Compiler::Compiler(AudioConf const& conf)
: m_conf { conf }
{
}
/*virtual*/ Compiler::~Compiler()
{
}
std::vector<std::unique_ptr<Signal>>
Compiler::compile(std::shared_ptr<Node> node)
{
compile_node(node);
return std::move(m_outputs);
}
void Compiler::compile_node(std::shared_ptr<Node> node)
{
switch (node->type())
{
case NODE_NUM: {
float value = std::stof(node->value());
push(std::make_unique<Constant>(m_conf, value));
} break;
case NODE_CMD: {
std::string name = node->child(0)->value();
for (size_t i=1; i<node->size(); i++)
{
compile_node(node->child(i));
}
if (name == "sine")
{
check_cmd_arity(*node, 2);
auto one = pop();
auto signal = std::make_unique<Sine>(m_conf,
std::move(pop()),
std::move(one));
push(std::move(signal));
}
else
{
throw compile_error {
std::string()
+ "cannot compile unknown command '" + name + "'."
};
}
} break;
case NODE_DIR: {
std::string name = node->child(0)->value();
if (name == "@out")
{
compile_node(node->child(1));
m_outputs.push_back(std::move(pop()));
}
else
{
throw compile_error {
std::string()
+ "cannot compile unknown directive '" + name + "'."
};
}
} break;
default:
for (size_t i=0; i<node->size(); i++)
{
compile_node(node->child(i));
}
break;
}
}
void Compiler::push(std::unique_ptr<Signal> signal)
{
m_signals.push_back(std::move(signal));
}
std::unique_ptr<Signal> Compiler::pop()
{
auto signal = std::move(m_signals.back());
m_signals.pop_back();
return signal;
}
void Compiler::check_cmd_arity(Node const& node, int arity)
{
if (node.size() - 1 != arity)
{
throw compile_error {
std::string()
+ "arity mismatch for '"
+ node.child(0)->value()
+ "': expected <"
+ std::to_string(arity)
+ ">, got <"
+ std::to_string(node.size() - 1)
+ ">."};
}
}
}