qalam 0.3.1

Interpreter for the Qalam programming language. Qalam is a dead-simple, Urdu inspired, interpreted programming langauge.
Documentation
use crate::native::*;

#[derive(Debug, Clone)]
pub struct SubstrFn {}

impl SubstrFn {
    pub fn init() -> Self {
        return Self {};
    }
}

impl QalamCallable for SubstrFn {
    fn call(
        &mut self,
        _interpreter: &mut Interpreter,
        arguments: Vec<Option<Literal>>,
        paren: &Token,
    ) -> Result<Option<Literal>, RuntimeError> {
        let arg = &arguments[0];
        let start = &arguments[1];
        let length = &arguments[2];

        if let (Some(arg), Some(start), Some(length)) = (arg, start, length) {
            if let Literal::String(arg) = arg {
                if let (Literal::Number(start), Literal::Number(length)) = (start, length) {
                    if !is_usize(**start) {
                        return Err(RuntimeError::init(
                            paren,
                            format!("'start' must be a positive integer!"),
                        ));
                    }

                    if !is_usize(**length) {
                        return Err(RuntimeError::init(
                            paren,
                            format!("'length' must be a positive integer!"),
                        ));
                    }

                    let start = **start as usize;
                    let length = **length as usize;

                    let s = &arg[start..(start + length)];
                    return Ok(Some(Literal::String(String::from(s))));
                } else {
                    return Err(RuntimeError::init(
                        paren,
                        format!(
                            "'start' = {} and 'length' = {} must be numbers!",
                            start.to_qalam_string(),
                            length.to_qalam_string()
                        ),
                    ));
                }
            } else {
                return Err(RuntimeError::init(
                    paren,
                    format!("'arg' = {} must be a string!", arg.to_qalam_string()),
                ));
            }
        } else {
            return Err(RuntimeError::init(
                paren,
                format!("All arguments must be defined!"),
            ));
        }
    }

    fn arity(&self) -> usize {
        return 3;
    }

    fn clone_box(&self) -> Box<dyn QalamCallable> {
        return Box::new(self.clone());
    }

    fn to_string(&self) -> String {
        return String::from("<native amal substr(arg, start, length)>");
    }

    fn as_any(&self) -> &dyn std::any::Any {
        self
    }
}