summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Bridle <ben@derelict.engineering>2025-10-15 14:12:37 +1300
committerBen Bridle <ben@derelict.engineering>2025-10-15 14:12:37 +1300
commit80ad3f392706c4f6bddd37d317b2519bd0d6f579 (patch)
tree9b67f07dbbbd82506ab82d4e8f54ffc4965fd23f
parent29d0b855f5a089e9ac26f56410ae62b8775a2dfe (diff)
downloadtorque-asm-80ad3f392706c4f6bddd37d317b2519bd0d6f579.zip
Add find operator for expressions
The <fnd> operator returns the index of the first element in a list with the given value.
-rw-r--r--src/types/expression_stack.rs19
-rw-r--r--src/types/operator.rs3
2 files changed, 22 insertions, 0 deletions
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<IntermediateVa
false => Err(ExpressionError::IndexError(l.len(), r)),
}
}
+fn op_find(l: IntermediateValue, r: IntermediateValue) -> Result<IntermediateValue, ExpressionError> {
+ 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<IntermediateValue, ExpressionError> {
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<ExpressionError>, 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 {
"<not>" => Some(Operator::BitNot),
"<len>" => Some(Operator::Length),
"<nth>" => Some(Operator::Index),
+ "<fnd>" => Some(Operator::Find),
"<sum>" => Some(Operator::Sum),
"<abs>" => Some(Operator::Absolute),
"<dbg>" => Some(Operator::Debug),
@@ -93,6 +95,7 @@ impl std::fmt::Display for Operator {
Operator::BitNot => "<not>",
Operator::Length => "<len>",
Operator::Index => "<nth>",
+ Operator::Find => "<fnd>",
Operator::Sum => "<sum>",
Operator::Absolute => "<abs>",
Operator::Debug => "<dbg>",