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
|
||||
- `<note><octave>` notation like `c4` that mimics [scientific notation](https://en.wikipedia.org/wiki/Scientific_pitch_notation)
|
||||
- operator pretty printing while printing values
|
||||
|
||||
### Changed
|
||||
|
||||
@ -22,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Fixed
|
||||
|
||||
- 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
|
||||
|
||||
|
@ -1,34 +1,44 @@
|
||||
#ifndef MUSIQUE_ACCESSORS_HH
|
||||
#define MUSIQUE_ACCESSORS_HH
|
||||
|
||||
#include <musique/common.hh>
|
||||
#include <musique/errors.hh>
|
||||
#include <variant>
|
||||
#include <iostream>
|
||||
#include <musique/value/collection.hh>
|
||||
|
||||
template<typename Desired, typename ...V>
|
||||
constexpr Desired* get_if(std::variant<V...> &v)
|
||||
namespace details
|
||||
{
|
||||
return std::visit([]<typename Actual>(Actual &act) -> Desired* {
|
||||
if constexpr (std::is_same_v<Desired, Actual>) {
|
||||
return &act;
|
||||
} else if constexpr (std::is_base_of_v<Desired, Actual>) {
|
||||
return static_cast<Desired*>(&act);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}, v);
|
||||
template<typename T>
|
||||
concept Reference = std::is_lvalue_reference_v<T>;
|
||||
}
|
||||
|
||||
template<typename Desired, typename ...V>
|
||||
constexpr Desired const* get_if(std::variant<V...> const& v)
|
||||
template<typename Desired, same_template_as<std::variant> Variant>
|
||||
requires details::Reference<Variant>
|
||||
constexpr auto get_if(Variant &&v)
|
||||
{
|
||||
return std::visit([]<typename Actual>(Actual const& act) -> Desired const* {
|
||||
if constexpr (std::is_same_v<Desired, Actual>) {
|
||||
using Return_Type = std::conditional_t<
|
||||
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;
|
||||
} else if constexpr (std::is_base_of_v<Desired, Actual>) {
|
||||
return static_cast<Desired const*>(&act);
|
||||
} else if constexpr (std::is_base_of_v<Desired, std::remove_cvref_t<Actual>>) {
|
||||
auto ret = static_cast<Return_Type>(&act);
|
||||
if constexpr (std::is_same_v<std::remove_cvref_t<Desired>, Collection>) {
|
||||
if (ret->is_collection()) {
|
||||
return ret;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}, v);
|
||||
}
|
||||
|
||||
@ -39,31 +49,5 @@ constexpr Desired& get_ref(std::variant<V...> &v)
|
||||
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
|
||||
|
||||
|
@ -38,6 +38,9 @@ struct is_template<Template, Template<T...>> : std::true_type {};
|
||||
template<template<typename ...> typename Template, typename T>
|
||||
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
|
||||
struct Explicit_Bool
|
||||
{
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <musique/format.hh>
|
||||
#include <musique/try.hh>
|
||||
#include <musique/value/value.hh>
|
||||
#include <musique/interpreter/interpreter.hh>
|
||||
|
||||
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 {
|
||||
[&](Intrinsic const& intrinsic) -> std::optional<Error> {
|
||||
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 << "'>";
|
||||
return {};
|
||||
}
|
||||
}
|
||||
for (auto const& [key, val] : interpreter.operators) {
|
||||
if (intrinsic == val) {
|
||||
os << "<operator '" << key << "'>";
|
||||
return {};
|
||||
}
|
||||
}
|
||||
os << "<intrinsic>";
|
||||
return {};
|
||||
},
|
||||
@ -41,6 +48,7 @@ std::optional<Error> Value_Formatter::format(std::ostream& os, Interpreter &inte
|
||||
return {};
|
||||
},
|
||||
[&](Block const& block) -> std::optional<Error> {
|
||||
if (block.is_collection()) {
|
||||
os << '(';
|
||||
for (auto i = 0u; i < block.size(); ++i) {
|
||||
if (i > 0) {
|
||||
@ -49,6 +57,9 @@ std::optional<Error> Value_Formatter::format(std::ostream& os, Interpreter &inte
|
||||
Try(nest(Inside_Block).format(os, interpreter, Try(block.index(interpreter, i))));
|
||||
}
|
||||
os << ')';
|
||||
} else {
|
||||
os << "<block>";
|
||||
}
|
||||
return {};
|
||||
},
|
||||
[&](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 constexpr auto guard = Guard<2> {
|
||||
.name = "fold",
|
||||
.name = "map",
|
||||
.possibilities = {
|
||||
"(callback, array) -> any",
|
||||
"(callback, array, init) -> any"
|
||||
"(callback, array) -> any"
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -38,3 +38,8 @@ std::ostream& operator<<(std::ostream& os, Array const& v)
|
||||
}
|
||||
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
|
||||
bool operator==(Array const&) const = default;
|
||||
|
||||
bool is_collection() const override;
|
||||
|
||||
/// Print array
|
||||
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
|
||||
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) {
|
||||
Try(guard_index(position, 1));
|
||||
return i.eval((Ast)body);
|
||||
@ -57,3 +57,8 @@ Result<Value> Block::operator()(Interpreter &i, std::vector<Value> arguments) co
|
||||
i.env = old_scope;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Block::is_collection() const
|
||||
{
|
||||
return parameters.empty();
|
||||
}
|
||||
|
@ -36,6 +36,8 @@ struct Block : Collection, Function
|
||||
|
||||
/// Count of elements in block
|
||||
usize size() const override;
|
||||
|
||||
bool is_collection() const override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -17,6 +17,8 @@ struct Collection
|
||||
/// Return elements count
|
||||
virtual usize size() const = 0;
|
||||
|
||||
virtual bool is_collection() const = 0;
|
||||
|
||||
bool operator==(Collection const&) const = default;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user