~sircmpwn/rc-devel

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch

[PATCH] parse: Accept whitespace in variable sub-list access

Details
Message ID
<20231103120048.39830-2-max@mxsr.de>
DKIM signature
missing
Download raw message
Patch: +130 -75
- 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
Reply to thread Export thread (mbox)