loft 0.0.1-alpha.22

Rusty embedded scripting language
Documentation
use super::*;

impl<'st> Interpreter {
    pub(crate) fn handle_str_method_call(&mut self, handle: Method, value: Vec<u8>) -> Result<Value, String> {
        let Method { object, args, call } = handle;

        match call {
            "len" => {
                if !args.is_empty() {
                    return Err("len method does not take any arguments".to_string());
                }
                let len = value.len();
                Ok(val!(ValueType::USize(len)))
            }

            "push" => {
                if args.len() != 1 {
                    return Err("push method takes exactly one argument".to_string());
                }

                let arg_value = self.evaluate_expression(&args[0])?;
                let actual_value = match arg_value.borrow().inner() {
                    ValueType::Reference {
                        source_name: _,
                        source_scope: _,
                        original_ptr: _,
                        _undropped: ref value,
                    } => value.borrow().inner(),
                    other => other,
                };

                if let ValueType::Str(push_value) = actual_value {
                    let mut object_mut = object.borrow_mut();
                    match *object_mut {
                        ValueEnum::Mutable(ValueType::Str(ref mut string)) => {
                            string.extend(push_value);
                            Ok(object.clone())
                        }

                        ValueEnum::Mutable(ValueType::Reference { _undropped: ref value, .. }) => {
                            let mut value_ref = value.borrow_mut();
                            if let ValueEnum::Mutable(ValueType::Str(ref mut string)) = *value_ref {
                                string.extend(push_value);
                                Ok(object.clone())
                            } else {
                                Err("Cannot call push on an immutable string".to_string())
                            }
                        }

                        _ => Err("Cannot call push on an immutable string".to_string()),
                    }
                } else {
                    Err("push method requires a string argument".to_string())
                }
            }

            "pop" => {
                if !args.is_empty() {
                    return Err("pop method does not take any arguments".to_string());
                }

                let mut object_mut = object.borrow_mut();
                if let ValueEnum::Mutable(ValueType::Str(ref mut string)) = *object_mut {
                    if let Some(popped_char) = string.pop() {
                        Ok(ValueEnum::new_str([popped_char]))
                    } else {
                        Err("Cannot pop from an empty string".to_string())
                    }
                } else {
                    Err("Cannot call pop on an immutable string".to_string())
                }
            }

            _ => Err(format!("Unknown method `{call}` for string")),
        }
    }
}