Working arrays, flat function

This commit is contained in:
Robert Bendun 2022-05-24 19:09:37 +02:00
parent 64417bf187
commit 6611512b1f
4 changed files with 98 additions and 8 deletions

View File

@ -67,6 +67,14 @@ dtn 3/64
Dostępne funkcje
---------------------------------------------------------------------------
flat : ...items : any -> array
tworzy tablicę z dostarczonych elementów, rozsypując elementy indeksowalne
przykład:
flat 1 2 3 tworzy tablicę 1, 2, 3
flat [1;2] 2 3 tworzy tablicę 1, 2, 2, 3
flat [[1;2]; [3;4]] 5 6 tworzy tablicę [1;2], [3;4], 5, 6
if : condition: bool, block: block -> (eval block)
wywołuje block jeśli condition jest:
dla b: bool jest b == true
@ -78,6 +86,11 @@ if : condition: Bool, then: Block, else: Block -> (eval then or eval else)
jeśli condition jest prawdziwe wg zasad wyżej wywołaj then
w innym przypadku wywołaj else
len : array -> number
zwraca ilość elementów w tablicy
Przykład:
len (flat 5 6 7) == 3
len : block -> number
zwraca ilość elementów (liczbę indeksowalnych pozycji) wewnątrz bloku
Przykład:

View File

@ -106,12 +106,8 @@ Interpreter::Interpreter()
global.force_define("len", +[](Interpreter &, std::vector<Value> args) -> Result<Value> {
assert(args.size() == 1, "len only accepts one argument");
assert(args.front().type == Value::Type::Block, "Only blocks can be measure");
if (args.front().blk.body.type != Ast::Type::Sequence) {
return Value::from(Number(1));
} else {
return Value::from(Number(args.front().blk.body.arguments.size()));
}
assert(args.front().type == Value::Type::Block || args.front().type == Value::Type::Array, "Only blocks and arrays can have length");
return Value::from(Number(args.front().size()));
});
global.force_define("play", +[](Interpreter &i, std::vector<Value> args) -> Result<Value> {
@ -122,6 +118,27 @@ Interpreter::Interpreter()
return Value{};
});
global.force_define("flat", +[](Interpreter &i, std::vector<Value> args) -> Result<Value> {
Array array;
for (auto &arg : args) {
switch (arg.type) {
case Value::Type::Array:
std::move(arg.array.elements.begin(), arg.array.elements.end(), std::back_inserter(array.elements));
break;
case Value::Type::Block:
for (auto j = 0u; j < arg.blk.size(); ++j) {
array.elements.push_back(Try(arg.blk.index(i, j)));
}
break;
default:
array.elements.push_back(std::move(arg));
}
}
return Value::from(std::move(array));
});
operators["+"] = binary_operator<std::plus<>>();
operators["-"] = binary_operator<std::minus<>>();
operators["*"] = binary_operator<std::multiplies<>>();

View File

@ -466,6 +466,7 @@ struct Block
Result<Value> operator()(Interpreter &i, std::vector<Value> params);
Result<Value> index(Interpreter &i, unsigned position);
usize size() const;
};
struct Note
@ -500,8 +501,13 @@ struct Array
std::vector<Value> elements;
Result<Value> index(Interpreter &i, unsigned position);
usize size() const;
bool operator==(Array const&) const = default;
};
std::ostream& operator<<(std::ostream& os, Array const& v);
// TODO Add location
struct Value
{
@ -546,6 +552,7 @@ struct Value
Intrinsic intr;
Block blk;
Note note;
Array array;
// TODO Most strings should not be allocated by Value, but reference to string allocated previously
// Wrapper for std::string is needed that will allocate only when needed, middle ground between:
@ -557,6 +564,7 @@ struct Value
bool falsy() const;
Result<Value> operator()(Interpreter &i, std::vector<Value> args);
Result<Value> index(Interpreter &i, unsigned position);
usize size() const;
bool operator==(Value const& other) const;
};

View File

@ -138,6 +138,14 @@ Value Value::from(Block &&block)
return v;
}
Value Value::from(Array &&array)
{
Value v;
v.type = Type::Array;
v.array = std::move(array);
return v;
}
Value Value::from(Note n)
{
Value v;
@ -217,7 +225,23 @@ bool Value::operator==(Value const& other) const
case Type::Block: return false; // TODO Reconsider if functions are comparable
case Type::Bool: return b == other.b;
case Type::Music: return note == other.note;
case Type::Array: unimplemented();
case Type::Array: return array == other.array;
}
unreachable();
}
usize Value::size() const
{
switch (type) {
case Type::Array:
return array.size();
case Type::Block:
return blk.size();
default:
assert(false, "This type does not support Value::size()"); // TODO(assert)
}
unreachable();
@ -245,7 +269,7 @@ std::ostream& operator<<(std::ostream& os, Value const& v)
return os << "<block>";
case Value::Type::Array:
unimplemented();
return os << v.array;
case Value::Type::Music:
return os << v.note;
@ -299,6 +323,34 @@ Result<Value> Block::index(Interpreter &i, unsigned position)
return i.eval((Ast)body.arguments[position]);
}
usize Block::size() const
{
return body.type == Ast::Type::Sequence ? body.arguments.size() : 1;
}
Result<Value> Array::index(Interpreter &, unsigned position)
{
assert(position < elements.size(), "Out of range"); // TODO(assert)
return elements[position];
}
usize Array::size() const
{
return elements.size();
}
std::ostream& operator<<(std::ostream& os, Array const& v)
{
os << '[';
for (auto it = v.elements.begin(); it != v.elements.end(); ++it) {
os << *it;
if (std::next(it) != v.elements.end()) {
os << "; ";
}
}
return os << ']';
}
std::optional<Note> Note::from(std::string_view literal)
{
if (auto note = note_index(literal); note != u8(-1)) {