Added Set value type
This commit is contained in:
parent
532727b7d1
commit
f19240d931
@ -19,6 +19,7 @@ Value_Formatter Value_Formatter::nest(Context nested) const
|
|||||||
|
|
||||||
std::optional<Error> Value_Formatter::format(std::ostream& os, Interpreter &interpreter, Value const& value)
|
std::optional<Error> Value_Formatter::format(std::ostream& os, Interpreter &interpreter, Value const& value)
|
||||||
{
|
{
|
||||||
|
static_assert(requires { os << value; });
|
||||||
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) {
|
||||||
@ -48,6 +49,9 @@ 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> {
|
||||||
|
if (block.body.arguments.front().type == Ast::Type::Concurrent)
|
||||||
|
unimplemented("Nice printing of concurrent blocks is not implemented yet");
|
||||||
|
|
||||||
if (block.is_collection()) {
|
if (block.is_collection()) {
|
||||||
os << '(';
|
os << '(';
|
||||||
for (auto i = 0u; i < block.size(); ++i) {
|
for (auto i = 0u; i < block.size(); ++i) {
|
||||||
@ -62,6 +66,17 @@ std::optional<Error> Value_Formatter::format(std::ostream& os, Interpreter &inte
|
|||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
|
[&](Set const& set) -> std::optional<Error> {
|
||||||
|
os << '{';
|
||||||
|
for (auto it = set.elements.begin(); it != set.elements.end(); ++it) {
|
||||||
|
if (it != set.elements.begin()) {
|
||||||
|
os << ", ";
|
||||||
|
}
|
||||||
|
Try(nest(Inside_Block).format(os, interpreter, *it));
|
||||||
|
}
|
||||||
|
os << '}';
|
||||||
|
return {};
|
||||||
|
},
|
||||||
[&](auto&&) -> std::optional<Error> {
|
[&](auto&&) -> std::optional<Error> {
|
||||||
os << value;
|
os << value;
|
||||||
return {};
|
return {};
|
||||||
|
@ -838,6 +838,14 @@ static Result<Value> builtin_flat(Interpreter &i, std::vector<Value> args)
|
|||||||
return Try(into_flat_array(i, std::move(args)));
|
return Try(into_flat_array(i, std::move(args)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs set from given arguments
|
||||||
|
static Result<Value> builtin_set(Interpreter&, std::vector<Value> args)
|
||||||
|
{
|
||||||
|
Set set;
|
||||||
|
std::move(args.begin(), args.end(), std::inserter(set.elements, set.elements.end()));
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
/// Pick random value from arugments
|
/// Pick random value from arugments
|
||||||
static Result<Value> builtin_pick(Interpreter &i, std::vector<Value> args)
|
static Result<Value> builtin_pick(Interpreter &i, std::vector<Value> args)
|
||||||
{
|
{
|
||||||
@ -1154,6 +1162,7 @@ void Interpreter::register_builtin_functions()
|
|||||||
global.force_define("rotate", builtin_rotate);
|
global.force_define("rotate", builtin_rotate);
|
||||||
global.force_define("round", apply_numeric_transform<&Number::round>);
|
global.force_define("round", apply_numeric_transform<&Number::round>);
|
||||||
global.force_define("scan", builtin_scan);
|
global.force_define("scan", builtin_scan);
|
||||||
|
global.force_define("set", builtin_set);
|
||||||
global.force_define("set_len", builtin_set_len);
|
global.force_define("set_len", builtin_set_len);
|
||||||
global.force_define("set_oct", builtin_set_oct);
|
global.force_define("set_oct", builtin_set_oct);
|
||||||
global.force_define("shuffle", builtin_shuffle);
|
global.force_define("shuffle", builtin_shuffle);
|
||||||
|
@ -448,7 +448,8 @@ static void snapshot(std::ostream& out, Value const& value) {
|
|||||||
out << ")";
|
out << ")";
|
||||||
},
|
},
|
||||||
[](Intrinsic const&) { unreachable(); },
|
[](Intrinsic const&) { unreachable(); },
|
||||||
[](Macro const&) { unreachable(); }
|
[](Macro const&) { unreachable(); },
|
||||||
|
[](Set const&) { unimplemented("Snapshoting is not supported yet"); }
|
||||||
}, value.data);
|
}, value.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
struct Interpreter;
|
struct Interpreter;
|
||||||
struct Value;
|
struct Value;
|
||||||
|
|
||||||
|
// TODO Array should have an ability to be invoked with duration parameter like singular note
|
||||||
|
|
||||||
/// Eager Array
|
/// Eager Array
|
||||||
struct Array : Collection
|
struct Array : Collection
|
||||||
{
|
{
|
||||||
|
@ -11,6 +11,8 @@ struct Env;
|
|||||||
struct Interpreter;
|
struct Interpreter;
|
||||||
struct Value;
|
struct Value;
|
||||||
|
|
||||||
|
// TODO Block should have an ability to be invoked with duration parameter like singular note
|
||||||
|
|
||||||
/// Lazy Array / Continuation / Closure type thingy
|
/// Lazy Array / Continuation / Closure type thingy
|
||||||
struct Block : Collection, Function
|
struct Block : Collection, Function
|
||||||
{
|
{
|
||||||
|
50
musique/value/hash.cc
Normal file
50
musique/value/hash.cc
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include <musique/value/hash.hh>
|
||||||
|
#include <musique/value/value.hh>
|
||||||
|
|
||||||
|
size_t std::hash<Set>::operator()(Set const& set) const noexcept
|
||||||
|
{
|
||||||
|
return std::accumulate(
|
||||||
|
set.elements.cbegin(), set.elements.cend(),
|
||||||
|
size_t(0),
|
||||||
|
[](size_t hash, Value const& element) {
|
||||||
|
return hash_combine(hash, std::hash<Value>{}(element));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t std::hash<Value>::operator()(Value const& value) const noexcept
|
||||||
|
{
|
||||||
|
auto const value_hash = std::visit(Overloaded {
|
||||||
|
[](Nil) {
|
||||||
|
return std::size_t(0);
|
||||||
|
},
|
||||||
|
|
||||||
|
[](Intrinsic i) {
|
||||||
|
return size_t(i.function_pointer);
|
||||||
|
},
|
||||||
|
|
||||||
|
[](Block const& b) {
|
||||||
|
return hash_combine(std::hash<Ast>{}(b.body), b.parameters.size());
|
||||||
|
},
|
||||||
|
|
||||||
|
[this](Array const& array) {
|
||||||
|
return std::accumulate(
|
||||||
|
array.elements.begin(), array.elements.end(), size_t(0),
|
||||||
|
[this](size_t h, Value const& v) { return hash_combine(h, operator()(v)); }
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
[](Chord const& chord) {
|
||||||
|
return std::accumulate(chord.notes.begin(), chord.notes.end(), size_t(0), [](size_t h, Note const& n) {
|
||||||
|
h = hash_combine(h, std::hash<std::optional<int>>{}(n.base));
|
||||||
|
h = hash_combine(h, std::hash<std::optional<Number>>{}(n.length));
|
||||||
|
h = hash_combine(h, std::hash<std::optional<i8>>{}(n.octave));
|
||||||
|
return h;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
[]<typename T>(T const& t) { return std::hash<T>{}(t); },
|
||||||
|
}, value.data);
|
||||||
|
|
||||||
|
return hash_combine(value_hash, size_t(value.data.index()));
|
||||||
|
}
|
17
musique/value/hash.hh
Normal file
17
musique/value/hash.hh
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef MUSIQUE_VALUE_HASH_HH
|
||||||
|
#define MUSIQUE_VALUE_HASH_HH
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#define Hash_For(Name) \
|
||||||
|
struct Name; \
|
||||||
|
template<> \
|
||||||
|
struct std::hash<Name> { \
|
||||||
|
size_t operator()(Name const&) const noexcept; \
|
||||||
|
}; \
|
||||||
|
|
||||||
|
Hash_For(Block)
|
||||||
|
Hash_For(Set)
|
||||||
|
Hash_For(Value)
|
||||||
|
|
||||||
|
#endif // MUSIQUE_VALUE_HASH_HH
|
60
musique/value/set.cc
Normal file
60
musique/value/set.cc
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#include <musique/value/value.hh>
|
||||||
|
#include <musique/value/set.hh>
|
||||||
|
|
||||||
|
|
||||||
|
Result<Value> Set::operator()(Interpreter&, std::vector<Value> params) const
|
||||||
|
{
|
||||||
|
auto copy = *this;
|
||||||
|
|
||||||
|
if (auto a = match<Number>(params)) {
|
||||||
|
auto [length] = *a;
|
||||||
|
for (auto& value : copy.elements) {
|
||||||
|
if (auto chord = get_if<Chord>(value)) {
|
||||||
|
// FIXME This const_cast should be unnesesary
|
||||||
|
for (auto ¬e : const_cast<Chord*>(chord)->notes) {
|
||||||
|
note.length = length;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Error reporting when parameters doesnt match
|
||||||
|
// TODO reconsider different options for this data structure invocation
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<Value> Set::index(Interpreter&, unsigned position) const
|
||||||
|
{
|
||||||
|
if (elements.size() < position) {
|
||||||
|
return errors::Out_Of_Range {
|
||||||
|
.required_index = position,
|
||||||
|
.size = elements.size()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// FIXME std::unordered_set::iterator has forward iterator, which means
|
||||||
|
// that any element lookup has complecity O(n). This may have serious
|
||||||
|
// performance implications and further investigation is needed.
|
||||||
|
return *std::next(elements.begin(), position);
|
||||||
|
}
|
||||||
|
|
||||||
|
usize Set::size() const
|
||||||
|
{
|
||||||
|
return elements.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Set::is_collection() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::strong_ordering Set::operator<=>(Set const&) const
|
||||||
|
{
|
||||||
|
unimplemented();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, Set const& set)
|
||||||
|
{
|
||||||
|
unimplemented();
|
||||||
|
return out;
|
||||||
|
}
|
36
musique/value/set.hh
Normal file
36
musique/value/set.hh
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef MUSIQUE_VALUE_SET_HH
|
||||||
|
#define MUSIQUE_VALUE_SET_HH
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
// Needs to be always first, before all the implicit template instantiations
|
||||||
|
#include <musique/value/hash.hh>
|
||||||
|
|
||||||
|
#include <musique/value/collection.hh>
|
||||||
|
#include <musique/value/function.hh>
|
||||||
|
#include <musique/common.hh>
|
||||||
|
|
||||||
|
struct Value;
|
||||||
|
|
||||||
|
struct Set : Collection, Function
|
||||||
|
{
|
||||||
|
std::unordered_set<Value> elements;
|
||||||
|
|
||||||
|
~Set() = default;
|
||||||
|
|
||||||
|
Result<Value> operator()(Interpreter &i, std::vector<Value> params) const override;
|
||||||
|
|
||||||
|
Result<Value> index(Interpreter &i, unsigned position) const override;
|
||||||
|
|
||||||
|
usize size() const override;
|
||||||
|
|
||||||
|
bool is_collection() const override;
|
||||||
|
|
||||||
|
bool operator==(Set const&) const = default;
|
||||||
|
std::strong_ordering operator<=>(Set const&) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, Set const& set);
|
||||||
|
|
||||||
|
#endif
|
@ -107,6 +107,11 @@ Value::Value(Chord chord)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value::Value(Set &&set)
|
||||||
|
: data(std::move(set))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Result<Value> Value::operator()(Interpreter &i, std::vector<Value> args) const
|
Result<Value> Value::operator()(Interpreter &i, std::vector<Value> args) const
|
||||||
{
|
{
|
||||||
if (auto func = get_if<Function>(data)) {
|
if (auto func = get_if<Function>(data)) {
|
||||||
@ -188,7 +193,10 @@ std::ostream& operator<<(std::ostream& os, Value const& v)
|
|||||||
[&](Nil) { os << "nil"; },
|
[&](Nil) { os << "nil"; },
|
||||||
[&](Intrinsic) { os << "<intrinisic>"; },
|
[&](Intrinsic) { os << "<intrinisic>"; },
|
||||||
[&](Block const&) { os << "<block>"; },
|
[&](Block const&) { os << "<block>"; },
|
||||||
[&](auto const& s) { os << s; }
|
[&](auto const& s) {
|
||||||
|
static_assert(requires { os << s; });
|
||||||
|
os << s;
|
||||||
|
}
|
||||||
}, v.data);
|
}, v.data);
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
@ -205,6 +213,7 @@ std::string_view type_name(Value const& v)
|
|||||||
[&](Nil const&) { return "nil"; },
|
[&](Nil const&) { return "nil"; },
|
||||||
[&](Number const&) { return "number"; },
|
[&](Number const&) { return "number"; },
|
||||||
[&](Symbol const&) { return "symbol"; },
|
[&](Symbol const&) { return "symbol"; },
|
||||||
|
[&](Set const&) { return "set"; },
|
||||||
}, v.data);
|
}, v.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,28 +237,3 @@ Result<std::vector<Value>> flatten(Interpreter &i, std::vector<Value> args)
|
|||||||
return flatten(i, std::span(args));
|
return flatten(i, std::span(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t std::hash<Value>::operator()(Value const& value) const
|
|
||||||
{
|
|
||||||
auto const value_hash = std::visit(Overloaded {
|
|
||||||
[](Nil) { return std::size_t(0); },
|
|
||||||
[](Intrinsic i) { return size_t(i.function_pointer); },
|
|
||||||
[](Block const& b) { return hash_combine(std::hash<Ast>{}(b.body), b.parameters.size()); },
|
|
||||||
[this](Array const& array) {
|
|
||||||
return std::accumulate(
|
|
||||||
array.elements.begin(), array.elements.end(), size_t(0),
|
|
||||||
[this](size_t h, Value const& v) { return hash_combine(h, operator()(v)); }
|
|
||||||
);
|
|
||||||
},
|
|
||||||
[](Chord const& chord) {
|
|
||||||
return std::accumulate(chord.notes.begin(), chord.notes.end(), size_t(0), [](size_t h, Note const& n) {
|
|
||||||
h = hash_combine(h, std::hash<std::optional<int>>{}(n.base));
|
|
||||||
h = hash_combine(h, std::hash<std::optional<Number>>{}(n.length));
|
|
||||||
h = hash_combine(h, std::hash<std::optional<i8>>{}(n.octave));
|
|
||||||
return h;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[]<typename T>(T const& t) { return std::hash<T>{}(t); },
|
|
||||||
}, value.data);
|
|
||||||
|
|
||||||
return hash_combine(value_hash, size_t(value.data.index()));
|
|
||||||
}
|
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#ifndef MUSIQUE_VALUE_HH
|
#ifndef MUSIQUE_VALUE_HH
|
||||||
#define MUSIQUE_VALUE_HH
|
#define MUSIQUE_VALUE_HH
|
||||||
|
|
||||||
|
// Needs to be always first, before all the implicit template instantiations
|
||||||
|
#include <musique/value/hash.hh>
|
||||||
|
|
||||||
#include <musique/accessors.hh>
|
#include <musique/accessors.hh>
|
||||||
#include <musique/common.hh>
|
#include <musique/common.hh>
|
||||||
#include <musique/lexer/token.hh>
|
#include <musique/lexer/token.hh>
|
||||||
@ -10,6 +13,7 @@
|
|||||||
#include <musique/value/chord.hh>
|
#include <musique/value/chord.hh>
|
||||||
#include <musique/value/intrinsic.hh>
|
#include <musique/value/intrinsic.hh>
|
||||||
#include <musique/value/note.hh>
|
#include <musique/value/note.hh>
|
||||||
|
#include <musique/value/set.hh>
|
||||||
|
|
||||||
struct Nil
|
struct Nil
|
||||||
{
|
{
|
||||||
@ -40,6 +44,7 @@ struct Value
|
|||||||
Value(char const* s); ///< Create value of type symbol holding provided symbol
|
Value(char const* s); ///< Create value of type symbol holding provided symbol
|
||||||
Value(std::string s); ///< Create value of type symbol holding provided symbol
|
Value(std::string s); ///< Create value of type symbol holding provided symbol
|
||||||
Value(std::string_view s); ///< Create value of type symbol holding provided symbol
|
Value(std::string_view s); ///< Create value of type symbol holding provided symbol
|
||||||
|
Value(Set &&set); ///< Create value of type set holding provided set
|
||||||
explicit Value(std::vector<Value> &&array); ///< Create value of type array holding provided array
|
explicit Value(std::vector<Value> &&array); ///< Create value of type array holding provided array
|
||||||
|
|
||||||
// TODO Most strings should not be allocated by Value, but reference to string allocated previously
|
// TODO Most strings should not be allocated by Value, but reference to string allocated previously
|
||||||
@ -54,6 +59,7 @@ struct Value
|
|||||||
Intrinsic,
|
Intrinsic,
|
||||||
Block,
|
Block,
|
||||||
Array,
|
Array,
|
||||||
|
Set,
|
||||||
Chord,
|
Chord,
|
||||||
Macro
|
Macro
|
||||||
> data = Nil{};
|
> data = Nil{};
|
||||||
@ -108,9 +114,6 @@ inline T* get_if(Value& v) { return get_if<T>(v.data); }
|
|||||||
/// Returns type name of Value type
|
/// Returns type name of Value type
|
||||||
std::string_view type_name(Value const& v);
|
std::string_view type_name(Value const& v);
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, Value const& v);
|
|
||||||
template<> struct std::hash<Value> { std::size_t operator()(Value const&) const; };
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Result<Value> wrap_value(Result<T> &&value)
|
Result<Value> wrap_value(Result<T> &&value)
|
||||||
{
|
{
|
||||||
@ -170,4 +173,6 @@ constexpr auto match(Values& ...values) -> std::optional<std::tuple<T&...>>
|
|||||||
} (std::make_index_sequence<sizeof...(T)>{});
|
} (std::make_index_sequence<sizeof...(T)>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, Value const& v);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user