#include "Compiler.hpp" // signals // ------- #include "Constant.hpp" #include "Sine.hpp" #include "Noise.hpp" namespace muz { /*explicit*/ Compiler::Compiler(AudioConf const& conf) : m_conf { conf } { } /*virtual*/ Compiler::~Compiler() { } std::vector> Compiler::compile(std::shared_ptr node) { compile_node(node); return std::move(m_outputs); } void Compiler::compile_node(std::shared_ptr node) { switch (node->type()) { case NODE_NUM: { float value = std::stof(node->value()); push(std::make_unique(m_conf, value)); } break; case NODE_CMD: { std::string name = node->child(0)->value(); for (size_t i=1; isize(); 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 { throw compile_error { std::string() + "cannot compile unknown directive '" + name + "'." }; } } break; default: for (size_t i=0; isize(); i++) { compile_node(node->child(i)); } break; } } void Compiler::execute_cmd(std::string const& name, std::shared_ptr node) { if (name == "sine") { check_cmd_arity(*node, 2); auto one = pop(); auto signal = std::make_unique(m_conf, pop(), std::move(one)); push(std::move(signal)); } else if (name == "noise") { check_cmd_arity(*node, 0); auto signal = std::make_unique(m_conf); push(std::move(signal)); } else { throw compile_error { std::string() + "cannot compile unknown command '" + name + "'." }; } } void Compiler::push(std::unique_ptr signal) { m_signals.push_back(std::move(signal)); } std::unique_ptr 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(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) + ">."}; } } }