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

Shell: Add support for indexing into variables

Now a variable may have an optional slice (only _one_ slice), which can
also use negative indices to index from the end.
This works on both lists and strings.
The contents of the slice have the same semantics as brace expansions.
For example:
```sh
$ x=(1 2 3 4 5 6)
$ echo $x[1..3] # select indices 1, 2, 3
2 3 4
$ echo $x[3,4,1,0] # select indices 3, 4, 1, 0 (in that order)
4 5 2 1
$ x="Well Hello Friends!"
$ echo $x[5..9]
Hello
```
This commit is contained in:
AnotherTest 2021-03-13 03:10:18 +03:30 committed by Andreas Kling
parent ddcef0452a
commit 3b8fa5a753
11 changed files with 391 additions and 56 deletions

View file

@ -1329,6 +1329,21 @@ RefPtr<AST::Node> Parser::parse_doublequoted_string_inner()
}
RefPtr<AST::Node> Parser::parse_variable()
{
auto rule_start = push_start();
auto ref = parse_variable_ref();
if (!ref)
return nullptr;
auto variable = static_ptr_cast<AST::VariableNode>(ref);
if (auto slice = parse_slice())
variable->set_slice(slice.release_nonnull());
return variable;
}
RefPtr<AST::Node> Parser::parse_variable_ref()
{
auto rule_start = push_start();
if (at_end())
@ -1358,6 +1373,38 @@ RefPtr<AST::Node> Parser::parse_variable()
return create<AST::SimpleVariable>(move(name)); // Variable Simple
}
RefPtr<AST::Node> Parser::parse_slice()
{
auto rule_start = push_start();
if (!next_is("["))
return nullptr;
consume(); // [
ScopedValueRollback chars_change { m_extra_chars_not_allowed_in_barewords };
m_extra_chars_not_allowed_in_barewords.append(']');
auto spec = parse_brace_expansion_spec();
RefPtr<AST::SyntaxError> error;
if (peek() != ']')
error = create<AST::SyntaxError>("Expected a close bracket ']' to end a variable slice");
else
consume();
if (!spec) {
if (error)
spec = move(error);
else
spec = create<AST::SyntaxError>("Expected either a range, or a comma-seprated list of selectors");
}
auto node = create<AST::Slice>(spec.release_nonnull());
if (error)
node->set_is_syntax_error(*error);
return node;
}
RefPtr<AST::Node> Parser::parse_evaluate()
{
auto rule_start = push_start();
@ -1787,7 +1834,9 @@ RefPtr<AST::Node> Parser::parse_brace_expansion()
RefPtr<AST::Node> Parser::parse_brace_expansion_spec()
{
TemporaryChange is_in_brace_expansion { m_is_in_brace_expansion_spec, true };
TemporaryChange chars_change { m_extra_chars_not_allowed_in_barewords, { ',' } };
ScopedValueRollback chars_change { m_extra_chars_not_allowed_in_barewords };
m_extra_chars_not_allowed_in_barewords.append(',');
auto rule_start = push_start();
auto start_expr = parse_expression();