Integrated Set type into existing infrastructure

This commit is contained in:
Robert Bendun 2022-11-24 18:35:51 +01:00
parent f19240d931
commit 948243febd
9 changed files with 102 additions and 64 deletions

View File

@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- `{}` notation for concurrently executing blocks
- `{}` notation for concurrently executing blocks and describing set of values
- `set` data type which contains an unordered collection of unique elements
### Fixed

View File

@ -5,61 +5,63 @@ WIP implemntation
oct 5, bpm 72, len (1/16),
subsection1 := (
sim (a4 en) (a2 e3 a3),
play (oct 4, c e a),
{ a4 en, a2 e3 a3 },
oct 4, c e a,
sim (b4 en) (e2 e3 g#3),
play (oct 4, e g# b),
{ b4 en, e2 e3 g#3 },
oct 4, e g# b,
sim (c5 en) (a2 e3 a3),
play (e4 e5 d#5),
{ c5 en, a2 e3 a3 },
e4 e5 d#5,
play e d# e b4 d c,
oct 5, e d# e b4 d c,
sim (a4 en) (a2 e3 a3),
play c4 e4 a4,
{ a4 en, a2 e3 a3 },
c4 e4 a4,
sim (b4 en) (e2 e3 g#3),
play d4 c5 b4,
{ b4 en, e2 e3 g#3 },
d4 c5 b4,
),
section1 := ( n |
play e d#,
play e d# e b4 d c,
e d#,
e d# e b4 d c,
call subsection1,
if (n == 1)
( sim (a4 qn) (a2 e3 a3) )
( sim (a4 en) (a2 e3 a3)
, play b4 c5 d5
{ a4 qn, a2 e3 a3 }
( { a4 en, a2 e3 a3 }
, b4 c5 d5
)
),
section2 := ( n |
sim (e5 den) (c3 g3 c4),
play g4 f e,
{ e5 den, c3 g3 c4 },
g4 f e,
sim (d 5 den) (g2 g3 b4),
play f4 e d,
{ d5 den, g2 g3 b4 },
f4 e d,
sim (c5 den) (a2 e3 a3),
play e4 d c,
{ c5 den, a2 e3 a3 },
e4 d c,
sim (b4 en) (e2 e3 e4),
play (e4 e5 e4 e4 e5 e6 d#5 e5 d#5 e5 en),
{ b4 en, e2 e3 e4 },
e4 e5 e4 e4 e5 e6 d#5 e5 d#5 e5 en,
play d# e d# e d#,
play e d# e b4 d c,
d# e d# e d#,
e d# e b4 d c,
call subsection1,
if (n == 1)
( sim (a4 en) (a2 e3 a3)
( { a4 en, a2 e3 a3 }
, play (b4 c5 d5)
)
),
section1 1,
section1 2,
section2 1,
play (
section1 1,
section1 2,
section2 1,
)

View File

@ -2,6 +2,7 @@
#define MUSIQUE_COMMON_HH
#include <cstdint>
#include <mutex>
#include <string>
#include <string_view>
@ -62,4 +63,6 @@ concept Three_Way_Comparable = requires (T const& lhs, T const& rhs) {
{ lhs <=> rhs };
};
extern std::mutex stdio_mutex;
#endif

View File

@ -49,20 +49,25 @@ std::optional<Error> Value_Formatter::format(std::ostream& os, Interpreter &inte
return {};
},
[&](Block const& block) -> std::optional<Error> {
if (block.body.arguments.front().type == Ast::Type::Concurrent)
unimplemented("Nice printing of concurrent blocks is not implemented yet");
if (block.is_collection()) {
os << '(';
auto const [open, close] = block.body.type == Ast::Type::Concurrent
? std::pair { '{', '}' }
: std::pair { '(', ')' };
os << open;
for (auto i = 0u; i < block.size(); ++i) {
if (i > 0) {
os << ", ";
}
Try(nest(Inside_Block).format(os, interpreter, Try(block.index(interpreter, i))));
}
os << ')';
os << close;
} else {
os << "<block>";
if (block.body.type == Ast::Type::Concurrent) {
os << "<concurrent block>";
} else {
os << "<sequential block>";
}
}
return {};
},

View File

@ -1,7 +1,8 @@
#include <musique/algo.hh>
#include <musique/interpreter/env.hh>
#include <musique/guard.hh>
#include <musique/interpreter/env.hh>
#include <musique/interpreter/interpreter.hh>
#include <musique/scope_exit.hh>
#include <musique/try.hh>
#include <chrono>
@ -12,6 +13,7 @@
#include <random>
#include <thread>
#include <unordered_set>
#include <future>
/// Check if type has index method
template<typename T>
@ -254,6 +256,19 @@ static inline std::optional<Error> sequential_play(Interpreter &interpreter, Val
}
else if (auto chord = get_if<Chord>(v)) {
return interpreter.play(*chord);
} else if (auto set = get_if<Set>(v)) {
std::vector<std::future<std::optional<Error>>> futures;
for (auto&& value : set->elements) {
futures.push_back(std::async(std::launch::async,
[interpreter = interpreter.clone(), value = std::move(value)]() mutable {
return sequential_play(interpreter, std::move(value));
}
));
}
for (auto &fut : futures) {
Try(fut.get());
}
}
return {};
@ -267,27 +282,25 @@ static std::optional<Error> action_play(Interpreter &interpreter, Value v)
}
/// Play notes
template<With_Index_Operator Container = std::vector<Value>>
static inline Result<Value> builtin_play(Interpreter &interpreter, Container args)
static inline Result<Value> builtin_play(Interpreter &interpreter, std::span<Ast> args)
{
Try(ensure_midi_connection_available(interpreter, "play"));
auto const previous_action = std::exchange(interpreter.default_action, action_play);
auto const previous_context = std::exchange(interpreter.current_context,
std::make_shared<Context>(*interpreter.current_context));
auto const finally = [&] {
Scope_Exit {
interpreter.default_action = std::move(previous_action);
interpreter.current_context = previous_context;
};
for (auto &el : args) {
if (std::optional<Error> error = sequential_play(interpreter, std::move(el))) {
finally();
for (auto &node : args) {
auto value = Try(interpreter.eval((Ast)node));
if (std::optional<Error> error = sequential_play(interpreter, std::move(value))) {
return *std::move(error);
}
}
finally();
return {};
}
@ -316,14 +329,15 @@ static Result<Value> builtin_par(Interpreter &interpreter, std::vector<Value> ar
}
}
auto result = builtin_play(interpreter, std::span(args).subspan(1));
unimplemented();
// auto result = builtin_play(interpreter, std::span(args).subspan(1));
for (auto const& note : chord->notes) {
if (note.base) {
interpreter.midi_connection->send_note_off(0, *note.into_midi_note(), 127);
}
}
return result;
// for (auto const& note : chord->notes) {
// if (note.base) {
// interpreter.midi_connection->send_note_off(0, *note.into_midi_note(), 127);
// }
// }
// return result;
}
/// Plays each argument simultaneously

View File

@ -1,5 +1,6 @@
#include <musique/interpreter/env.hh>
#include <musique/interpreter/interpreter.hh>
#include <musique/options.hh>
#include <musique/try.hh>
#include <chrono>
@ -97,14 +98,14 @@ static Result<Value> eval_concurrent(Interpreter &interpreter, Ast &&ast)
}));
}
std::vector<Value> results;
Set set;
for (auto& future : futures) {
if (error) {
return *error;
}
results.push_back(future.get());
set.elements.insert(future.get());
}
return results;
return set;
}
Result<Value> Interpreter::eval(Ast &&ast)
@ -288,6 +289,11 @@ void Interpreter::leave_scope()
std::optional<Error> Interpreter::play(Chord chord)
{
if (global_options::dump_play_actions) {
std::lock_guard guard{stdio_mutex};
std::cerr << "[DEBUG] Interpreter::play " << chord << std::endl;
}
Try(ensure_midi_connection_available(*this, "play"));
auto &ctx = *current_context;

View File

@ -35,15 +35,16 @@ private:
Interpreter(Clone);
public:
/// Explicit clone method
Interpreter clone() const;
/// Try to evaluate given program tree
Result<Value> eval(Ast &&ast);
// Enter scope by changing current environment
/// Enter scope by changing current environment
void enter_scope();
// Leave scope by changing current environment
/// Leave scope by changing current environment
void leave_scope();
/// Play note resolving any missing parameters with context via `midi_connection` member.

View File

@ -37,6 +37,8 @@ static bool ast_only_mode = false;
static bool enable_repl = false;
static unsigned repl_line_number = 1;
std::mutex stdio_mutex;
#define Ignore(Call) do { auto const ignore_ ## __LINE__ = (Call); (void) ignore_ ## __LINE__; } while(0)
/// Pop string from front of an array
@ -190,7 +192,6 @@ struct Runner
}
Env::global->force_define("print", +[](Interpreter &interpreter, std::vector<Value> args) -> Result<Value> {
static std::mutex stdio_mutex;
for (auto it = args.begin(); it != args.end(); ++it) {
{
auto result = Try(format(interpreter, *it));

View File

@ -4,6 +4,11 @@
#include <musique/value/block.hh>
#include <musique/value/value.hh>
inline bool is_ast_collection(Ast::Type type)
{
return type == Ast::Type::Sequence || type == Ast::Type::Concurrent;
}
/// Helper that produces error when trying to access container with too few elements for given index
static inline std::optional<Error> guard_index(unsigned index, unsigned size)
{
@ -17,18 +22,18 @@ static inline std::optional<Error> guard_index(unsigned index, unsigned size)
Result<Value> Block::index(Interpreter &i, unsigned position) const
{
ensure(parameters.empty(), "cannot index into block with parameters (for now)");
if (body.type != Ast::Type::Sequence) {
Try(guard_index(position, 1));
return i.eval((Ast)body);
if (is_ast_collection(body.type)) {
Try(guard_index(position, body.arguments.size()));
return i.eval((Ast)body.arguments[position]);
}
Try(guard_index(position, body.arguments.size()));
return i.eval((Ast)body.arguments[position]);
Try(guard_index(position, 1));
return i.eval((Ast)body);
}
usize Block::size() const
{
return body.type == Ast::Type::Sequence ? body.arguments.size() : 1;
return is_ast_collection(body.type) ? body.arguments.size() : 1;
}
Result<Value> Block::operator()(Interpreter &i, std::vector<Value> arguments) const