From 946d4b96b1d3ae0589920cf18fff35cb2679d4e7 Mon Sep 17 00:00:00 2001 From: Robert Bendun Date: Thu, 2 Jun 2022 23:17:02 +0200 Subject: [PATCH] Permutations! --- examples/permutations.mq | 11 +++++++++ src/interpreter.cc | 23 +++++++++++++++++++ src/main.cc | 7 +++--- src/musique.hh | 5 +++- src/value.cc | 49 +++++++++++++++++++++++++++++++++++++++- 5 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 examples/permutations.mq diff --git a/examples/permutations.mq b/examples/permutations.mq new file mode 100644 index 0000000..8b30873 --- /dev/null +++ b/examples/permutations.mq @@ -0,0 +1,11 @@ +var factorial = [n | if (n < 2) [1] [factorial (n-1) * n]]; + +var for_all_permutations = [array fun | + var iter = [start stop x | if (start >= stop) [x] [iter (start+1) stop (fun x)]]; + iter 0 (factorial (len array)) array +]; + +for_all_permutations (flat 1 2 3 4 5) [array| + say array; + permute array +]; diff --git a/src/interpreter.cc b/src/interpreter.cc index 6d737e5..98b0705 100644 --- a/src/interpreter.cc +++ b/src/interpreter.cc @@ -362,6 +362,29 @@ Interpreter::Interpreter() return Value::from(std::move(array)); }); + global.force_define("permute", +[](Interpreter &i, std::vector args) -> Result { + Array array; + for (auto &arg : args) { + switch (arg.type) { + case Value::Type::Array: + std::move(arg.array.elements.begin(), arg.array.elements.end(), std::back_inserter(array.elements)); + break; + + case Value::Type::Block: + for (auto j = 0u; j < arg.blk.size(); ++j) { + array.elements.push_back(Try(arg.blk.index(i, j))); + } + break; + + default: + array.elements.push_back(std::move(arg)); + } + } + + std::next_permutation(array.elements.begin(), array.elements.end()); + return Value::from(std::move(array)); + }); + global.force_define("chord", +[](Interpreter &i, std::vector args) -> Result { Chord chord; Try(create_chord(chord.notes, i, std::move(args))); diff --git a/src/main.cc b/src/main.cc index c809950..a2a8670 100644 --- a/src/main.cc +++ b/src/main.cc @@ -89,7 +89,7 @@ struct Runner } /// Run given source - Result run(std::string_view source, std::string_view filename) + Result run(std::string_view source, std::string_view filename, bool output = false) { auto ast = Try(Parser::parse(source, filename)); @@ -97,7 +97,7 @@ struct Runner dump(ast); return {}; } - if (auto result = Try(interpreter.eval(std::move(ast))); result.type != Value::Type::Nil) { + if (auto result = Try(interpreter.eval(std::move(ast))); output && result.type != Value::Type::Nil) { std::cout << result << std::endl; } return {}; @@ -185,6 +185,7 @@ static Result Main(std::span args) } if (runnables.empty() || enable_repl) { + enable_repl = true; for (;;) { char *input_buffer = readline("> "); if (input_buffer == nullptr) { @@ -215,7 +216,7 @@ static Result Main(std::span args) continue; } - auto result = runner.run(raw, ""); + auto result = runner.run(raw, "", true); if (not result.has_value()) { std::cout << std::flush; std::cerr << result.error() << std::flush; diff --git a/src/musique.hh b/src/musique.hh index fdd1697..609bdf8 100644 --- a/src/musique.hh +++ b/src/musique.hh @@ -667,6 +667,8 @@ struct Note bool operator==(Note const&) const; + std::partial_ordering operator<=>(Note const&) const; + /// Simplify note by adding base to octave if octave is present void simplify_inplace(); }; @@ -714,7 +716,6 @@ struct Value /// Using Explicit_Bool to prevent from implicit casts static Value from(Explicit_Bool b); - static Value from(Number n); ///< Create value of type number holding provided number static Value from(std::string s); ///< Create value of type symbol holding provided symbol static Value from(std::string_view s); ///< Create value of type symbol holding provided symbol @@ -777,6 +778,8 @@ struct Value usize size() const; bool operator==(Value const& other) const; + + std::partial_ordering operator<=>(Value const& other) const; }; template diff --git a/src/value.cc b/src/value.cc index b89ee34..f4c3781 100644 --- a/src/value.cc +++ b/src/value.cc @@ -249,6 +249,44 @@ usize Value::size() const unreachable(); } +std::partial_ordering Value::operator<=>(Value const& rhs) const +{ + // TODO Block - array comparison should be allowed + if (type != rhs.type) { + return std::partial_ordering::unordered; + } + + switch (type) { + case Type::Nil: + return std::partial_ordering::equivalent; + + case Type::Bool: + return b <=> rhs.b; + + case Type::Symbol: + return s <=> rhs.s; + + case Type::Number: + return n <=> rhs.n; + + case Type::Array: + return std::lexicographical_compare_three_way( + array.elements.begin(), array.elements.end(), + rhs.array.elements.begin(), rhs.array.elements.end() + ); + + case Type::Music: + return chord.notes.front() <=> rhs.chord.notes.front(); + + // Block should be compared but after evaluation so for now it's Type::Block + case Type::Block: + case Type::Intrinsic: + return std::partial_ordering::unordered; + } + + unreachable(); +} + std::ostream& operator<<(std::ostream& os, Value const& v) { switch (v.type) { @@ -391,6 +429,16 @@ void Note::simplify_inplace() } } +std::partial_ordering Note::operator<=>(Note const& rhs) const +{ + if (octave.has_value() == rhs.octave.has_value()) { + if (octave.has_value()) + return (12 * *octave) + base <=> (12 * *rhs.octave) + rhs.base; + return base <=> rhs.base; + } + return std::partial_ordering::unordered; +} + std::ostream& operator<<(std::ostream& os, Note note) { note.simplify_inplace(); @@ -401,7 +449,6 @@ std::ostream& operator<<(std::ostream& os, Note note) if (note.length) { os << ":len=" << *note.length; } - return os; }