check if block is a collection at runtime; operators pretty printing
This commit is contained in:
parent
d4c3dbb280
commit
6a3308fc46
@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
- new builtins: map, while, set_len, duration
|
- new builtins: map, while, set_len, duration
|
||||||
- `<note><octave>` notation like `c4` that mimics [scientific notation](https://en.wikipedia.org/wiki/Scientific_pitch_notation)
|
- `<note><octave>` notation like `c4` that mimics [scientific notation](https://en.wikipedia.org/wiki/Scientific_pitch_notation)
|
||||||
|
- operator pretty printing while printing values
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
@ -22,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Index operation using booleans behaves like a mask and not fancy way of spelling 0 and 1
|
- Index operation using booleans behaves like a mask and not fancy way of spelling 0 and 1
|
||||||
|
- Blocks are check against beeing a collection at runtime to prevent treating anonymous functions as collections and cousing assertions
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
@ -1,34 +1,44 @@
|
|||||||
#ifndef MUSIQUE_ACCESSORS_HH
|
#ifndef MUSIQUE_ACCESSORS_HH
|
||||||
#define MUSIQUE_ACCESSORS_HH
|
#define MUSIQUE_ACCESSORS_HH
|
||||||
|
|
||||||
|
#include <musique/common.hh>
|
||||||
#include <musique/errors.hh>
|
#include <musique/errors.hh>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
#include <iostream>
|
||||||
|
#include <musique/value/collection.hh>
|
||||||
|
|
||||||
template<typename Desired, typename ...V>
|
namespace details
|
||||||
constexpr Desired* get_if(std::variant<V...> &v)
|
|
||||||
{
|
{
|
||||||
return std::visit([]<typename Actual>(Actual &act) -> Desired* {
|
template<typename T>
|
||||||
if constexpr (std::is_same_v<Desired, Actual>) {
|
concept Reference = std::is_lvalue_reference_v<T>;
|
||||||
return &act;
|
|
||||||
} else if constexpr (std::is_base_of_v<Desired, Actual>) {
|
|
||||||
return static_cast<Desired*>(&act);
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}, v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Desired, typename ...V>
|
template<typename Desired, same_template_as<std::variant> Variant>
|
||||||
constexpr Desired const* get_if(std::variant<V...> const& v)
|
requires details::Reference<Variant>
|
||||||
|
constexpr auto get_if(Variant &&v)
|
||||||
{
|
{
|
||||||
return std::visit([]<typename Actual>(Actual const& act) -> Desired const* {
|
using Return_Type = std::conditional_t<
|
||||||
if constexpr (std::is_same_v<Desired, Actual>) {
|
std::is_const_v<std::remove_reference_t<Variant>>,
|
||||||
|
Desired const*,
|
||||||
|
Desired*
|
||||||
|
>;
|
||||||
|
|
||||||
|
return std::visit([]<details::Reference Actual>(Actual&& act) -> Return_Type {
|
||||||
|
if constexpr (std::is_same_v<Desired, std::remove_cvref_t<Actual>>) {
|
||||||
return &act;
|
return &act;
|
||||||
} else if constexpr (std::is_base_of_v<Desired, Actual>) {
|
} else if constexpr (std::is_base_of_v<Desired, std::remove_cvref_t<Actual>>) {
|
||||||
return static_cast<Desired const*>(&act);
|
auto ret = static_cast<Return_Type>(&act);
|
||||||
} else {
|
if constexpr (std::is_same_v<std::remove_cvref_t<Desired>, Collection>) {
|
||||||
return nullptr;
|
if (ret->is_collection()) {
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
}, v);
|
}, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,31 +49,5 @@ constexpr Desired& get_ref(std::variant<V...> &v)
|
|||||||
unreachable();
|
unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
template<typename ...T, typename Values>
|
|
||||||
constexpr auto match(Values& values) -> std::optional<std::tuple<T...>>
|
|
||||||
{
|
|
||||||
return [&]<std::size_t ...I>(std::index_sequence<I...>) -> std::optional<std::tuple<T...>> {
|
|
||||||
if (sizeof...(T) == values.size() && (std::holds_alternative<T>(values[I].data) && ...)) {
|
|
||||||
return {{ std::get<T>(values[I].data)... }};
|
|
||||||
} else {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
} (std::make_index_sequence<sizeof...(T)>{});
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ...T, typename Values>
|
|
||||||
constexpr auto match_ref(Values& values) -> std::optional<std::tuple<T&...>>
|
|
||||||
{
|
|
||||||
return [&]<std::size_t ...I>(std::index_sequence<I...>) -> std::optional<std::tuple<T&...>> {
|
|
||||||
if (sizeof...(T) == values.size() && (get_if<T>(values[I].data) && ...)) {
|
|
||||||
return {{ get_ref<T>(values[I].data)... }};
|
|
||||||
} else {
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
} (std::make_index_sequence<sizeof...(T)>{});
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -38,6 +38,9 @@ struct is_template<Template, Template<T...>> : std::true_type {};
|
|||||||
template<template<typename ...> typename Template, typename T>
|
template<template<typename ...> typename Template, typename T>
|
||||||
constexpr auto is_template_v = is_template<Template, T>::value;
|
constexpr auto is_template_v = is_template<Template, T>::value;
|
||||||
|
|
||||||
|
template<typename T, template<typename ...> typename Template>
|
||||||
|
concept same_template_as = is_template_v<Template, std::remove_cvref_t<T>>;
|
||||||
|
|
||||||
/// Drop in replacement for bool when C++ impilcit conversions stand in your way
|
/// Drop in replacement for bool when C++ impilcit conversions stand in your way
|
||||||
struct Explicit_Bool
|
struct Explicit_Bool
|
||||||
{
|
{
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <musique/format.hh>
|
#include <musique/format.hh>
|
||||||
#include <musique/try.hh>
|
#include <musique/try.hh>
|
||||||
#include <musique/value/value.hh>
|
#include <musique/value/value.hh>
|
||||||
|
#include <musique/interpreter/interpreter.hh>
|
||||||
|
|
||||||
Result<std::string> format(Interpreter &i, Value const& value)
|
Result<std::string> format(Interpreter &i, Value const& value)
|
||||||
{
|
{
|
||||||
@ -21,11 +22,17 @@ std::optional<Error> Value_Formatter::format(std::ostream& os, Interpreter &inte
|
|||||||
return std::visit(Overloaded {
|
return std::visit(Overloaded {
|
||||||
[&](Intrinsic const& intrinsic) -> std::optional<Error> {
|
[&](Intrinsic const& intrinsic) -> std::optional<Error> {
|
||||||
for (auto const& [key, val] : Env::global->variables) {
|
for (auto const& [key, val] : Env::global->variables) {
|
||||||
if (auto other = get_if<Intrinsic>(val); intrinsic == *other) {
|
if (auto other = get_if<Intrinsic>(val); other && intrinsic == *other) {
|
||||||
os << "<intrinsic '" << key << "'>";
|
os << "<intrinsic '" << key << "'>";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (auto const& [key, val] : interpreter.operators) {
|
||||||
|
if (intrinsic == val) {
|
||||||
|
os << "<operator '" << key << "'>";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
os << "<intrinsic>";
|
os << "<intrinsic>";
|
||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
@ -41,14 +48,18 @@ std::optional<Error> Value_Formatter::format(std::ostream& os, Interpreter &inte
|
|||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
[&](Block const& block) -> std::optional<Error> {
|
[&](Block const& block) -> std::optional<Error> {
|
||||||
os << '(';
|
if (block.is_collection()) {
|
||||||
for (auto i = 0u; i < block.size(); ++i) {
|
os << '(';
|
||||||
if (i > 0) {
|
for (auto i = 0u; i < block.size(); ++i) {
|
||||||
os << ", ";
|
if (i > 0) {
|
||||||
|
os << ", ";
|
||||||
|
}
|
||||||
|
Try(nest(Inside_Block).format(os, interpreter, Try(block.index(interpreter, i))));
|
||||||
}
|
}
|
||||||
Try(nest(Inside_Block).format(os, interpreter, Try(block.index(interpreter, i))));
|
os << ')';
|
||||||
|
} else {
|
||||||
|
os << "<block>";
|
||||||
}
|
}
|
||||||
os << ')';
|
|
||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
[&](auto&&) -> std::optional<Error> {
|
[&](auto&&) -> std::optional<Error> {
|
||||||
|
@ -549,10 +549,9 @@ static Result<Value> builtin_fold(Interpreter &interpreter, std::vector<Value> a
|
|||||||
static Result<Value> builtin_map(Interpreter &interpreter, std::vector<Value> args)
|
static Result<Value> builtin_map(Interpreter &interpreter, std::vector<Value> args)
|
||||||
{
|
{
|
||||||
static constexpr auto guard = Guard<2> {
|
static constexpr auto guard = Guard<2> {
|
||||||
.name = "fold",
|
.name = "map",
|
||||||
.possibilities = {
|
.possibilities = {
|
||||||
"(callback, array) -> any",
|
"(callback, array) -> any"
|
||||||
"(callback, array, init) -> any"
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -38,3 +38,8 @@ std::ostream& operator<<(std::ostream& os, Array const& v)
|
|||||||
}
|
}
|
||||||
return os << ')';
|
return os << ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Array::is_collection() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -32,6 +32,8 @@ struct Array : Collection
|
|||||||
/// Arrays are equal if all of their elements are equal
|
/// Arrays are equal if all of their elements are equal
|
||||||
bool operator==(Array const&) const = default;
|
bool operator==(Array const&) const = default;
|
||||||
|
|
||||||
|
bool is_collection() const override;
|
||||||
|
|
||||||
/// Print array
|
/// Print array
|
||||||
friend std::ostream& operator<<(std::ostream& os, Array const& v);
|
friend std::ostream& operator<<(std::ostream& os, Array const& v);
|
||||||
};
|
};
|
||||||
|
@ -16,7 +16,7 @@ static inline std::optional<Error> guard_index(unsigned index, unsigned size)
|
|||||||
// TODO Add memoization
|
// TODO Add memoization
|
||||||
Result<Value> Block::index(Interpreter &i, unsigned position) const
|
Result<Value> Block::index(Interpreter &i, unsigned position) const
|
||||||
{
|
{
|
||||||
ensure(parameters.size() == 0, "cannot index into block with parameters (for now)");
|
ensure(parameters.empty(), "cannot index into block with parameters (for now)");
|
||||||
if (body.type != Ast::Type::Sequence) {
|
if (body.type != Ast::Type::Sequence) {
|
||||||
Try(guard_index(position, 1));
|
Try(guard_index(position, 1));
|
||||||
return i.eval((Ast)body);
|
return i.eval((Ast)body);
|
||||||
@ -57,3 +57,8 @@ Result<Value> Block::operator()(Interpreter &i, std::vector<Value> arguments) co
|
|||||||
i.env = old_scope;
|
i.env = old_scope;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Block::is_collection() const
|
||||||
|
{
|
||||||
|
return parameters.empty();
|
||||||
|
}
|
||||||
|
@ -36,6 +36,8 @@ struct Block : Collection, Function
|
|||||||
|
|
||||||
/// Count of elements in block
|
/// Count of elements in block
|
||||||
usize size() const override;
|
usize size() const override;
|
||||||
|
|
||||||
|
bool is_collection() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -17,6 +17,8 @@ struct Collection
|
|||||||
/// Return elements count
|
/// Return elements count
|
||||||
virtual usize size() const = 0;
|
virtual usize size() const = 0;
|
||||||
|
|
||||||
|
virtual bool is_collection() const = 0;
|
||||||
|
|
||||||
bool operator==(Collection const&) const = default;
|
bool operator==(Collection const&) const = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user