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

View File

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

View File

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

View File

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

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

View File

@ -38,3 +38,8 @@ std::ostream& operator<<(std::ostream& os, Array const& v)
} }
return os << ')'; 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 /// 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);
}; };

View File

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

View File

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

View File

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