Block indexing and len builtin

This commit is contained in:
Robert Bendun 2022-05-22 16:43:36 +02:00
parent 23b9d901ac
commit f28cb10669
6 changed files with 50 additions and 11 deletions

11
examples/arrays.mq Normal file
View File

@ -0,0 +1,11 @@
var numbers = [1;2;3;4;5];
var for = [array iteration |
var iter = [i | if (i < (len array)) [
iteration (numbers.i);
iter (i+1)
]];
iter 0
];
for numbers say;

View File

@ -95,6 +95,16 @@ Interpreter::Interpreter(std::ostream& out)
return {};
});
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::number(Number(1));
} else {
return Value::number(Number(args.front().blk.body.arguments.size()));
}
});
operators["+"] = binary_operator<std::plus<>>();
operators["-"] = binary_operator<std::minus<>>();
operators["*"] = binary_operator<std::multiplies<>>();
@ -107,6 +117,13 @@ Interpreter::Interpreter(std::ostream& out)
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)
assert(args.front().type == Value::Type::Block, "Only blocks can be indexed"); // TODO(assert)
assert(args.back().type == Value::Type::Number, "Only numbers can be used for indexing"); // TODO(assert)
return std::move(args.front()).blk.index(i, std::move(args.back()).n.as_int());
};
}
Result<Value> Interpreter::eval(Ast &&ast)

View File

@ -7,6 +7,7 @@ constexpr std::string_view Valid_Operator_Chars =
"+-*/:%" // arithmetic
"|&^" // logic & bit operations
"<>=!" // comparisons
"." // indexing
;
constexpr auto Keywords = std::array {
@ -84,14 +85,6 @@ auto Lexer::next_token() -> Result<Token>
return { Token::Type::Parameter_Separator, finish(), token_location };
}
// Number literals like .75
if (peek() == '.') {
consume();
while (consume_if(unicode::is_digit)) {}
if (token_length != 1)
return { Token::Type::Numeric, finish(), token_location };
}
if (consume_if(unicode::is_digit)) {
while (consume_if(unicode::is_digit)) {}
if (peek() == '.') {

View File

@ -444,6 +444,7 @@ struct Block
std::shared_ptr<Env> context;
Result<Value> operator()(Interpreter &i, std::vector<Value> params);
Result<Value> index(Interpreter &i, unsigned position);
};
template<typename T, typename ...XS>
@ -530,8 +531,13 @@ private:
struct Interpreter
{
/// Output of IO builtins like `say`
std::ostream &out;
/// Operators defined for language
std::unordered_map<std::string, Intrinsic> operators;
/// Current environment (current scope)
std::shared_ptr<Env> env;
Interpreter();

View File

@ -114,7 +114,6 @@ suite lexer_test = [] {
"Numeric tokens"_test = [] {
expect_token_type_and_value(Token::Type::Numeric, "0");
expect_token_type_and_value(Token::Type::Numeric, "123456789");
expect_token_type_and_value(Token::Type::Numeric, ".75");
expect_token_type_and_value(Token::Type::Numeric, "0.75");
expect_token_type_and_value(Token::Type::Numeric, "123456789.123456789");
expect_token_type_and_value(Token::Type::Numeric, "123.", "123");

View File

@ -152,3 +152,16 @@ Result<Value> Block::operator()(Interpreter &i, std::vector<Value> arguments)
i.env = old_scope;
return result;
}
// TODO Add memoization
Result<Value> Block::index(Interpreter &i, unsigned position)
{
assert(parameters.size() == 0, "cannot index into block with parameters (for now)");
if (body.type != Ast::Type::Sequence) {
assert(position == 0, "Out of range"); // TODO(assert)
return i.eval((Ast)body);
}
assert(position < body.arguments.size(), "Out of range"); // TODO(assert)
return i.eval((Ast)body.arguments[position]);
}