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
|
bin/debug/musique: $(Debug_Obj) bin/debug/main.o src/*.hh
|
||||||
@echo "CXX $@"
|
@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
|
bin/debug/%.o: src/%.cc src/*.hh
|
||||||
@echo "CXX $@"
|
@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>
|
#include <thread>
|
||||||
|
|
||||||
template<typename Binary_Operation>
|
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());
|
||||||
auto result = std::move(args.front());
|
for (auto &v : std::span(args).subspan(1)) {
|
||||||
for (auto &v : std::span(args).subspan(1)) {
|
assert(result.type == Value::Type::Number, "LHS should be a number"); // TODO(assert)
|
||||||
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)
|
||||||
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>>) {
|
||||||
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);
|
||||||
result.n = Binary_Operation{}(std::move(result.n), std::move(v).n);
|
} else {
|
||||||
} else {
|
result.type = Value::Type::Bool;
|
||||||
result.type = Value::Type::Bool;
|
result.b = Binary_Operation{}(std::move(result.n), std::move(v).n);
|
||||||
result.b = Binary_Operation{}(std::move(result.n), std::move(v).n);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
}
|
||||||
};
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Binary_Predicate>
|
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)
|
||||||
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())));
|
||||||
return Value::from(Binary_Predicate{}(std::move(args.front()), std::move(args.back())));
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Binary_Predicate>
|
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.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.front().type == args.back().type, "Only values of the same type can be ordered"); // TODO(assert)
|
|
||||||
|
|
||||||
switch (args.front().type) {
|
switch (args.front().type) {
|
||||||
case Value::Type::Number:
|
case Value::Type::Number:
|
||||||
return Value::from(Binary_Predicate{}(std::move(args.front()).n, std::move(args.back()).n));
|
return Value::from(Binary_Predicate{}(std::move(args.front()).n, std::move(args.back()).n));
|
||||||
|
|
||||||
case Value::Type::Bool:
|
case Value::Type::Bool:
|
||||||
return Value::from(Binary_Predicate{}(std::move(args.front()).b, std::move(args.back()).b));
|
return Value::from(Binary_Predicate{}(std::move(args.front()).b, std::move(args.back()).b));
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(false, "Cannot compare value of given types"); // TODO(assert)
|
assert(false, "Cannot compare value of given types"); // TODO(assert)
|
||||||
}
|
}
|
||||||
unreachable();
|
unreachable();
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registers constants like `fn = full note = 1/1`
|
/// 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 {};
|
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:
|
/// Creates implementation of plus/minus operator that support following operations:
|
||||||
/// number, number -> number (standard math operations)
|
/// number, number -> number (standard math operations)
|
||||||
/// n: number, m: music -> music
|
/// n: number, m: music -> music
|
||||||
/// m: music, n: number -> music moves m by n semitones (+ goes up, - goes down)
|
/// m: music, n: number -> music moves m by n semitones (+ goes up, - goes down)
|
||||||
template<typename Binary_Operation>
|
template<typename Binary_Operation>
|
||||||
[[gnu::always_inline]]
|
static Result<Value> plus_minus_operator(Interpreter &interpreter, std::vector<Value> args)
|
||||||
static inline auto plus_minus_operator()
|
|
||||||
{
|
{
|
||||||
return [](Interpreter&, std::vector<Value> args) -> Result<Value> {
|
assert(args.size() == 2, "Binary operator only accepts 2 arguments");
|
||||||
assert(args.size() == 2, "Binary operator only accepts 2 arguments");
|
auto lhs = std::move(args.front());
|
||||||
auto lhs = std::move(args.front());
|
auto rhs = std::move(args.back());
|
||||||
auto rhs = std::move(args.back());
|
|
||||||
|
|
||||||
if (lhs.type == rhs.type && lhs.type == Value::Type::Number) {
|
if (lhs.type == rhs.type && lhs.type == Value::Type::Number) {
|
||||||
return Value::from(Binary_Operation{}(std::move(lhs).n, std::move(rhs).n));
|
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) {
|
if (lhs.type == Value::Type::Number && rhs.type == Value::Type::Music) {
|
||||||
music_number_operation:
|
for (auto ¬e : rhs.chord.notes) {
|
||||||
for (auto ¬e : lhs.chord.notes) {
|
note.base = Binary_Operation{}(lhs.n.as_int(), note.base);
|
||||||
note.base = Binary_Operation{}(note.base, rhs.n.as_int());
|
note.simplify_inplace();
|
||||||
note.simplify_inplace();
|
|
||||||
}
|
|
||||||
return lhs;
|
|
||||||
}
|
}
|
||||||
|
return rhs;
|
||||||
|
}
|
||||||
|
|
||||||
if (lhs.type == Value::Type::Number && rhs.type == Value::Type::Music) {
|
if (is_indexable(lhs.type) && !is_indexable(rhs.type)) {
|
||||||
std::swap(lhs, rhs);
|
Array array;
|
||||||
goto music_number_operation;
|
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)
|
if (!is_indexable(lhs.type) && is_indexable(rhs.type)) {
|
||||||
unreachable();
|
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()
|
Interpreter::Interpreter()
|
||||||
@ -191,10 +238,7 @@ Interpreter::Interpreter()
|
|||||||
});
|
});
|
||||||
|
|
||||||
global.force_define("play", +[](Interpreter &i, std::vector<Value> args) -> Result<Value> {
|
global.force_define("play", +[](Interpreter &i, std::vector<Value> args) -> Result<Value> {
|
||||||
for (auto &arg : args) {
|
Try(play_notes(i, std::move(args)));
|
||||||
assert(arg.type == Value::Type::Music, "Only music values can be played"); // TODO(assert)
|
|
||||||
i.play(arg.chord);
|
|
||||||
}
|
|
||||||
return Value{};
|
return Value{};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -225,18 +269,18 @@ Interpreter::Interpreter()
|
|||||||
return Value::from(std::move(chord));
|
return Value::from(std::move(chord));
|
||||||
});
|
});
|
||||||
|
|
||||||
operators["+"] = plus_minus_operator<std::plus<>>();
|
operators["+"] = plus_minus_operator<std::plus<>>;
|
||||||
operators["-"] = plus_minus_operator<std::minus<>>();
|
operators["-"] = plus_minus_operator<std::minus<>>;
|
||||||
operators["*"] = binary_operator<std::multiplies<>>();
|
operators["*"] = binary_operator<std::multiplies<>>;
|
||||||
operators["/"] = binary_operator<std::divides<>>();
|
operators["/"] = binary_operator<std::divides<>>;
|
||||||
|
|
||||||
operators["<"] = comparison_operator<std::less<>>();
|
operators["<"] = comparison_operator<std::less<>>;
|
||||||
operators[">"] = comparison_operator<std::greater<>>();
|
operators[">"] = comparison_operator<std::greater<>>;
|
||||||
operators["<="] = comparison_operator<std::less_equal<>>();
|
operators["<="] = comparison_operator<std::less_equal<>>;
|
||||||
operators[">="] = comparison_operator<std::greater_equal<>>();
|
operators[">="] = comparison_operator<std::greater_equal<>>;
|
||||||
|
|
||||||
operators["=="] = equality_operator<std::equal_to<>>();
|
operators["=="] = equality_operator<std::equal_to<>>;
|
||||||
operators["!="] = equality_operator<std::not_equal_to<>>();
|
operators["!="] = equality_operator<std::not_equal_to<>>;
|
||||||
|
|
||||||
operators["."] = +[](Interpreter &i, std::vector<Value> args) -> Result<Value> {
|
operators["."] = +[](Interpreter &i, std::vector<Value> args) -> Result<Value> {
|
||||||
assert(args.size() == 2, "Operator . requires two arguments"); // TODO(assert)
|
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:
|
case Type::Block:
|
||||||
return blk.index(i, position);
|
return blk.index(i, position);
|
||||||
|
|
||||||
|
case Type::Array:
|
||||||
|
return array.index(i, position);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(false, "Block indexing is not supported for this type"); // TODO(assert)
|
assert(false, "Block indexing is not supported for this type"); // TODO(assert)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user