~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
3 2

[PATCH v2] Implement the variable sub-list operator

Details
Message ID
<20231029153803.37064-1-max@mxsr.de>
DKIM signature
missing
Download raw message
Patch: +94 -4
---
Make the upper value of a range inclusive.

 ast/value.ha    | 14 ++++++++++++++
 interp/value.ha | 32 +++++++++++++++++++++++++++++++-
 parse/value.ha  | 28 ++++++++++++++++++++++++++--
 test/access.rc  | 24 +++++++++++++++++++++++-
 4 files changed, 94 insertions(+), 4 deletions(-)

diff --git a/ast/value.ha b/ast/value.ha
index 4f4ddc2..4c2f89f 100644
--- a/ast/value.ha
+++ b/ast/value.ha
@@ -24,6 +24,7 @@ export type access = struct {
	atype: access_type,
	target: str,
	index: nullable *value,
	end: nullable *value,
};

// A subscript value, e.g. `{echo hi}.
@@ -46,6 +47,13 @@ export fn value_finish(val: *value) void = {
			value_finish(val);
			free(val);
		};
		match (val.end) {
		case null =>
			yield;
		case let val: *value =>
			value_finish(val);
			free(val);
		};
	case let val: string =>
		free(val);
	case let val: argument =>
@@ -81,6 +89,12 @@ export fn value_dup(val: *value) value = {
			case let v: *value =>
				yield alloc(value_dup(v));
			},
			end = match (val.end) {
			case null =>
				yield null;
			case let v: *value =>
				yield alloc(value_dup(v));
			},
		};
	case let val: string =>
		return strings::dup(val): string;
diff --git a/interp/value.ha b/interp/value.ha
index 1ac8653..bec0e7d 100644
--- a/interp/value.ha
+++ b/interp/value.ha
@@ -81,7 +81,37 @@ export fn expand(state: *state, val: *ast::value, glob: bool) (value | error) =
				return value_dup(&x[ix]);
			};
		case access_type::SLICE =>
			abort(); // TODO
			const ix = expand(state, val.index as *ast::value, true)?;
			defer value_finish(&ix);
			const ix = value_int(&ix)?;
			if (ix <= 0) {
				return bounds;
			};
			const ix = ix: size - 1;

			const end = expand(state, val.end as *ast::value, true)?;
			defer value_finish(&end);
			let end = value_int(&end)?;
			if (end <= -1) {
				return bounds;
			};
			let end = end: size;

			match (var.value) {
			case let x: str =>
				if (ix >= len(x)) {
					return bounds;
				};
				const end = if (end == 0) strings::end else end;
				const sub = strings::sub(x, ix, end);
				return strings::dup(sub);
			case let x: []value =>
				if (ix >= len(x)) {
					return bounds;
				};
				let v: value = if (end == 0) x[ix..] else x[ix..end];
				return value_dup(&v);
			};
		};
	case let val: []*ast::value =>
		let list: []value = alloc([], len(val));
diff --git a/parse/value.ha b/parse/value.ha
index bff0372..fb3eeed 100644
--- a/parse/value.ha
+++ b/parse/value.ha
@@ -133,12 +133,36 @@ fn parse_access(p: *parser) (ast::access | error) = {
		atype = atype,
		target = strings::dup(var.1),
		index = null,
		end = null,
	};

	if (atype == access_type::VAR && try(p, ltok::LPAREN)? is lex::token) {
		access.atype = access_type::INDEX;
		const (ix, _) = parse_value(p)?;
		access.index = alloc(ix);
		let arg: str = match (ix) {
		case let arg: ast::argument =>
			yield arg;
		case =>
			yield "";  // ix is not a range
		};
		if (strings::contains(arg, '-')) {
			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 {
			access.atype = access_type::INDEX;
			access.index = alloc(ix);
		};
		want(p, ltok::RPAREN)?;
	};

diff --git a/test/access.rc b/test/access.rc
index 5b24cea..1b91e15 100644
--- a/test/access.rc
+++ b/test/access.rc
@@ -37,6 +37,28 @@ begin "Quoted access"
}
end

# TODO: Test slices
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"'

	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"'

	# y=$x(-4)
	# test $y "=" "ABCD" || fail 'expected $x(-4) to equal "ABCD"'
}
end

finish
-- 
2.42.0
Details
Message ID
<CWLM5XXQ3XK0.2EWL8QDHC22W1@taiga>
In-Reply-To
<20231029153803.37064-1-max@mxsr.de> (view parent)
DKIM signature
missing
Download raw message
Thanks!

To git@git.sr.ht:~sircmpwn/rc
   35ccdc1..2c55050  master -> master
Details
Message ID
<CWLOFU0H9KEB.6BL7LIIGI73A@taiga>
In-Reply-To
<20231029153803.37064-1-max@mxsr.de> (view parent)
DKIM signature
missing
Download raw message
Another issue that came up after the fact:

% x=(foo bar baz) 
% y=2 
% echo $x($y-) 
Error: Value is not a number
Details
Message ID
<CWLXK63A0WLN.2KJF4M9EVI2GH@mxsr.de>
In-Reply-To
<CWLOFU0H9KEB.6BL7LIIGI73A@taiga> (view parent)
DKIM signature
missing
Download raw message
On Mon Oct 30, 2023 at 10:47 AM CET, Drew DeVault wrote:
> Another issue that came up after the fact:
>
> % x=(foo bar baz) 
> % y=2 
> % echo $x($y-) 
> Error: Value is not a number

Oops! It looks like my new tests were too simple. I'll fix this.
Reply to thread Export thread (mbox)