fold buultin. Operators can be quoted

By prepending ' to operator you can use it as function
This commit is contained in:
Robert Bendun 2022-09-11 20:10:44 +02:00
parent 9b846d8115
commit 96c96ef2b0
3 changed files with 54 additions and 2 deletions

View File

@ -402,6 +402,43 @@ static Result<Value> builtin_for(Interpreter &i, std::vector<Value> args)
return result; return result;
} }
/// Fold container
static Result<Value> builtin_fold(Interpreter &interpreter, std::vector<Value> args) {
constexpr auto guard = Guard<2> {
.name = "fold",
.possibilities = {
"(array, callback) -> any",
"(array, init, callback) -> any"
}
};
Value array, init, callback;
switch (args.size()) {
break; case 2:
array = std::move(args[0]);
callback = std::move(args[1]);
if (array.size() != 0) {
init = Try(array.index(interpreter, 0));
}
break; case 3:
array = std::move(args[0]);
init = std::move(args[1]);
callback = std::move(args[2]);
break; default:
return guard.yield_error();
}
Try(guard(is_indexable, array));
Try(guard(is_callable, callback));
for (auto i = 0u; i < array.size(); ++i) {
auto element = Try(array.index(interpreter, i));
init = Try(callback(interpreter, { std::move(init), std::move(element) }));
}
return init;
}
/// Execute blocks depending on condition /// Execute blocks depending on condition
static Result<Value> builtin_if(Interpreter &i, std::vector<Value> args) { static Result<Value> builtin_if(Interpreter &i, std::vector<Value> args) {
constexpr auto guard = Guard<2> { constexpr auto guard = Guard<2> {
@ -790,6 +827,7 @@ void Interpreter::register_builtin_functions()
global.force_define("down", builtin_range<Range_Direction::Down>); global.force_define("down", builtin_range<Range_Direction::Down>);
global.force_define("flat", builtin_flat); global.force_define("flat", builtin_flat);
global.force_define("floor", apply_numeric_transform<&Number::floor>); global.force_define("floor", apply_numeric_transform<&Number::floor>);
global.force_define("fold", builtin_fold);
global.force_define("for", builtin_for); global.force_define("for", builtin_for);
global.force_define("hash", builtin_hash); global.force_define("hash", builtin_hash);
global.force_define("if", builtin_if); global.force_define("if", builtin_if);

View File

@ -55,8 +55,12 @@ Result<Value> Interpreter::eval(Ast &&ast)
case Token::Type::Symbol: case Token::Type::Symbol:
{ {
if (ast.token.source.starts_with('\'')) { if (ast.token.source.starts_with('\'')) {
if (auto op = operators.find(std::string(ast.token.source.substr(1))); op != operators.end()) {
return Value(op->second);
} else {
return Value::from(std::move(ast.token.source).substr(1)); return Value::from(std::move(ast.token.source).substr(1));
} }
}
auto name = std::string(ast.token.source); auto name = std::string(ast.token.source);

View File

@ -135,8 +135,18 @@ auto Lexer::next_token() -> Result<std::variant<Token, End_Of_File>>
return Token { Token::Type::Chord, finish(), token_location }; return Token { Token::Type::Chord, finish(), token_location };
} }
// Lex symbol
using namespace std::placeholders; using namespace std::placeholders;
// Lex quoted symbol
if (consume_if('\'')) {
for (auto predicate = std::bind(unicode::is_identifier, _1, unicode::First_Character::No);
consume_if(predicate) || consume_if(Valid_Operator_Chars);) {}
Token t = { Token::Type::Symbol, finish(), token_location };
return t;
}
// Lex symbol
if (consume_if(std::bind(unicode::is_identifier, _1, unicode::First_Character::Yes))) { if (consume_if(std::bind(unicode::is_identifier, _1, unicode::First_Character::Yes))) {
symbol_lexing: symbol_lexing:
for (auto predicate = std::bind(unicode::is_identifier, _1, unicode::First_Character::No); for (auto predicate = std::bind(unicode::is_identifier, _1, unicode::First_Character::No);