From 7f73f3dcad4e8623d8f62802dfa8febad7579c68 Mon Sep 17 00:00:00 2001 From: Robert Bendun Date: Mon, 21 Nov 2022 17:03:14 +0100 Subject: [PATCH] Made context stack a tree; fixed function name in error printing --- CHANGELOG.md | 8 ++++ musique/errors.hh | 2 +- musique/interpreter/builtin_functions.cc | 53 ++++++++++++------------ musique/interpreter/context.hh | 3 ++ musique/interpreter/interpreter.cc | 9 ++-- musique/interpreter/interpreter.hh | 8 ++-- scripts/release | 3 +- 7 files changed, 51 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84f71e8..e971d6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- release build script was producing executable with wrong path +- `examples/for-elise.mq` had bug in it +- in error reporting printing garbage instead of function name was fixed + +## [0.3.0] + ### Added - new builtins: map, while, set_len, set_oct, duration, pick diff --git a/musique/errors.hh b/musique/errors.hh index 7c481b2..90c9dfe 100644 --- a/musique/errors.hh +++ b/musique/errors.hh @@ -97,7 +97,7 @@ namespace errors enum Type { Operator, Function } type; /// Name of operation - std::string_view name; + std::string name; /// Possible ways to use it correctly std::vector possibilities; diff --git a/musique/interpreter/builtin_functions.cc b/musique/interpreter/builtin_functions.cc index 1433103..d92d5d0 100644 --- a/musique/interpreter/builtin_functions.cc +++ b/musique/interpreter/builtin_functions.cc @@ -87,15 +87,15 @@ static Result ctx_read_write_property(Interpreter &interpreter, std::vect using Member_Type = std::remove_cvref_t().*(Mem_Ptr))>; if (args.size() == 0) { - return Number(interpreter.context_stack.back().*(Mem_Ptr)); + return Number((*interpreter.current_context).*(Mem_Ptr)); } ensure(std::holds_alternative(args.front().data), "Ctx only holds numeric values"); if constexpr (std::is_same_v) { - interpreter.context_stack.back().*(Mem_Ptr) = std::get(args.front().data); + (*interpreter.current_context).*(Mem_Ptr) = std::get(args.front().data); } else { - interpreter.context_stack.back().*(Mem_Ptr) = static_cast( + (*interpreter.current_context).*(Mem_Ptr) = static_cast( std::get(args.front().data).as_int() ); } @@ -266,19 +266,20 @@ static std::optional action_play(Interpreter &i, Value v) /// Play notes template> -static inline Result builtin_play(Interpreter &i, Container args) +static inline Result builtin_play(Interpreter &interpreter, Container args) { - Try(ensure_midi_connection_available(i, "play")); - auto previous_action = std::exchange(i.default_action, action_play); - i.context_stack.push_back(i.context_stack.back()); + 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(*interpreter.current_context)); auto const finally = [&] { - i.default_action = std::move(previous_action); - i.context_stack.pop_back(); + interpreter.default_action = std::move(previous_action); + interpreter.current_context = previous_context; }; for (auto &el : args) { - if (std::optional error = sequential_play(i, std::move(el))) { + if (std::optional error = sequential_play(interpreter, std::move(el))) { finally(); return *std::move(error); } @@ -289,19 +290,19 @@ static inline Result builtin_play(Interpreter &i, Container args) } /// Play first argument while playing all others -static Result builtin_par(Interpreter &i, std::vector args) { - Try(ensure_midi_connection_available(i, "par")); +static Result builtin_par(Interpreter &interpreter, std::vector args) { + Try(ensure_midi_connection_available(interpreter, "par")); ensure(args.size() >= 1, "par only makes sense for at least one argument"); // TODO(assert) if (args.size() == 1) { auto chord = get_if(args.front()); ensure(chord, "Par expects music value as first argument"); // TODO(assert) - Try(i.play(std::move(*chord))); + Try(interpreter.play(std::move(*chord))); return Value{}; } // Create chord that should sustain during playing of all other notes - auto &ctx = i.context_stack.back(); + auto &ctx = *interpreter.current_context; auto chord = get_if(args.front()); ensure(chord, "par expects music value as first argument"); // TODO(assert) @@ -309,15 +310,15 @@ static Result builtin_par(Interpreter &i, std::vector args) { for (auto const& note : chord->notes) { if (note.base) { - i.midi_connection->send_note_on(0, *note.into_midi_note(), 127); + interpreter.midi_connection->send_note_on(0, *note.into_midi_note(), 127); } } - auto result = builtin_play(i, std::span(args).subspan(1)); + auto result = builtin_play(interpreter, std::span(args).subspan(1)); for (auto const& note : chord->notes) { if (note.base) { - i.midi_connection->send_note_off(0, *note.into_midi_note(), 127); + interpreter.midi_connection->send_note_off(0, *note.into_midi_note(), 127); } } return result; @@ -386,7 +387,7 @@ static Result builtin_sim(Interpreter &interpreter, std::vector ar }; std::vector schedule; - auto const& ctx = interpreter.context_stack.back(); + auto const& ctx = *interpreter.current_context; for (auto const& track : tracks) { auto passed_time = Number(0); @@ -997,19 +998,19 @@ static Result builtin_chord(Interpreter &i, std::vector args) } /// Send MIDI message Note On -static Result builtin_note_on(Interpreter &i, std::vector args) +static Result builtin_note_on(Interpreter &interpreter, std::vector args) { if (auto a = match(args)) { auto [chan, note, vel] = *a; - i.midi_connection->send_note_on(chan.as_int(), note.as_int(), vel.as_int()); + interpreter.midi_connection->send_note_on(chan.as_int(), note.as_int(), vel.as_int()); return Value {}; } if (auto a = match(args)) { auto [chan, chord, vel] = *a; for (auto note : chord.notes) { - note = i.context_stack.back().fill(note); - i.midi_connection->send_note_on(chan.as_int(), *note.into_midi_note(), vel.as_int()); + note = interpreter.current_context->fill(note); + interpreter.midi_connection->send_note_on(chan.as_int(), *note.into_midi_note(), vel.as_int()); } } @@ -1027,11 +1028,11 @@ static Result builtin_note_on(Interpreter &i, std::vector args) } /// Send MIDI message Note Off -static Result builtin_note_off(Interpreter &i, std::vector args) +static Result builtin_note_off(Interpreter &interpreter, std::vector args) { if (auto a = match(args)) { auto [chan, note] = *a; - i.midi_connection->send_note_off(chan.as_int(), note.as_int(), 127); + interpreter.midi_connection->send_note_off(chan.as_int(), note.as_int(), 127); return Value {}; } @@ -1039,8 +1040,8 @@ static Result builtin_note_off(Interpreter &i, std::vector args) auto& [chan, chord] = *a; for (auto note : chord.notes) { - note = i.context_stack.back().fill(note); - i.midi_connection->send_note_off(chan.as_int(), *note.into_midi_note(), 127); + note = interpreter.current_context->fill(note); + interpreter.midi_connection->send_note_off(chan.as_int(), *note.into_midi_note(), 127); } } diff --git a/musique/interpreter/context.hh b/musique/interpreter/context.hh index 1aa0aa3..c85c0e2 100644 --- a/musique/interpreter/context.hh +++ b/musique/interpreter/context.hh @@ -5,6 +5,7 @@ #include #include #include +#include /// Context holds default values for music related actions struct Context @@ -23,6 +24,8 @@ struct Context /// Converts length to seconds with current bpm std::chrono::duration length_to_duration(std::optional length) const; + + std::shared_ptr parent; }; #endif diff --git a/musique/interpreter/interpreter.cc b/musique/interpreter/interpreter.cc index f521192..ed4aa73 100644 --- a/musique/interpreter/interpreter.cc +++ b/musique/interpreter/interpreter.cc @@ -7,6 +7,9 @@ #include #include +midi::Connection *Interpreter::midi_connection = nullptr; +std::unordered_map Interpreter::operators {}; + /// Registers constants like `fn = full note = 1/1` static inline void register_note_length_constants() { @@ -32,7 +35,7 @@ static inline void register_note_length_constants() Interpreter::Interpreter() { // Context initialization - context_stack.emplace_back(); + current_context = std::make_shared(); // Environment initlialization ensure(!bool(Env::global), "Only one instance of interpreter can be at one time"); @@ -228,7 +231,7 @@ void Interpreter::leave_scope() std::optional Interpreter::play(Chord chord) { Try(ensure_midi_connection_available(*this, "play")); - auto &ctx = context_stack.back(); + auto &ctx = *current_context; if (chord.notes.size() == 0) { std::this_thread::sleep_for(ctx.length_to_duration(ctx.length)); @@ -389,7 +392,7 @@ static void snapshot(std::ostream& out, Value const& value) { void Interpreter::snapshot(std::ostream& out) { - auto const& ctx = context_stack.back(); + auto const& ctx = *current_context; out << ", oct " << int(ctx.octave) << '\n'; out << ", len (" << ctx.length.num << "/" << ctx.length.den << ")\n"; out << ", bpm " << ctx.bpm << '\n'; diff --git a/musique/interpreter/interpreter.hh b/musique/interpreter/interpreter.hh index b9ce708..e00edf1 100644 --- a/musique/interpreter/interpreter.hh +++ b/musique/interpreter/interpreter.hh @@ -11,24 +11,24 @@ struct Interpreter { /// MIDI connection that is used to play music. /// It's optional for simple interpreter testing. - midi::Connection *midi_connection = nullptr; + static midi::Connection *midi_connection; /// Operators defined for language - std::unordered_map operators; + static std::unordered_map operators; /// Current environment (current scope) std::shared_ptr env; /// Context stack. `constext_stack.back()` is a current context. /// There is always at least one context - std::vector context_stack; + std::shared_ptr current_context; std::function(Interpreter&, Value)> default_action; Interpreter(); ~Interpreter(); + Interpreter(Interpreter &&) = delete; Interpreter(Interpreter const&) = delete; - Interpreter(Interpreter &&) = default; /// Try to evaluate given program tree Result eval(Ast &&ast); diff --git a/scripts/release b/scripts/release index 4e66080..20e6a86 100755 --- a/scripts/release +++ b/scripts/release @@ -26,7 +26,7 @@ cp bin/musique "$Target"/musique-x86_64-linux sudo rm -rf bin/ make os=windows >/dev/null -cp bin/musique.exe "$Target"/musique-x86_64-windows +cp bin/musique.exe "$Target"/musique-x86_64-windows.exe cp LICENSE "$Target"/LICENSE cp CHANGELOG.md "$Target/CHANGELOG.md" @@ -37,6 +37,7 @@ chmod 0755 "$Target"/install.sh lowdown -s doc/functions.md -m "title:Lista funkcji języka Musique" -o "$Target"/functions.html python scripts/language-cmp-cheatsheet.py doc/musique-vs-languages-cheatsheet.template mv doc/musique-vs-languages-cheatsheet.html "${Target}/musique-vs-others-cheatsheet.html" +make doc/wprowadzenie.html && mv doc/wprowadzenie.html "${Target}/wprowadzenie.html" git clone --recursive --quiet --depth=1 "$(git remote -v | awk '{ print $2 }' | head -n1)" "$Target"/source_code rm -rf "$Target"/source_code/.git