diff --git a/doc/cheatsheet.txt b/doc/cheatsheet.txt index e1170d7..589c9a3 100644 --- a/doc/cheatsheet.txt +++ b/doc/cheatsheet.txt @@ -16,6 +16,9 @@ Ustawianie oktawy i długości, a następnie modyfikacja (c 8 fn) 4 zmienia oktawę na 4 (c 8 fn) 4 qn zmienia oktawę na 4 i długość na 1/4 +Stworzenie akordu + c123 == chord[c; c#; d; d#] + Arytmetyka (aktualnie brak wsparcia dla precedensji operatorów) 3 * (4 * 12 - 8) @@ -100,3 +103,6 @@ len : block -> number play : music... -> nil odtwarza sekwencyjnie otrzymane wartości muzyczne + +chord : (collection | music)... -> music + tworzy akord z przekazanych wartości muzycznych diff --git a/src/interpreter.cc b/src/interpreter.cc index f8e475c..06d1451 100644 --- a/src/interpreter.cc +++ b/src/interpreter.cc @@ -74,6 +74,50 @@ static inline void register_note_length_constants() global.force_define("dtn", Value::from(Number(3, 64))); } +template +concept With_Index_Method = requires (T t, Interpreter interpreter, usize position) { + { t.index(interpreter, position) } -> std::convertible_to>; +}; + +template +concept With_Index_Operator = requires (T t, unsigned i) { + { t[i] } -> std::convertible_to; +}; + +template +concept Iterable = (With_Index_Method || With_Index_Operator) && requires (T const t) { + { t.size() } -> std::convertible_to; +}; + +template +static inline Result create_chord(std::vector &chord, Interpreter &interpreter, T args) +{ + for (auto i = 0u; i < args.size(); ++i) { + Value arg; + if constexpr (With_Index_Method) { + arg = Try(args.index(interpreter, i)); + } else { + arg = std::move(args[i]); + } + + switch (arg.type) { + case Value::Type::Array: + case Value::Type::Block: + Try(create_chord(chord, interpreter, std::move(arg))); + break; + + case Value::Type::Music: + std::move(arg.chord.notes.begin(), arg.chord.notes.end(), std::back_inserter(chord)); + break; + + default: + assert(false, "this type is not supported inside chord"); + } + } + + return {}; +} + Interpreter::Interpreter() { { // Context initialization @@ -139,6 +183,12 @@ Interpreter::Interpreter() 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))); + return Value::from(std::move(chord)); + }); + operators["+"] = binary_operator>(); operators["-"] = binary_operator>(); operators["*"] = binary_operator>();