1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 06:38:10 +00:00

Shell: Add the 'join' and 'filter_glob' immediate functions

'split' was missing its other half, and to avoid globbing the
filesystem, let's keep the globbing to shell-internal state.
This commit is contained in:
Ali Mohammad Pur 2022-02-23 09:16:31 +03:30 committed by Ali Mohammad Pur
parent 4a331c73f8
commit e6bd1f8807
2 changed files with 73 additions and 1 deletions

View file

@ -383,6 +383,76 @@ RefPtr<AST::Node> Shell::immediate_concat_lists(AST::ImmediateExpression& invoki
return AST::make_ref_counted<AST::ListConcatenate>(invoking_node.position(), move(result));
}
RefPtr<AST::Node> Shell::immediate_filter_glob(AST::ImmediateExpression& invoking_node, const NonnullRefPtrVector<AST::Node>& arguments)
{
// filter_glob string list
if (arguments.size() != 2) {
raise_error(ShellError::EvaluatedSyntaxError, "Expected exactly two arguments to filter_glob (<glob> <list>)", invoking_node.position());
return nullptr;
}
auto glob_list = const_cast<AST::Node&>(arguments[0]).run(*this)->resolve_as_list(*this);
if (glob_list.size() != 1) {
raise_error(ShellError::EvaluatedSyntaxError, "Expected the <glob> argument to filter_glob to be a single string", arguments[0].position());
return nullptr;
}
auto& glob = glob_list.first();
auto& list_node = arguments[1];
NonnullRefPtrVector<AST::Node> result;
const_cast<AST::Node&>(list_node).for_each_entry(*this, [&](NonnullRefPtr<AST::Value> entry) {
auto value = entry->resolve_as_list(*this);
if (value.size() == 0)
return IterationDecision::Continue;
if (value.size() == 1) {
if (!value.first().matches(glob))
return IterationDecision::Continue;
result.append(AST::make_ref_counted<AST::StringLiteral>(arguments[1].position(), value.first()));
return IterationDecision::Continue;
}
for (auto& entry : value) {
if (entry.matches(glob)) {
NonnullRefPtrVector<AST::Node> nodes;
for (auto& string : value)
nodes.append(AST::make_ref_counted<AST::StringLiteral>(arguments[1].position(), string));
result.append(AST::make_ref_counted<AST::ListConcatenate>(arguments[1].position(), move(nodes)));
return IterationDecision::Continue;
}
}
return IterationDecision::Continue;
});
return AST::make_ref_counted<AST::ListConcatenate>(invoking_node.position(), move(result));
}
RefPtr<AST::Node> Shell::immediate_join(AST::ImmediateExpression& invoking_node, const NonnullRefPtrVector<AST::Node>& arguments)
{
if (arguments.size() != 2) {
raise_error(ShellError::EvaluatedSyntaxError, "Expected exactly 2 arguments to join", invoking_node.position());
return nullptr;
}
auto delimiter = const_cast<AST::Node&>(arguments[0]).run(this);
if (!delimiter->is_string()) {
raise_error(ShellError::EvaluatedSyntaxError, "Expected the join delimiter string to be a string", arguments[0].position());
return nullptr;
}
auto value = const_cast<AST::Node&>(arguments[1]).run(this)->resolve_without_cast(this);
if (!value->is_list()) {
raise_error(ShellError::EvaluatedSyntaxError, "Expected the joined list to be a list", arguments[1].position());
return nullptr;
}
auto delimiter_str = delimiter->resolve_as_list(this)[0];
StringBuilder builder;
builder.join(delimiter_str, value->resolve_as_list(*this));
return AST::make_ref_counted<AST::StringLiteral>(invoking_node.position(), builder.to_string());
}
RefPtr<AST::Node> Shell::run_immediate_function(StringView str, AST::ImmediateExpression& invoking_node, const NonnullRefPtrVector<AST::Node>& arguments)
{
#define __ENUMERATE_SHELL_IMMEDIATE_FUNCTION(name) \