115 lines
2.5 KiB
C++
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 != static_cast<size_t>(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)
|
|
+ ">."};
|
|
}
|
|
}
|
|
}
|