~sircmpwn/rc-devel

Implement variable sub-list access using other variables v1 PROPOSED

Max Schillinger: 1
 Implement variable sub-list access using other variables

 2 files changed, 80 insertions(+), 24 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~sircmpwn/rc-devel/patches/46314/mbox | git am -3
Learn more about email & git

[PATCH] Implement variable sub-list access using other variables Export this patch

Example:

% x=(foo bar baz)
% y=2
% z=3
% echo $x($y-)
% echo $x($y-$z)
% echo $x(2-$z)
---
 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..e4d4fbd 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