Begining of support of array programming
This commit is contained in:
parent
5d410a1ffd
commit
70e1431f05
2
Makefile
2
Makefile
@ -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
1
examples/fib.mq
Normal file
@ -0,0 +1 @@
|
||||
var fib = [n | if (n <= 1) [ n ] [ fib (n-1) + fib (n-2) ] ];
|
15
prelude.mq
Normal file
15
prelude.mq
Normal 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;
|
@ -5,52 +5,46 @@
|
||||
#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)
|
||||
assert(v.type == Value::Type::Number, "RHS should be a number"); // TODO(assert)
|
||||
if constexpr (std::is_same_v<Number, std::invoke_result_t<Binary_Operation, Number, Number>>) {
|
||||
result.n = Binary_Operation{}(std::move(result.n), std::move(v).n);
|
||||
} else {
|
||||
result.type = Value::Type::Bool;
|
||||
result.b = Binary_Operation{}(std::move(result.n), std::move(v).n);
|
||||
}
|
||||
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)
|
||||
assert(v.type == Value::Type::Number, "RHS should be a number"); // TODO(assert)
|
||||
if constexpr (std::is_same_v<Number, std::invoke_result_t<Binary_Operation, Number, Number>>) {
|
||||
result.n = Binary_Operation{}(std::move(result.n), std::move(v).n);
|
||||
} else {
|
||||
result.type = Value::Type::Bool;
|
||||
result.b = Binary_Operation{}(std::move(result.n), std::move(v).n);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
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())));
|
||||
};
|
||||
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)
|
||||
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)
|
||||
|
||||
switch (args.front().type) {
|
||||
case Value::Type::Number:
|
||||
return Value::from(Binary_Predicate{}(std::move(args.front()).n, std::move(args.back()).n));
|
||||
switch (args.front().type) {
|
||||
case Value::Type::Number:
|
||||
return Value::from(Binary_Predicate{}(std::move(args.front()).n, std::move(args.back()).n));
|
||||
|
||||
case Value::Type::Bool:
|
||||
return Value::from(Binary_Predicate{}(std::move(args.front()).b, std::move(args.back()).b));
|
||||
case Value::Type::Bool:
|
||||
return Value::from(Binary_Predicate{}(std::move(args.front()).b, std::move(args.back()).b));
|
||||
|
||||
default:
|
||||
assert(false, "Cannot compare value of given types"); // TODO(assert)
|
||||
}
|
||||
unreachable();
|
||||
};
|
||||
default:
|
||||
assert(false, "Cannot compare value of given types"); // TODO(assert)
|
||||
}
|
||||
unreachable();
|
||||
}
|
||||
|
||||
/// Registers constants like `fn = full note = 1/1`
|
||||
@ -118,40 +112,93 @@ 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());
|
||||
assert(args.size() == 2, "Binary operator only accepts 2 arguments");
|
||||
auto lhs = std::move(args.front());
|
||||
auto rhs = std::move(args.back());
|
||||
|
||||
if (lhs.type == rhs.type && lhs.type == Value::Type::Number) {
|
||||
return Value::from(Binary_Operation{}(std::move(lhs).n, std::move(rhs).n));
|
||||
if (lhs.type == rhs.type && lhs.type == Value::Type::Number) {
|
||||
return Value::from(Binary_Operation{}(std::move(lhs).n, std::move(rhs).n));
|
||||
}
|
||||
|
||||
if (lhs.type == Value::Type::Music && rhs.type == Value::Type::Number) {
|
||||
for (auto ¬e : lhs.chord.notes) {
|
||||
note.base = Binary_Operation{}(note.base, rhs.n.as_int());
|
||||
note.simplify_inplace();
|
||||
}
|
||||
return lhs;
|
||||
}
|
||||
|
||||
if (lhs.type == Value::Type::Music && rhs.type == Value::Type::Number) {
|
||||
music_number_operation:
|
||||
for (auto ¬e : lhs.chord.notes) {
|
||||
note.base = Binary_Operation{}(note.base, rhs.n.as_int());
|
||||
note.simplify_inplace();
|
||||
}
|
||||
return lhs;
|
||||
if (lhs.type == Value::Type::Number && rhs.type == Value::Type::Music) {
|
||||
for (auto ¬e : rhs.chord.notes) {
|
||||
note.base = Binary_Operation{}(lhs.n.as_int(), note.base);
|
||||
note.simplify_inplace();
|
||||
}
|
||||
return rhs;
|
||||
}
|
||||
|
||||
if (lhs.type == Value::Type::Number && rhs.type == Value::Type::Music) {
|
||||
std::swap(lhs, rhs);
|
||||
goto music_number_operation;
|
||||
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));
|
||||
}
|
||||
|
||||
assert(false, "Unsupported types for this operation"); // TODO(assert)
|
||||
unreachable();
|
||||
};
|
||||
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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user