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 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
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,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 &note : 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 &note : rhs.chord.notes) {
for (auto &note : 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)

View File

@ -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)
} }