maid-lang 1.1.0

Maid Programming Language
Documentation
use std::{cell::RefCell, rc::Rc};

use crate::{
    errors::standard_error::StandardError,
    interpreting::context::Context,
    lexing::position::Position,
    values::{
        built_in_function::BuiltInFunction, function::Function, list::List, number::Number,
        string::Str,
    },
};

#[derive(Debug, Clone)]
pub enum Value {
    NumberValue(Number),
    ListValue(List),
    StringValue(Str),
    FunctionValue(Function),
    BuiltInFunction(BuiltInFunction),
}

impl Value {
    pub fn position_start(&self) -> Option<Position> {
        match self {
            Value::NumberValue(value) => value.pos_start.clone(),
            Value::ListValue(value) => value.pos_start.clone(),
            Value::StringValue(value) => value.pos_start.clone(),
            Value::FunctionValue(value) => value.pos_start.clone(),
            Value::BuiltInFunction(value) => value.pos_start.clone(),
        }
    }

    pub fn position_end(&self) -> Option<Position> {
        match self {
            Value::NumberValue(value) => value.pos_end.clone(),
            Value::ListValue(value) => value.pos_end.clone(),
            Value::StringValue(value) => value.pos_end.clone(),
            Value::FunctionValue(value) => value.pos_end.clone(),
            Value::BuiltInFunction(value) => value.pos_end.clone(),
        }
    }

    pub fn set_position(
        &mut self,
        pos_start: Option<Position>,
        pos_end: Option<Position>,
    ) -> Value {
        match self {
            Value::NumberValue(value) => {
                value.pos_start = pos_start;
                value.pos_end = pos_end;
            }
            Value::ListValue(value) => {
                value.pos_start = pos_start;
                value.pos_end = pos_end;
            }
            Value::StringValue(value) => {
                value.pos_start = pos_start;
                value.pos_end = pos_end;
            }
            Value::FunctionValue(value) => {
                value.pos_start = pos_start;
                value.pos_end = pos_end;
            }
            Value::BuiltInFunction(value) => {
                value.pos_start = pos_start;
                value.pos_end = pos_end;
            }
        }

        self.clone()
    }

    pub fn set_context(&mut self, context: Option<Rc<RefCell<Context>>>) -> Value {
        match self {
            Value::NumberValue(value) => value.context = context,
            Value::ListValue(value) => value.context = context,
            Value::StringValue(value) => value.context = context,
            Value::FunctionValue(value) => value.context = context,
            Value::BuiltInFunction(value) => value.context = context,
        }

        self.clone()
    }

    pub fn perform_operation(
        &mut self,
        operator: &str,
        other: Value,
    ) -> Result<Value, StandardError> {
        match self {
            Value::NumberValue(value) => value.perform_operation(operator, other),
            Value::ListValue(value) => value.to_owned().perform_operation(operator, other),
            Value::StringValue(value) => value.perform_operation(operator, other),
            _ => Err(StandardError::new(
                format!("type doesn't support the '{operator}' operator").as_str(),
                self.position_start().unwrap(),
                self.position_end().unwrap(),
                None,
            )),
        }
    }

    pub fn object_type(&self) -> &str {
        match self {
            Value::NumberValue(_) => "number",
            Value::ListValue(_) => "list",
            Value::StringValue(_) => "string",
            Value::FunctionValue(_) => "function",
            Value::BuiltInFunction(_) => "built-in-function",
            _ => "null",
        }
    }

    pub fn is_true(&self) -> bool {
        match self {
            Value::NumberValue(value) => value.value != 0.0,
            Value::ListValue(value) => value.elements.is_empty(),
            Value::StringValue(value) => value.value.is_empty(),
            Value::FunctionValue(value) => value.name.is_empty(),
            Value::BuiltInFunction(value) => value.name.is_empty(),
            _ => false,
        }
    }

    pub fn as_string(&self) -> String {
        match self {
            Value::NumberValue(value) => value.as_string(),
            Value::ListValue(value) => value.as_string(),
            Value::StringValue(value) => value.as_string(),
            Value::FunctionValue(value) => value.as_string(),
            Value::BuiltInFunction(value) => value.as_string(),
            _ => "".to_string(),
        }
    }
}