From 80ad3f392706c4f6bddd37d317b2519bd0d6f579 Mon Sep 17 00:00:00 2001 From: Ben Bridle Date: Wed, 15 Oct 2025 14:12:37 +1300 Subject: Add find operator for expressions The operator returns the index of the first element in a list with the given value. --- src/types/expression_stack.rs | 19 +++++++++++++++++++ src/types/operator.rs | 3 +++ 2 files changed, 22 insertions(+) (limited to 'src') diff --git a/src/types/expression_stack.rs b/src/types/expression_stack.rs index f197ea7..e60dad7 100644 --- a/src/types/expression_stack.rs +++ b/src/types/expression_stack.rs @@ -69,6 +69,7 @@ impl ExpressionStack { Operator::BitNot => { pop!(a); push!(op_bit_not(a)) }, Operator::Length => { pop!(a); push!(op_length(a)) }, Operator::Index => { pop!(b); pop!(a); push!(op_index(a, b)) }, + Operator::Find => { pop!(b); pop!(a); push!(op_find(a, b)) }, Operator::Sum => { pop!(a); push!(op_sum(a)) }, Operator::Absolute => { pop!(a); push!(op_absolute(a)) }, Operator::Debug => { pop!(a); op_debug(&a, &source); push!(Ok(a)) }, @@ -192,6 +193,13 @@ fn op_index(l: IntermediateValue, r: IntermediateValue) -> Result Err(ExpressionError::IndexError(l.len(), r)), } } +fn op_find(l: IntermediateValue, r: IntermediateValue) -> Result { + let l = to_list(l)?; let r = to_isize(r)?; + match l.iter().position(|e| *e == r) { + Some(i) => Ok(from_isize(i as isize)), + None => Err(ExpressionError::FindError(l.len(), r)), + } +} fn op_sum(l: IntermediateValue) -> Result { let sum = match l { IntermediateValue::Integer(integer) => ones(*integer) as isize, @@ -243,6 +251,8 @@ pub enum ExpressionError { InvalidArgumentType(&'static str, &'static str), // (length, index) IndexError(usize, isize), + // (length, value) + FindError(usize, isize), } @@ -261,6 +271,15 @@ pub fn report_expression_error(error: &Tracked, source_code: &s &format!("Operator expected {expected} value, not {received} value"), ExpressionError::IndexError(length, index) => &format!("Could not access element {index} from a list of length {length}"), + ExpressionError::FindError(length, value) => { + let mut character = String::new(); + if let Ok(value) = u32::try_from(*value) { + if let Some(c) = char::from_u32(value) { + character = format!(" (character '{c}')"); + } + } + &format!("Could not find value {value}{character} in list of length {length}") + } }; report_source_issue(LogLevel::Error, &context, message); diff --git a/src/types/operator.rs b/src/types/operator.rs index 5bf82b2..e94c67d 100644 --- a/src/types/operator.rs +++ b/src/types/operator.rs @@ -20,6 +20,7 @@ pub enum Operator { BitNot, Length, Index, + Find, Sum, Absolute, Debug, @@ -62,6 +63,7 @@ impl Operator { "" => Some(Operator::BitNot), "" => Some(Operator::Length), "" => Some(Operator::Index), + "" => Some(Operator::Find), "" => Some(Operator::Sum), "" => Some(Operator::Absolute), "" => Some(Operator::Debug), @@ -93,6 +95,7 @@ impl std::fmt::Display for Operator { Operator::BitNot => "", Operator::Length => "", Operator::Index => "", + Operator::Find => "", Operator::Sum => "", Operator::Absolute => "", Operator::Debug => "", -- cgit v1.2.3-70-g09d2