diff --git a/src/builtins.rs b/src/builtins.rs index 53280a2..3ceef04 100644 --- a/src/builtins.rs +++ b/src/builtins.rs @@ -228,7 +228,7 @@ fn abs<'a>(payload: &BuiltinFunctionPayload<'a>) -> Result, Error> { fn acos<'a>(payload: &BuiltinFunctionPayload<'a>) -> Result, Error> { let argument = payload.arguments[0].number(payload.span)?; - if argument < Number::from(-1_i64) || argument > Number::from(1_i64) { + if argument < &Number::from(-1_i64) || argument > &Number::from(1_i64) { return Err(Error::new( payload.span, "acos argument must be between -1 and 1", @@ -268,7 +268,7 @@ fn acsc<'a>(payload: &BuiltinFunctionPayload<'a>) -> Result, Error> { } let reciprocal = Number::from(1_i64) - .div(&argument, payload.config) + .div(argument, payload.config) .map_err(|error| Error::new(payload.span, error.to_string()))?; Ok(Value::Number(reciprocal.asin(payload.config))) @@ -277,7 +277,7 @@ fn acsc<'a>(payload: &BuiltinFunctionPayload<'a>) -> Result, Error> { fn append<'a>( payload: &BuiltinFunctionPayload<'a>, ) -> Result, Error> { - let mut list = payload.arguments[0].list(payload.span)?; + let mut list = payload.arguments[0].list(payload.span)?.to_vec(); list.push(payload.arguments[1].clone()); @@ -303,7 +303,7 @@ fn asec<'a>(payload: &BuiltinFunctionPayload<'a>) -> Result, Error> { } let reciprocal = Number::from(1_i64) - .div(&argument, payload.config) + .div(argument, payload.config) .map_err(|error| Error::new(payload.span, error.to_string()))?; Ok(Value::Number(reciprocal.acos(payload.config))) @@ -312,7 +312,7 @@ fn asec<'a>(payload: &BuiltinFunctionPayload<'a>) -> Result, Error> { fn asin<'a>(payload: &BuiltinFunctionPayload<'a>) -> Result, Error> { let argument = payload.arguments[0].number(payload.span)?; - if argument < Number::from(-1_i64) || argument > Number::from(1_i64) { + if argument < &Number::from(-1_i64) || argument > &Number::from(1_i64) { return Err(Error::new( payload.span, "asin argument must be between -1 and 1", @@ -827,7 +827,7 @@ fn sum<'a>(payload: &BuiltinFunctionPayload<'a>) -> Result, Error> { let mut sum = Number::from(0_i64); for value in list { - sum = sum.add(&value.number(payload.span)?, payload.config); + sum = sum.add(value.number(payload.span)?, payload.config); } Ok(Value::Number(sum)) diff --git a/src/completion.rs b/src/completion.rs index 8191b11..393dd3e 100644 --- a/src/completion.rs +++ b/src/completion.rs @@ -6,12 +6,3 @@ pub enum Completion<'a> { Return(Value<'a>), Value(Value<'a>), } - -impl<'a> Completion<'a> { - pub(crate) fn unwrap(&self) -> Value<'a> { - match self { - Completion::Return(value) | Completion::Value(value) => value.clone(), - Completion::Break | Completion::Continue => Value::Null, - } - } -} diff --git a/src/environment.rs b/src/environment.rs index c676aa2..c5ae02b 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -8,43 +8,62 @@ pub struct Environment<'src> { impl<'src> Environment<'src> { pub fn add_function(&self, name: &str, function: Function<'src>) { - self - .frame - .borrow_mut() - .symbols - .entry(name.to_owned()) - .or_default() - .function = Some(function); + let mut frame = self.frame.borrow_mut(); + + if let Some(symbol) = frame.symbols.get_mut(name) { + symbol.function = Some(function); + } else { + frame.symbols.insert( + name.to_owned(), + Symbol { + function: Some(function), + value: None, + }, + ); + } } pub fn add_symbol(&self, name: &str, value: Value<'src>) { - self - .frame - .borrow_mut() - .symbols - .entry(name.to_owned()) - .or_default() - .value = Some(value); + let mut frame = self.frame.borrow_mut(); + + if let Some(symbol) = frame.symbols.get_mut(name) { + symbol.value = Some(value); + } else { + frame.symbols.insert( + name.to_owned(), + Symbol { + function: None, + value: Some(value), + }, + ); + } } - fn assign_existing_symbol(&self, name: &str, value: Value<'src>) -> bool { + fn assign_existing_symbol( + &self, + name: &str, + value: Value<'src>, + ) -> std::result::Result<(), Value<'src>> { let parent = { let mut frame = self.frame.borrow_mut(); match frame.symbols.get_mut(name) { Some(symbol) if symbol.value.is_some() => { symbol.value = Some(value); - return true; + return Ok(()); } _ => frame.parent.clone(), } }; - parent.is_some_and(|parent| parent.assign_existing_symbol(name, value)) + match parent { + Some(parent) => parent.assign_existing_symbol(name, value), + None => Err(value), + } } pub(crate) fn assign_symbol(&self, name: &str, value: Value<'src>) { - if !self.assign_existing_symbol(name, value.clone()) { + if let Err(value) = self.assign_existing_symbol(name, value) { self.add_symbol(name, value); } } diff --git a/src/evaluator.rs b/src/evaluator.rs index 410c00b..23102c5 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -73,8 +73,9 @@ impl<'a> Evaluator<'a> { )); } - list[index] = - self.assign_indices(name, list[index].clone(), rest, assigned, span)?; + let value = std::mem::replace(&mut list[index], Value::Null); + + list[index] = self.assign_indices(name, value, rest, assigned, span)?; Ok(Value::List(list)) } @@ -110,7 +111,10 @@ impl<'a> Evaluator<'a> { match node { Program::Statements(statements) => { - Ok(self.evaluate_statements(statements)?.unwrap()) + match self.evaluate_statements(statements)? { + Completion::Return(value) | Completion::Value(value) => Ok(value), + Completion::Break | Completion::Continue => Ok(Value::Null), + } } } } @@ -128,32 +132,33 @@ impl<'a> Evaluator<'a> { self.evaluate_expression(rhs)?, ); - match (&lhs_val, &rhs_val) { + match (lhs_val, rhs_val) { (Value::Number(a), Value::Number(b)) => { - Ok(Value::Number(a.add(b, self.environment.config))) + Ok(Value::Number(a.add(&b, self.environment.config))) } - (Value::String(a), Value::String(b)) => Ok(Value::String( - Cow::Owned(format!("{}{}", a.as_ref(), b.as_ref())), - )), - (Value::String(a), _) => Ok(Value::String(Cow::Owned(format!( - "{}{}", - a.as_ref(), - rhs_val.display(self.environment.config) - )))), - (_, Value::String(b)) => Ok(Value::String(Cow::Owned(format!( - "{}{}", - lhs_val.display(self.environment.config), - b.as_ref() - )))), - (Value::List(a), Value::List(b)) => { - let mut result = a.clone(); - result.extend(b.clone()); - Ok(Value::List(result)) + (Value::String(a), Value::String(b)) => { + let mut result = a.into_owned(); + result.push_str(&b); + Ok(Value::String(Cow::Owned(result))) + } + (Value::String(a), rhs) => { + let mut result = a.into_owned(); + result.push_str(&rhs.display(self.environment.config)); + Ok(Value::String(Cow::Owned(result))) + } + (lhs, Value::String(b)) => { + let mut result = lhs.display(self.environment.config); + result.push_str(&b); + Ok(Value::String(Cow::Owned(result))) + } + (Value::List(mut a), Value::List(b)) => { + a.extend(b); + Ok(Value::List(a)) } - _ => Ok(Value::Number( - lhs_val + (lhs_value, rhs_value) => Ok(Value::Number( + lhs_value .number(lhs.1)? - .add(&rhs_val.number(rhs.1)?, self.environment.config), + .add(rhs_value.number(rhs.1)?, self.environment.config), )), } } @@ -167,7 +172,7 @@ impl<'a> Evaluator<'a> { (lhs_val.number(lhs.1)?, rhs_val.number(rhs.1)?); lhs_num - .div(&rhs_num, self.environment.config) + .div(rhs_num, self.environment.config) .map(Value::Number) .map_err(|error| Error::new(rhs.1, error.to_string())) } @@ -239,13 +244,13 @@ impl<'a> Evaluator<'a> { (lhs_val.number(lhs.1)?, rhs_val.number(rhs.1)?); lhs_num - .rem(&rhs_num, self.environment.config) + .rem(rhs_num, self.environment.config) .map(Value::Number) .map_err(|error| Error::new(rhs.1, error.to_string())) } Expression::BinaryOp(BinaryOp::Multiply, lhs, rhs) => Ok(Value::Number( self.evaluate_expression(lhs)?.number(lhs.1)?.mul( - &self.evaluate_expression(rhs)?.number(rhs.1)?, + self.evaluate_expression(rhs)?.number(rhs.1)?, self.environment.config, ), )), @@ -262,13 +267,13 @@ impl<'a> Evaluator<'a> { (lhs_val.number(lhs.1)?, rhs_val.number(rhs.1)?); lhs_num - .pow(&rhs_num, self.environment.config) + .pow(rhs_num, self.environment.config) .map(Value::Number) .map_err(|error| Error::new(rhs.1, error.to_string())) } Expression::BinaryOp(BinaryOp::Subtract, lhs, rhs) => Ok(Value::Number( self.evaluate_expression(lhs)?.number(lhs.1)?.sub( - &self.evaluate_expression(rhs)?.number(rhs.1)?, + self.evaluate_expression(rhs)?.number(rhs.1)?, self.environment.config, ), )), @@ -418,13 +423,18 @@ impl<'a> Evaluator<'a> { for statement in body { let completion = evaluator.evaluate_statement(statement)?; - result = completion.unwrap(); - match completion { - Completion::Break => return Ok(Completion::Value(result)), - Completion::Continue => break, - Completion::Return(_) => return Ok(Completion::Return(result)), - Completion::Value(_) => {} + Completion::Break => { + return Ok(Completion::Value(Value::Null)); + } + Completion::Continue => { + result = Value::Null; + break; + } + Completion::Return(value) => { + return Ok(Completion::Return(value)); + } + Completion::Value(value) => result = value, } } } @@ -459,12 +469,14 @@ impl<'a> Evaluator<'a> { for statement in body { let completion = evaluator.evaluate_statement(statement)?; - let result = completion.unwrap(); - match completion { - Completion::Break => return Ok(Completion::Value(result)), + Completion::Break => { + return Ok(Completion::Value(Value::Null)); + } Completion::Continue => break, - Completion::Return(_) => return Ok(Completion::Return(result)), + Completion::Return(value) => { + return Ok(Completion::Return(value)); + } Completion::Value(_) => {} } } @@ -491,13 +503,18 @@ impl<'a> Evaluator<'a> { for statement in body { let completion = evaluator.evaluate_statement(statement)?; - result = completion.unwrap(); - match completion { - Completion::Break => return Ok(Completion::Value(result)), - Completion::Continue => break, - Completion::Return(_) => return Ok(Completion::Return(result)), - Completion::Value(_) => {} + Completion::Break => { + return Ok(Completion::Value(Value::Null)); + } + Completion::Continue => { + result = Value::Null; + break; + } + Completion::Return(value) => { + return Ok(Completion::Return(value)); + } + Completion::Value(value) => result = value, } } } @@ -517,13 +534,13 @@ impl<'a> Evaluator<'a> { for statement in statements { let completion = self.evaluate_statement(statement)?; - result = completion.unwrap(); - - if matches!( - &completion, - Completion::Return(_) | Completion::Break | Completion::Continue - ) { - return Ok(completion); + match completion { + Completion::Return(value) => { + return Ok(Completion::Return(value)); + } + Completion::Break => return Ok(Completion::Break), + Completion::Continue => return Ok(Completion::Continue), + Completion::Value(value) => result = value, } } diff --git a/src/function.rs b/src/function.rs index a94d9fd..4b569b5 100644 --- a/src/function.rs +++ b/src/function.rs @@ -23,8 +23,6 @@ impl<'src> Function<'src> { config: Config, span: Span, ) -> Result, Error> { - self.check_arity(arguments.len(), span)?; - match self { Self::Builtin { function, .. } => { function.call(&BuiltinFunctionPayload { @@ -46,8 +44,8 @@ impl<'src> Function<'src> { call_environment.add_function(name, self.clone()); } - for (parameter, argument) in parameters.iter().zip(arguments.iter()) { - call_environment.add_symbol(parameter, argument.clone()); + for (parameter, argument) in parameters.iter().zip(arguments) { + call_environment.add_symbol(parameter, argument); } Evaluator::from(call_environment).enter_function(|evaluator| { diff --git a/src/number.rs b/src/number.rs index b13ae93..9462e03 100644 --- a/src/number.rs +++ b/src/number.rs @@ -273,12 +273,12 @@ impl Number { pub fn sqrt(&self, config: Config) -> Self { match self { Self::Exact(number) => { - let (numerator, denominator) = number.clone().into_numer_denom(); - - if numerator.is_perfect_square() && denominator.is_perfect_square() { + if number.numer().is_perfect_square() + && number.denom().is_perfect_square() + { return Self::Exact(Rational::from(( - numerator.sqrt(), - denominator.sqrt(), + number.numer().clone().sqrt(), + number.denom().clone().sqrt(), ))); } @@ -373,12 +373,26 @@ impl Number { #[must_use] pub fn to_non_negative_usize(&self) -> Option { - let number = self.to_integer()?; + match self { + Self::Exact(number) if number.is_integer() => { + let number = number.numer(); - if number.is_negative() { - None - } else { - number.to_usize() + if number.is_negative() { + None + } else { + number.to_usize() + } + } + Self::Exact(_) => None, + Self::Approx(_) => { + let number = self.to_integer()?; + + if number.is_negative() { + None + } else { + number.to_usize() + } + } } } } diff --git a/src/value.rs b/src/value.rs index 7d0635a..f496853 100644 --- a/src/value.rs +++ b/src/value.rs @@ -54,9 +54,9 @@ impl<'a> Value<'a> { } } - pub(crate) fn list(&self, span: Span) -> Result>, Error> { + pub(crate) fn list(&self, span: Span) -> Result<&[Value<'a>], Error> { if let Value::List(x) = self { - Ok(x.clone()) + Ok(x) } else { Err(Error { span, @@ -65,9 +65,9 @@ impl<'a> Value<'a> { } } - pub(crate) fn number(&self, span: Span) -> Result { + pub(crate) fn number(&self, span: Span) -> Result<&Number, Error> { if let Value::Number(x) = self { - Ok(x.clone()) + Ok(x) } else { Err(Error { span,