- 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