From 96c96ef2b0442b9454ab252f6725c1534249aa0d Mon Sep 17 00:00:00 2001 From: Robert Bendun Date: Sun, 11 Sep 2022 20:10:44 +0200 Subject: [PATCH] `fold` buultin. Operators can be quoted By prepending ' to operator you can use it as function --- src/builtin_functions.cc | 38 ++++++++++++++++++++++++++++++++++++++ src/interpreter.cc | 6 +++++- src/lexer.cc | 12 +++++++++++- 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/builtin_functions.cc b/src/builtin_functions.cc index d0c87fd..e6d00ca 100644 --- a/src/builtin_functions.cc +++ b/src/builtin_functions.cc @@ -402,6 +402,43 @@ static Result builtin_for(Interpreter &i, std::vector args) return result; } +/// Fold container +static Result builtin_fold(Interpreter &interpreter, std::vector 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 static Result builtin_if(Interpreter &i, std::vector args) { constexpr auto guard = Guard<2> { @@ -790,6 +827,7 @@ void Interpreter::register_builtin_functions() global.force_define("down", builtin_range); global.force_define("flat", builtin_flat); global.force_define("floor", apply_numeric_transform<&Number::floor>); + global.force_define("fold", builtin_fold); global.force_define("for", builtin_for); global.force_define("hash", builtin_hash); global.force_define("if", builtin_if); diff --git a/src/interpreter.cc b/src/interpreter.cc index 3c0abb4..d42d25b 100644 --- a/src/interpreter.cc +++ b/src/interpreter.cc @@ -55,7 +55,11 @@ Result Interpreter::eval(Ast &&ast) case Token::Type::Symbol: { if (ast.token.source.starts_with('\'')) { - return Value::from(std::move(ast.token.source).substr(1)); + 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)); + } } auto name = std::string(ast.token.source); diff --git a/src/lexer.cc b/src/lexer.cc index 710e845..80113d9 100644 --- a/src/lexer.cc +++ b/src/lexer.cc @@ -135,8 +135,18 @@ auto Lexer::next_token() -> Result> return Token { Token::Type::Chord, finish(), token_location }; } - // Lex symbol 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))) { symbol_lexing: for (auto predicate = std::bind(unicode::is_identifier, _1, unicode::First_Character::No);