Max Schillinger: 1 parse: Accept whitespace in variable sub-list access 2 files changed, 86 insertions(+), 58 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/46887/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) Add more tests. --- Don't insert carets in parse_value for access lists. This allows a simpler/shorter parse_access_range function. parse/value.ha | 103 +++++++++++++++++++++++++++---------------------- test/access.rc | 41 ++++++++++++++------ 2 files changed, 86 insertions(+), 58 deletions(-) diff --git a/parse/value.ha b/parse/value.ha index a9746bf..eaca0bc 100644 --- a/parse/value.ha +++ b/parse/value.ha @@ -46,7 +46,7 @@ export fn parse_value_list(p: *parser, lf: bool) ([]*ast::value | error) = { }; // Parses an [[ast::value]], returning true if there was trailing whitespace. -export fn parse_value(p: *parser) ((ast::value, bool) | error) = { +export fn parse_value(p: *parser, access: bool...) ((ast::value, bool) | error) = { const tok = want(p, ltok::DOLLAR, ltok::DOLLAR_POUND, @@ -85,7 +85,8 @@ export fn parse_value(p: *parser) ((ast::value, bool) | error) = { }; let had_ws = ws(p, false)?; - if (!had_ws && peek(p, + let is_access = len(access) > 0 && access[0] == true; + if (!had_ws && !is_access && peek(p, ltok::DOLLAR, ltok::DOLLAR_POUND, ltok::DOLLAR_QUOTE, @@ -146,17 +147,26 @@ 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)?; + access.atype = access_type::INDEX; + let had_dash = false; + + ws(p, false)?; + + const (ix, _) = parse_value(p, true)?; match (ix) { case ast::access => - // p.e. $var($index) - access.atype = access_type::INDEX; + // p.e. $var($index) or $var($start-$end) or $var($start - $end) access.index = alloc(ix); case let arg: ast::argument => - if (strings::contains(arg, '-')) { + // p.e. $var(2-4) or $var(-$end), everything starting with a number + // or a dash + if (arg == "-") { + // p.e. $var(- 4) or $var(- $end) + access.index = alloc("1": ast::string: ast::value); + access.end = alloc("0": ast::string: ast::value); + had_dash = true; + } else 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 == "") { @@ -169,56 +179,55 @@ fn parse_access_range(p: *parser, access: *ast::access) (void | error) = { end = "0"; // "open end" }; access.end = alloc(strings::dup(end): ast::string: ast::value); + access.atype = access_type::SLICE; + had_dash = true; } else { - // p.e. $var(2) - access.atype = access_type::INDEX; + // p.e. $var(2) or $var(2 - 4) 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(); - }; - let tokens = strings::tokenize(arg0, "-"); - let start = strings::next_token(&tokens) as str; - if (start == "") { - start = "1"; // start with first value + // error for all other types? + }; + + if (peek(p, ltok::RPAREN) is lex::token) { + return; + }; + + access.atype = access_type::SLICE; + + // check for "-" and end index + if (!had_dash) { + const tok = try(p, ltok::ARGUMENT)?; + if (tok is lex::token) { + const arg = (tok as lex::token).1; + if (arg != "-") { + if (strings::sub(arg, 0, 1) != "-") { + abort(); + }; + const rest = strings::sub(arg, 1, strings::end); + access.end = alloc(strings::dup(rest): 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); + ws(p, false)?; + + if (peek(p, ltok::RPAREN)? is lex::token) { + if (access.end == null) { + access.end = alloc("0": ast::string: ast::value); + }; + } else { + const (end, _) = parse_value(p, true)?; + match (end) { + case let acc: ast::access => + access.end = alloc(end); + case let end: ast::argument => 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? - }; + case => + abort(); // error? }; - // error for all other types? }; }; diff --git a/test/access.rc b/test/access.rc index 4c1bd96..a3bf407 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,46 @@ 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(2 - ) "=" "BCDE" || fail 'expected $x(2 - ) to equal "BCDE"' + test $x(- 4) "=" "ABCD" || fail 'expected $x(- 4) to equal "ABCD"' + 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.1
Thanks! To git@git.sr.ht:~sircmpwn/rc c8f393b..f408a95 master -> master