Moved from Result<void> to std::optional<Error>
This commit is contained in:
parent
d9c0468729
commit
038de0fc27
@ -2,7 +2,6 @@
|
|||||||
#define Musique_Header_HH
|
#define Musique_Header_HH
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <concepts>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -390,6 +389,73 @@ struct [[nodiscard("This value may contain critical error, so it should NOT be i
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Abstraction over any value that are either value or error
|
||||||
|
///
|
||||||
|
/// Inspired by P2561R0
|
||||||
|
template<typename = void>
|
||||||
|
struct Try_Traits
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
static constexpr bool is_ok(T const& v) { return Try_Traits<T>::is_ok(v); }
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static constexpr auto yield_value(T&& v) { return Try_Traits<T>::yield_value(std::forward<T>(v)); }
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static constexpr auto yield_error(T&& v) { return Try_Traits<T>::yield_error(std::forward<T>(v)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Try_Traits<std::optional<Error>>
|
||||||
|
{
|
||||||
|
using Value_Type = std::nullopt_t;
|
||||||
|
using Error_Type = Error;
|
||||||
|
|
||||||
|
static constexpr bool is_ok(std::optional<Error> const& o)
|
||||||
|
{
|
||||||
|
return not o.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::nullopt_t yield_value(std::optional<Error>&& err)
|
||||||
|
{
|
||||||
|
assert(not err.has_value(), "Trying to yield value from optional that contains error");
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Error yield_error(std::optional<Error>&& err)
|
||||||
|
{
|
||||||
|
assert(err.has_value(), "Trying to yield value from optional that NOT constains error");
|
||||||
|
return std::move(*err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Try_Traits<Result<T>>
|
||||||
|
{
|
||||||
|
using Value_Type = T;
|
||||||
|
using Error_Type = Error;
|
||||||
|
|
||||||
|
static constexpr bool is_ok(Result<T> const& o)
|
||||||
|
{
|
||||||
|
return o.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
static auto yield_value(Result<T> val)
|
||||||
|
{
|
||||||
|
assert(val.has_value(), "Trying to yield value from expected that contains error");
|
||||||
|
if constexpr (std::is_void_v<T>) {
|
||||||
|
} else {
|
||||||
|
return std::move(*val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Error yield_error(Result<T>&& val)
|
||||||
|
{
|
||||||
|
assert(not val.has_value(), "Trying to yield error from expected with value");
|
||||||
|
return std::move(val.error());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// Shorthand for forwarding error values with Result type family.
|
/// Shorthand for forwarding error values with Result type family.
|
||||||
///
|
///
|
||||||
/// This implementation requires C++ language extension: statement expressions
|
/// This implementation requires C++ language extension: statement expressions
|
||||||
@ -398,9 +464,10 @@ struct [[nodiscard("This value may contain critical error, so it should NOT be i
|
|||||||
#define Try(Value) \
|
#define Try(Value) \
|
||||||
({ \
|
({ \
|
||||||
auto try_value = (Value); \
|
auto try_value = (Value); \
|
||||||
if (not try_value.has_value()) [[unlikely]] \
|
using Trait [[maybe_unused]] = Try_Traits<std::decay_t<decltype(try_value)>>; \
|
||||||
return tl::unexpected(try_value.error()); \
|
if (not Trait::is_ok(try_value)) [[unlikely]] \
|
||||||
std::move(try_value).value(); \
|
return Trait::yield_error(std::move(try_value)); \
|
||||||
|
Trait::yield_value(std::move(try_value)); \
|
||||||
})
|
})
|
||||||
|
|
||||||
/// Drop in replacement for bool when C++ implcit conversions stand in your way
|
/// Drop in replacement for bool when C++ implcit conversions stand in your way
|
||||||
@ -1035,7 +1102,7 @@ struct Interpreter
|
|||||||
/// There is always at least one context
|
/// There is always at least one context
|
||||||
std::vector<Context> context_stack;
|
std::vector<Context> context_stack;
|
||||||
|
|
||||||
std::function<Result<void>(Interpreter&, Value)> default_action;
|
std::function<std::optional<Error>(Interpreter&, Value)> default_action;
|
||||||
|
|
||||||
struct Incoming_Midi_Callbacks;
|
struct Incoming_Midi_Callbacks;
|
||||||
std::unique_ptr<Incoming_Midi_Callbacks> callbacks;
|
std::unique_ptr<Incoming_Midi_Callbacks> callbacks;
|
||||||
@ -1056,7 +1123,7 @@ struct Interpreter
|
|||||||
void leave_scope();
|
void leave_scope();
|
||||||
|
|
||||||
/// Play note resolving any missing parameters with context via `midi_connection` member.
|
/// Play note resolving any missing parameters with context via `midi_connection` member.
|
||||||
Result<void> play(Chord);
|
std::optional<Error> play(Chord);
|
||||||
|
|
||||||
/// Add to global interpreter scope all builtin function definitions
|
/// Add to global interpreter scope all builtin function definitions
|
||||||
///
|
///
|
||||||
@ -1150,7 +1217,7 @@ struct Value_Formatter
|
|||||||
|
|
||||||
Value_Formatter nest(Context nested = Free) const;
|
Value_Formatter nest(Context nested = Free) const;
|
||||||
|
|
||||||
Result<void> format(std::ostream& os, Interpreter &interpreter, Value const& value);
|
std::optional<Error> format(std::ostream& os, Interpreter &interpreter, Value const& value);
|
||||||
};
|
};
|
||||||
|
|
||||||
Result<std::string> format(Interpreter &i, Value const& value);
|
Result<std::string> format(Interpreter &i, Value const& value);
|
||||||
|
@ -27,14 +27,14 @@ struct Guard
|
|||||||
return Error { std::move(error) };
|
return Error { std::move(error) };
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Result<void> yield_result() const
|
inline std::optional<Error> yield_result() const
|
||||||
{
|
{
|
||||||
return yield_error();
|
return yield_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Result<void> operator()(bool(*predicate)(Value::Type), Value const& v) const
|
inline std::optional<Error> operator()(bool(*predicate)(Value::Type), Value const& v) const
|
||||||
{
|
{
|
||||||
return predicate(v.type) ? Result<void>{} : yield_result();
|
return predicate(v.type) ? std::optional<Error>{} : yield_result();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ struct Interpreter::Incoming_Midi_Callbacks
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum class Midi_Connection_Type { Output, Input };
|
enum class Midi_Connection_Type { Output, Input };
|
||||||
Result<void> ensure_midi_connection_available(Interpreter&, Midi_Connection_Type, std::string_view operation_name);
|
std::optional<Error> ensure_midi_connection_available(Interpreter&, Midi_Connection_Type, std::string_view operation_name);
|
||||||
|
|
||||||
constexpr std::size_t hash_combine(std::size_t lhs, std::size_t rhs) {
|
constexpr std::size_t hash_combine(std::size_t lhs, std::size_t rhs) {
|
||||||
return lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2);
|
return lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2);
|
||||||
|
@ -35,7 +35,7 @@ concept Iterable = (With_Index_Method<T> || With_Index_Operator<T>) && requires
|
|||||||
|
|
||||||
/// Create chord out of given notes
|
/// Create chord out of given notes
|
||||||
template<Iterable T>
|
template<Iterable T>
|
||||||
static inline Result<void> create_chord(std::vector<Note> &chord, Interpreter &interpreter, T args)
|
static inline std::optional<Error> create_chord(std::vector<Note> &chord, Interpreter &interpreter, T args)
|
||||||
{
|
{
|
||||||
for (auto i = 0u; i < args.size(); ++i) {
|
for (auto i = 0u; i < args.size(); ++i) {
|
||||||
Value arg;
|
Value arg;
|
||||||
@ -229,7 +229,7 @@ static auto builtin_program_change(Interpreter &i, std::vector<Value> args) -> R
|
|||||||
/// Plays sequentialy notes walking into arrays and evaluation blocks
|
/// Plays sequentialy notes walking into arrays and evaluation blocks
|
||||||
///
|
///
|
||||||
/// @invariant default_action is play one
|
/// @invariant default_action is play one
|
||||||
static inline Result<void> sequential_play(Interpreter &i, Value v)
|
static inline std::optional<Error> sequential_play(Interpreter &i, Value v)
|
||||||
{
|
{
|
||||||
switch (v.type) {
|
switch (v.type) {
|
||||||
break; case Value::Type::Array:
|
break; case Value::Type::Array:
|
||||||
@ -250,7 +250,7 @@ static inline Result<void> sequential_play(Interpreter &i, Value v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Play what's given
|
/// Play what's given
|
||||||
static Result<void> action_play(Interpreter &i, Value v)
|
static std::optional<Error> action_play(Interpreter &i, Value v)
|
||||||
{
|
{
|
||||||
Try(sequential_play(i, std::move(v)));
|
Try(sequential_play(i, std::move(v)));
|
||||||
return {};
|
return {};
|
||||||
@ -335,7 +335,7 @@ static Result<Value> builtin_sim(Interpreter &interpreter, std::vector<Value> ar
|
|||||||
struct {
|
struct {
|
||||||
Interpreter &interpreter;
|
Interpreter &interpreter;
|
||||||
|
|
||||||
Result<void> operator()(std::vector<Chord> &track, Value &arg)
|
std::optional<Error> operator()(std::vector<Chord> &track, Value &arg)
|
||||||
{
|
{
|
||||||
if (arg.type == Value::Type::Music) {
|
if (arg.type == Value::Type::Music) {
|
||||||
track.push_back(std::move(arg).chord);
|
track.push_back(std::move(arg).chord);
|
||||||
@ -351,13 +351,13 @@ static Result<Value> builtin_sim(Interpreter &interpreter, std::vector<Value> ar
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invalid type for sim function
|
// Invalid type for sim function
|
||||||
return errors::Unsupported_Types_For {
|
return Error{errors::Unsupported_Types_For {
|
||||||
.type = errors::Unsupported_Types_For::Function,
|
.type = errors::Unsupported_Types_For::Function,
|
||||||
.name = "sim",
|
.name = "sim",
|
||||||
.possibilities = {
|
.possibilities = {
|
||||||
"(music | array of music)+"
|
"(music | array of music)+"
|
||||||
},
|
},
|
||||||
};
|
}};
|
||||||
}
|
}
|
||||||
} append { interpreter };
|
} append { interpreter };
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@ void Interpreter::leave_scope()
|
|||||||
env = env->leave();
|
env = env->leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> Interpreter::play(Chord chord)
|
std::optional<Error> Interpreter::play(Chord chord)
|
||||||
{
|
{
|
||||||
Try(ensure_midi_connection_available(*this, Midi_Connection_Type::Output, "play"));
|
Try(ensure_midi_connection_available(*this, Midi_Connection_Type::Output, "play"));
|
||||||
auto &ctx = context_stack.back();
|
auto &ctx = context_stack.back();
|
||||||
@ -256,7 +256,7 @@ Result<void> Interpreter::play(Chord chord)
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<void> ensure_midi_connection_available(Interpreter &i, Midi_Connection_Type m, std::string_view operation_name)
|
std::optional<Error> ensure_midi_connection_available(Interpreter &i, Midi_Connection_Type m, std::string_view operation_name)
|
||||||
{
|
{
|
||||||
switch (m) {
|
switch (m) {
|
||||||
break; case Midi_Connection_Type::Output:
|
break; case Midi_Connection_Type::Output:
|
||||||
|
@ -153,7 +153,7 @@ struct Runner
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Run given source
|
/// Run given source
|
||||||
Result<void> run(std::string_view source, std::string_view filename, bool output = false)
|
std::optional<Error> run(std::string_view source, std::string_view filename, bool output = false)
|
||||||
{
|
{
|
||||||
auto ast = Try(Parser::parse(source, filename, repl_line_number));
|
auto ast = Try(Parser::parse(source, filename, repl_line_number));
|
||||||
|
|
||||||
@ -326,9 +326,10 @@ static Result<void> Main(std::span<char const*> args)
|
|||||||
|
|
||||||
Lines::the.add_line("<repl>", raw, repl_line_number);
|
Lines::the.add_line("<repl>", raw, repl_line_number);
|
||||||
auto result = runner.run(raw, "<repl>", true);
|
auto result = runner.run(raw, "<repl>", true);
|
||||||
if (not result.has_value()) {
|
using Traits = Try_Traits<std::decay_t<decltype(result)>>;
|
||||||
|
if (not Traits::is_ok(result)) {
|
||||||
std::cout << std::flush;
|
std::cout << std::flush;
|
||||||
std::cerr << result.error() << std::flush;
|
std::cerr << Traits::yield_error(std::move(result)) << std::flush;
|
||||||
}
|
}
|
||||||
repl_line_number++;
|
repl_line_number++;
|
||||||
// We don't free input line since there could be values that still relay on it
|
// We don't free input line since there could be values that still relay on it
|
||||||
|
Loading…
Reference in New Issue
Block a user