muzgen/lib/Compiler.cpp

184 lines
4.5 KiB
C++

#include "Compiler.hpp"
// signals
// -------
#include "Constant.hpp"
#include "Sine.hpp"
#include "Noise.hpp"
#include "Add.hpp"
#include "Sub.hpp"
#include "Mul.hpp"
#include "Div.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));
}
execute_cmd(name, node);
} 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
{
format_error<compile_error>(node->line(),
"cannot compile unknown directive '"
+ name
+ "'.");
}
} break;
default:
for (size_t i=0; i<node->size(); i++)
{
compile_node(node->child(i));
}
break;
}
}
void Compiler::execute_cmd(std::string const& name,
std::shared_ptr<Node> node)
{
if (name == "sine")
{
check_cmd_arity(*node, 2);
auto one = pop();
auto signal = std::make_unique<Sine>(m_conf,
pop(),
std::move(one));
push(std::move(signal));
}
else if (name == "noise")
{
check_cmd_arity(*node, 0);
auto signal = std::make_unique<Noise>(m_conf);
push(std::move(signal));
}
else if (name == "add")
{
check_cmd_arity(*node, 2);
auto rhs = pop();
auto lhs = pop();
auto signal = std::make_unique<Add>(m_conf,
std::move(lhs),
std::move(rhs));
push(std::move(signal));
}
else if (name == "sub")
{
check_cmd_arity(*node, 2);
auto rhs = pop();
auto lhs = pop();
auto signal = std::make_unique<Sub>(m_conf,
std::move(lhs),
std::move(rhs));
push(std::move(signal));
}
else if (name == "mul")
{
check_cmd_arity(*node, 2);
auto rhs = pop();
auto lhs = pop();
auto signal = std::make_unique<Mul>(m_conf,
std::move(lhs),
std::move(rhs));
push(std::move(signal));
}
else if (name == "div")
{
check_cmd_arity(*node, 2);
auto rhs = pop();
auto lhs = pop();
auto signal = std::make_unique<Div>(m_conf,
std::move(lhs),
std::move(rhs));
push(std::move(signal));
}
else
{
format_error<compile_error>(node->line(),
"cannot compile unknown command '"
+ name
+ "'.");
}
}
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 != static_cast<size_t>(arity))
{
format_error<compile_error>(node.line(),
"arity mismatch for '"
+ node.child(0)->value()
+ "': expected <"
+ std::to_string(arity)
+ ">, got <"
+ std::to_string(node.size() - 1)
+ ">.");
}
}
}