Block indexing and len builtin
This commit is contained in:
parent
23b9d901ac
commit
f28cb10669
11
examples/arrays.mq
Normal file
11
examples/arrays.mq
Normal 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;
|
@ -95,6 +95,16 @@ Interpreter::Interpreter(std::ostream& out)
|
|||||||
return {};
|
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::plus<>>();
|
||||||
operators["-"] = binary_operator<std::minus<>>();
|
operators["-"] = binary_operator<std::minus<>>();
|
||||||
operators["*"] = binary_operator<std::multiplies<>>();
|
operators["*"] = binary_operator<std::multiplies<>>();
|
||||||
@ -107,6 +117,13 @@ Interpreter::Interpreter(std::ostream& out)
|
|||||||
|
|
||||||
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> {
|
||||||
|
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)
|
Result<Value> Interpreter::eval(Ast &&ast)
|
||||||
|
13
src/lexer.cc
13
src/lexer.cc
@ -5,8 +5,9 @@
|
|||||||
constexpr std::string_view Notes_Symbols = "abcedefgh";
|
constexpr std::string_view Notes_Symbols = "abcedefgh";
|
||||||
constexpr std::string_view Valid_Operator_Chars =
|
constexpr std::string_view Valid_Operator_Chars =
|
||||||
"+-*/:%" // arithmetic
|
"+-*/:%" // arithmetic
|
||||||
"|&^" // logic & bit operations
|
"|&^" // logic & bit operations
|
||||||
"<>=!" // comparisons
|
"<>=!" // comparisons
|
||||||
|
"." // indexing
|
||||||
;
|
;
|
||||||
|
|
||||||
constexpr auto Keywords = std::array {
|
constexpr auto Keywords = std::array {
|
||||||
@ -84,14 +85,6 @@ auto Lexer::next_token() -> Result<Token>
|
|||||||
return { Token::Type::Parameter_Separator, finish(), token_location };
|
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)) {
|
if (consume_if(unicode::is_digit)) {
|
||||||
while (consume_if(unicode::is_digit)) {}
|
while (consume_if(unicode::is_digit)) {}
|
||||||
if (peek() == '.') {
|
if (peek() == '.') {
|
||||||
|
@ -444,6 +444,7 @@ struct Block
|
|||||||
std::shared_ptr<Env> context;
|
std::shared_ptr<Env> context;
|
||||||
|
|
||||||
Result<Value> operator()(Interpreter &i, std::vector<Value> params);
|
Result<Value> operator()(Interpreter &i, std::vector<Value> params);
|
||||||
|
Result<Value> index(Interpreter &i, unsigned position);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename ...XS>
|
template<typename T, typename ...XS>
|
||||||
@ -530,8 +531,13 @@ private:
|
|||||||
|
|
||||||
struct Interpreter
|
struct Interpreter
|
||||||
{
|
{
|
||||||
|
/// Output of IO builtins like `say`
|
||||||
std::ostream &out;
|
std::ostream &out;
|
||||||
|
|
||||||
|
/// Operators defined for language
|
||||||
std::unordered_map<std::string, Intrinsic> operators;
|
std::unordered_map<std::string, Intrinsic> operators;
|
||||||
|
|
||||||
|
/// Current environment (current scope)
|
||||||
std::shared_ptr<Env> env;
|
std::shared_ptr<Env> env;
|
||||||
|
|
||||||
Interpreter();
|
Interpreter();
|
||||||
|
@ -114,7 +114,6 @@ suite lexer_test = [] {
|
|||||||
"Numeric tokens"_test = [] {
|
"Numeric tokens"_test = [] {
|
||||||
expect_token_type_and_value(Token::Type::Numeric, "0");
|
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, "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, "0.75");
|
||||||
expect_token_type_and_value(Token::Type::Numeric, "123456789.123456789");
|
expect_token_type_and_value(Token::Type::Numeric, "123456789.123456789");
|
||||||
expect_token_type_and_value(Token::Type::Numeric, "123.", "123");
|
expect_token_type_and_value(Token::Type::Numeric, "123.", "123");
|
||||||
|
13
src/value.cc
13
src/value.cc
@ -152,3 +152,16 @@ Result<Value> Block::operator()(Interpreter &i, std::vector<Value> arguments)
|
|||||||
i.env = old_scope;
|
i.env = old_scope;
|
||||||
return result;
|
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]);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user