Max Schillinger: 1 Implement variable sub-list access using other variables 2 files changed, 80 insertions(+), 24 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~sircmpwn/rc-devel/patches/46326/mbox | git am -3Learn more about email & git
Example: % x=(foo bar baz) % y=2 % z=3 % echo $x($y-) % echo $x($y-$z) % echo $x(2-$z) --- v1 didn't compile. Comment out empty block. parse/value.ha | 73 +++++++++++++++++++++++++++++++++++++++++++------- test/access.rc | 31 +++++++++++---------- 2 files changed, 80 insertions(+), 24 deletions(-) diff --git a/parse/value.ha b/parse/value.ha index fb3eeed..a9746bf 100644 --- a/parse/value.ha +++ b/parse/value.ha @@ -137,14 +137,24 @@ fn parse_access(p: *parser) (ast::access | error) = { }; if (atype == access_type::VAR && try(p, ltok::LPAREN)? is lex::token) { - const (ix, _) = parse_value(p)?; - let arg: str = match (ix) { - case let arg: ast::argument => - yield arg; - case => - yield ""; // ix is not a range - }; + parse_access_range(p, &access)?; + want(p, ltok::RPAREN)?; + }; + + return access; +}; + +// Parses an [[ast::access]] index or slice. +fn parse_access_range(p: *parser, access: *ast::access) (void | error) = { + const (ix, _) = parse_value(p)?; + match (ix) { + case ast::access => + // p.e. $var($index) + access.atype = access_type::INDEX; + access.index = alloc(ix); + case let arg: ast::argument => if (strings::contains(arg, '-')) { + // p.e. $var(2-4) or $var(2-) or $var(-4) access.atype = access_type::SLICE; let tokens = strings::tokenize(arg, "-"); @@ -160,13 +170,56 @@ fn parse_access(p: *parser) (ast::access | error) = { }; access.end = alloc(strings::dup(end): ast::string: ast::value); } else { + // p.e. $var(2) access.atype = access_type::INDEX; access.index = alloc(ix); }; - want(p, ltok::RPAREN)?; - }; + case let arg: ast::concat => + access.atype = access_type::SLICE; + match (*arg.0) { + case let arg0: ast::access => + // p.e. $var($start-) or $var($start-$end) or $var($start-3) + access.index = alloc(ast::value_dup(arg.0)); + case let arg0: ast::argument => + // p.e. $var(-$end) or $var(2-$end) + if (!strings::contains(arg0, '-')) { + abort(); + }; + let tokens = strings::tokenize(arg0, "-"); + let start = strings::next_token(&tokens) as str; + if (start == "") { + start = "1"; // start with first value + }; + access.index = alloc(strings::dup(start): ast::string: ast::value); + }; - return access; + match (*arg.1) { + case let arg1: ast::access => + // p.e. $var(-$end) or $var(2-$end) + access.end = alloc(ast::value_dup(arg.1)); + case let arg1: ast::argument => + // p.e. $var($start-) or $var($start-3) + // if (!strings::contains(arg1, '-')) { + // // error? + // }; + let tokens = strings::tokenize(arg1, "-"); + strings::next_token(&tokens); + let end = strings::remaining_tokens(&tokens); + if (end == "") { + end = "0"; // "open end" + }; + access.end = alloc(strings::dup(end): ast::string: ast::value); + case let arg1: ast::concat => + // p.e. $var($start-$end) + // assuming *arg1.0 = "-", error if not? + match (*arg1.1) { + case let arg2: ast::access => + access.end = alloc(ast::value_dup(arg1.1)); + // error if other type? + }; + }; + // error for all other types? + }; }; // Parses an [[ast::subscript]] value. diff --git a/test/access.rc b/test/access.rc index 1b91e15..4c1bd96 100644 --- a/test/access.rc +++ b/test/access.rc @@ -39,25 +39,28 @@ end begin "List slice access" @{ - # x=(1 2 3 4 5) - # y=$x(2-4) - # test $"y "=" "2 3 4" || fail 'expected $"x(2-4) to equal "2 3 4"' + x=(1 2 3 4 5) + y=$x(2-4) + test $"y "=" "2 3 4" || fail 'expected $"x(2-4) to equal "2 3 4"' - # y=$x(2-) - # test $"y "=" "2 3 4 5" || fail 'expected $"x(2-) to equal "2 3 4 5"' + y=$x(2-) + test $"y "=" "2 3 4 5" || fail 'expected $"x(2-) to equal "2 3 4 5"' - # y=$x(-4) - # test $"y "=" "1 2 3 4" || fail 'expected $"x(-4) to equal "1 2 3 4"' + y=$x(-4) + test $"y "=" "1 2 3 4" || fail 'expected $"x(-4) to equal "1 2 3 4"' x="ABCDE" - y=$x(2-4) - test $y "=" "BCD" || fail 'expected $x(2-4) to equal "BCD"' - - # y=$x(2-) - # test $y "=" "BCDE" || fail 'expected $x(2-) to equal "BCDE"' + test $x(2-4) "=" "BCD" || fail 'expected $x(2-4) to equal "BCD"' + test $x(2-) "=" "BCDE" || fail 'expected $x(2-) to equal "BCDE"' + test $x(-4) "=" "ABCD" || fail 'expected $x(-4) to equal "ABCD"' - # y=$x(-4) - # test $y "=" "ABCD" || fail 'expected $x(-4) to equal "ABCD"' + start=2 + end=4 + test $x($start-$end) "=" "BCD" || fail 'expected $x($start-$end) to equal "BCD"' + test $x($start-) "=" "BCDE" || fail 'expected $x($start-) to equal "BCDE"' + test $x(-$end) "=" "ABCD" || fail 'expected $x(-$end) to equal "ABCD"' + test $x($start-4) "=" "BCD" || fail 'expected $x($start-) to equal "BCD"' + test $x(2-$end) "=" "BCD" || fail 'expected $x(-$end) to equal "BCD"' } end -- 2.42.0
Thanks! To git@git.sr.ht:~sircmpwn/rc 87b794f..62dab51 master -> master Can you also update doc/grammar.txt accordingly?