Begining of support of array programming

This commit is contained in:
Robert Bendun 2022-05-25 04:30:24 +02:00
parent 5d410a1ffd
commit 70e1431f05
5 changed files with 132 additions and 69 deletions

View File

@ -53,7 +53,7 @@ bin/musique: $(Release_Obj) bin/main.o src/*.hh lib/midi/libmidi-alsa.a
bin/debug/musique: $(Debug_Obj) bin/debug/main.o src/*.hh
@echo "CXX $@"
@$(CXX) $(CXXFLAGS) $(DEBUG_FLAGS) $(CPPFLAGS) -o $@ $(Debug_Obj) bin/debug/main.o
@$(CXX) $(CXXFLAGS) $(DEBUG_FLAGS) $(CPPFLAGS) -o $@ $(Debug_Obj) bin/debug/main.o $(LDFLAGS) $(LDLIBS)
bin/debug/%.o: src/%.cc src/*.hh
@echo "CXX $@"

1
examples/fib.mq Normal file
View File

@ -0,0 +1 @@
var fib = [n | if (n <= 1) [ n ] [ fib (n-1) + fib (n-2) ] ];

15
prelude.mq Normal file
View File

@ -0,0 +1,15 @@
var iota = [n |
var iter = [start stop |
if (start >= stop) [[]] [flat start (iter (start+1) stop)]
];
iter 0 n
];
var map = [array fun|
var iter = [start stop |
if (start >= stop) [[]] [flat (fun (array.start)) (iter (start+1) stop)]
];
iter 0 (len array)
];
var cdur = c47;

View File

@ -5,9 +5,8 @@
#include <thread>
template<typename Binary_Operation>
constexpr auto binary_operator()
static Result<Value> binary_operator(Interpreter&, std::vector<Value> args)
{
return [](Interpreter&, std::vector<Value> args) -> Result<Value> {
auto result = std::move(args.front());
for (auto &v : std::span(args).subspan(1)) {
assert(result.type == Value::Type::Number, "LHS should be a number"); // TODO(assert)
@ -20,22 +19,18 @@ constexpr auto binary_operator()
}
}
return result;
};
}
template<typename Binary_Predicate>
constexpr auto equality_operator()
static Result<Value> equality_operator(Interpreter&, std::vector<Value> args)
{
return [](Interpreter&, std::vector<Value> args) -> Result<Value> {
assert(args.size() == 2, "(in)Equality only allows for 2 operands"); // TODO(assert)
return Value::from(Binary_Predicate{}(std::move(args.front()), std::move(args.back())));
};
}
template<typename Binary_Predicate>
constexpr auto comparison_operator()
static Result<Value> comparison_operator(Interpreter&, std::vector<Value> args)
{
return [](Interpreter&, std::vector<Value> args) -> Result<Value> {
assert(args.size() == 2, "Ordering only allows for 2 operands"); // TODO(assert)
assert(args.front().type == args.back().type, "Only values of the same type can be ordered"); // TODO(assert)
@ -50,7 +45,6 @@ constexpr auto comparison_operator()
assert(false, "Cannot compare value of given types"); // TODO(assert)
}
unreachable();
};
}
/// Registers constants like `fn = full note = 1/1`
@ -118,15 +112,47 @@ static inline Result<void> create_chord(std::vector<Note> &chord, Interpreter &i
return {};
}
template<Iterable T>
static inline Result<void> play_notes(Interpreter &interpreter, T args)
{
for (auto i = 0u; i < args.size(); ++i) {
Value arg;
if constexpr (With_Index_Method<T>) {
arg = Try(args.index(interpreter, i));
} else {
arg = std::move(args[i]);
}
switch (arg.type) {
case Value::Type::Array:
case Value::Type::Block:
Try(play_notes(interpreter, std::move(arg)));
break;
case Value::Type::Music:
interpreter.play(arg.chord);
break;
default:
assert(false, "this type does not support playing");
}
}
return {};
}
constexpr bool is_indexable(Value::Type type)
{
return type == Value::Type::Array || type == Value::Type::Block;
}
/// Creates implementation of plus/minus operator that support following operations:
/// number, number -> number (standard math operations)
/// n: number, m: music -> music
/// m: music, n: number -> music moves m by n semitones (+ goes up, - goes down)
template<typename Binary_Operation>
[[gnu::always_inline]]
static inline auto plus_minus_operator()
static Result<Value> plus_minus_operator(Interpreter &interpreter, std::vector<Value> args)
{
return [](Interpreter&, std::vector<Value> args) -> Result<Value> {
assert(args.size() == 2, "Binary operator only accepts 2 arguments");
auto lhs = std::move(args.front());
auto rhs = std::move(args.back());
@ -136,7 +162,6 @@ static inline auto plus_minus_operator()
}
if (lhs.type == Value::Type::Music && rhs.type == Value::Type::Number) {
music_number_operation:
for (auto &note : lhs.chord.notes) {
note.base = Binary_Operation{}(note.base, rhs.n.as_int());
note.simplify_inplace();
@ -145,13 +170,35 @@ music_number_operation:
}
if (lhs.type == Value::Type::Number && rhs.type == Value::Type::Music) {
std::swap(lhs, rhs);
goto music_number_operation;
for (auto &note : rhs.chord.notes) {
note.base = Binary_Operation{}(lhs.n.as_int(), note.base);
note.simplify_inplace();
}
return rhs;
}
if (is_indexable(lhs.type) && !is_indexable(rhs.type)) {
Array array;
for (auto i = 0u; i < lhs.size(); ++i) {
array.elements.push_back(Try(
plus_minus_operator<Binary_Operation>(
interpreter, { Try(lhs.index(interpreter, i)), rhs })));
}
return Value::from(std::move(array));
}
if (!is_indexable(lhs.type) && is_indexable(rhs.type)) {
Array array;
for (auto i = 0u; i < rhs.size(); ++i) {
array.elements.push_back(Try(
plus_minus_operator<Binary_Operation>(
interpreter, { lhs, Try(rhs.index(interpreter, i)) })));
}
return Value::from(std::move(array));
}
assert(false, "Unsupported types for this operation"); // TODO(assert)
unreachable();
};
}
Interpreter::Interpreter()
@ -191,10 +238,7 @@ Interpreter::Interpreter()
});
global.force_define("play", +[](Interpreter &i, std::vector<Value> args) -> Result<Value> {
for (auto &arg : args) {
assert(arg.type == Value::Type::Music, "Only music values can be played"); // TODO(assert)
i.play(arg.chord);
}
Try(play_notes(i, std::move(args)));
return Value{};
});
@ -225,18 +269,18 @@ Interpreter::Interpreter()
return Value::from(std::move(chord));
});
operators["+"] = plus_minus_operator<std::plus<>>();
operators["-"] = plus_minus_operator<std::minus<>>();
operators["*"] = binary_operator<std::multiplies<>>();
operators["/"] = binary_operator<std::divides<>>();
operators["+"] = plus_minus_operator<std::plus<>>;
operators["-"] = plus_minus_operator<std::minus<>>;
operators["*"] = binary_operator<std::multiplies<>>;
operators["/"] = binary_operator<std::divides<>>;
operators["<"] = comparison_operator<std::less<>>();
operators[">"] = comparison_operator<std::greater<>>();
operators["<="] = comparison_operator<std::less_equal<>>();
operators[">="] = comparison_operator<std::greater_equal<>>();
operators["<"] = comparison_operator<std::less<>>;
operators[">"] = comparison_operator<std::greater<>>;
operators["<="] = comparison_operator<std::less_equal<>>;
operators[">="] = comparison_operator<std::greater_equal<>>;
operators["=="] = equality_operator<std::equal_to<>>();
operators["!="] = equality_operator<std::not_equal_to<>>();
operators["=="] = equality_operator<std::equal_to<>>;
operators["!="] = equality_operator<std::not_equal_to<>>;
operators["."] = +[](Interpreter &i, std::vector<Value> args) -> Result<Value> {
assert(args.size() == 2, "Operator . requires two arguments"); // TODO(assert)

View File

@ -202,6 +202,9 @@ Result<Value> Value::index(Interpreter &i, unsigned position)
case Type::Block:
return blk.index(i, position);
case Type::Array:
return array.index(i, position);
default:
assert(false, "Block indexing is not supported for this type"); // TODO(assert)
}