Max Schillinger: 1 parse: Accept whitespace in variable sub-list access 2 files changed, 130 insertions(+), 75 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/46371/mbox | git am -3Learn more about email & git
- Accept expressions like these: $var( 3 ) $var(2 - 4) $var(2 -) $var( $i ) $var($start - $end) $var(- $end) - Extend "List index access" test. - Split "List slice access" test into two. --- https://todo.sr.ht/~sircmpwn/rc/31 parse/value.ha | 166 ++++++++++++++++++++++++++++++------------------- test/access.rc | 39 ++++++++---- 2 files changed, 130 insertions(+), 75 deletions(-) diff --git a/parse/value.ha b/parse/value.ha index a9746bf..dac88b6 100644 --- a/parse/value.ha +++ b/parse/value.ha @@ -146,79 +146,117 @@ fn parse_access(p: *parser) (ast::access | error) = { // 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, "-"); - 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); + ws(p, false)?; - let end = strings::remaining_tokens(&tokens); - if (end == "") { - end = "0"; // "open end" - }; - access.end = alloc(strings::dup(end): ast::string: ast::value); - } else { - // p.e. $var(2) + const tok = peek(p, ltok::ARGUMENT)?; + if (tok is lex::token && (tok as lex::token).1 == "-") { + // p.e. $var(- 4) or $var(- $end) + access.atype = access_type::SLICE; + access.index = alloc("1": ast::string: ast::value); + } else { + // p.e. $var(-4) $var(-$end) or every argument not starting with "-" + const (ix, had_ws) = parse_value(p)?; + match (ix) { + case ast::access => + // p.e. $var($index) or $var($start - $end) access.atype = access_type::INDEX; access.index = alloc(ix); - }; - 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(); + 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, "-"); + 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); + + let end = strings::remaining_tokens(&tokens); + if (end == "") { + end = "0"; // "open end" + }; + access.end = alloc(strings::dup(end): ast::string: ast::value); + } else { + // p.e. $var(2) or $var(2 - 4) + access.atype = access_type::INDEX; + access.index = alloc(ix); }; - let tokens = strings::tokenize(arg0, "-"); - let start = strings::next_token(&tokens) as str; - if (start == "") { - start = "1"; // start with first value + 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); }; - access.index = alloc(strings::dup(start): ast::string: ast::value); - }; - 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" + 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, '-')) { + abort(); // 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? + }; }; - 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? + }; + }; + + // check for "-" and end index + if (peek(p, ltok::RPAREN) is void) { + const tok = want(p, ltok::ARGUMENT)?; + if (tok.1 != "-") { + abort(); + }; + access.atype = access_type::SLICE; + + ws(p, false)?; + + if (peek(p, ltok::RPAREN)? is lex::token) { + access.end = alloc("0": ast::string: ast::value); + } else { + const (end, _) = parse_value(p)?; + match (end) { + case let end: ast::argument => + if (end == "") { + end = "0"; // "open end" + }; + access.end = alloc(strings::dup(end): ast::string: ast::value); + case ast::access => + access.end = alloc(end); + case => + abort(); // error? }; }; - // error for all other types? }; }; diff --git a/test/access.rc b/test/access.rc index 4c1bd96..39d3460 100644 --- a/test/access.rc +++ b/test/access.rc @@ -17,6 +17,9 @@ begin "List index access" test $i -eq $x($i) || fail 'unexpected value' i=`{dc -e "$i 1+p"} } + + i=3 + test $i -eq $x( $i ) || fail 'unexpected value' } end @@ -37,30 +40,44 @@ begin "Quoted access" } end -begin "List slice access" +begin "String 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"' - - 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"' - x="ABCDE" 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"' + 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"' 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 - $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"' + + 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 + +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"' + + 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"' } end -- 2.42.0