check if block is a collection at runtime; operators pretty printing

This commit is contained in:
Robert Bendun 2022-10-28 00:56:11 +02:00
parent d4c3dbb280
commit 6a3308fc46
10 changed files with 71 additions and 56 deletions

View File

@ -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

View File

@ -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

View File

@ -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
{

View File

@ -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> {

View File

@ -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"
}
};

View File

@ -38,3 +38,8 @@ std::ostream& operator<<(std::ostream& os, Array const& v)
}
return os << ')';
}
bool Array::is_collection() const
{
return true;
}

View File

@ -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);
};

View File

@ -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();
}

View File

@ -36,6 +36,8 @@ struct Block : Collection, Function
/// Count of elements in block
usize size() const override;
bool is_collection() const override;
};
#endif

View File

@ -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;
};