#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> 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 { format_error(node->line(), "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 if (name == "add") { check_cmd_arity(*node, 2); auto rhs = pop(); auto lhs = pop(); auto signal = std::make_unique(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(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(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
(m_conf, std::move(lhs), std::move(rhs)); push(std::move(signal)); } else { format_error(node->line(), "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)) { format_error(node.line(), "arity mismatch for '" + node.child(0)->value() + "': expected <" + std::to_string(arity) + ">, got <" + std::to_string(node.size() - 1) + ">."); } } }