loft 0.0.1-alpha.22

Rusty embedded scripting language
Documentation
mod bool;
mod clone;
mod display;

use crate::parser::ast::*;
use std::{borrow::Cow, cell::RefCell, collections::HashMap, fmt, rc::Rc};

pub type Cell = RefCell<ValueEnum>;
pub type Value = Rc<Cell>;
pub type Ptr = *const Cell;

#[derive(Clone, Debug, PartialEq)]
pub enum ValueEnum {
    Immutable(ValueType),
    Mutable(ValueType),
}

#[derive(Clone, Debug, PartialEq)]
pub struct FunctionData {
    pub name: Option<String>,
    pub params: Vec<(Pattern, Type)>,
    pub body: Vec<Stmt>,
    pub return_type: Option<Type>,
    pub captures: Option<HashMap<String, Value>>,
    pub type_params: Vec<GenericParam>,
    pub is_method: bool,
    pub is_const: bool,
    pub visibility: bool,
}

#[derive(Clone, Debug, PartialEq)]
pub enum ValueType {
    Function(Rc<FunctionData>),

    I8(i8),
    I16(i16),
    I32(i32),
    I64(i64),
    I128(i128),
    ISize(isize),

    U8(u8),
    U16(u16),
    U32(u32),
    U64(u64),
    U128(u128),
    USize(usize),

    F32(f32),
    F64(f64),

    Str(Vec<u8>),
    Pointer(Ptr),
    Boolean(bool),
    Tuple(Vec<Value>),

    Return(Value),
    Continue(Option<String>),
    Break(Option<String>, Option<Value>),

    TailCall {
        function: Value,
        arguments: Vec<Value>,
    },

    Range {
        start: Value,
        end: Value,
        inclusive: bool,
    },

    Iterator {
        current: Value,
        end: Value,
        inclusive: bool,
        exhausted: bool,
        collection: Value,
        kind: String,
    },

    Struct {
        name: String,
        fields: HashMap<String, Value>,
    },

    StructDef {
        name: String,
        fields: HashMap<String, (Type, bool)>,
        methods: HashMap<String, Function>,
    },

    Enum {
        enum_type: String,
        variant: String,
        data: Option<Vec<Value>>,
    },

    EnumDef {
        name: String,
        variants: Vec<EnumVariant>,
        methods: HashMap<String, Function>,
    },

    EnumConstructor {
        enum_name: String,
        variant_name: String,
        fields: Vec<Type>,
    },

    EnumStructConstructor {
        enum_name: String,
        variant_name: String,
        fields: HashMap<String, (Type, bool)>,
    },

    FieldRef {
        base: Value,
        chain: Vec<String>,
    },

    Reference {
        original_ptr: Ptr,
        _undropped: Rc<Cell>,
        source_name: Option<String>,
        source_scope: Option<usize>,
    },

    StaticMethod {
        struct_name: String,
        method: String,
        function: Function,
    },

    Array {
        ty: Box<ValueType>,
        el: Vec<Value>,
        len: usize,
    },

    Slice {
        ty: Box<ValueType>,
        el: Vec<Value>,
    },

    Unbounded,
    Unit,
}

pub trait ValueExt {
    fn as_ptr(&self) -> Ptr;

    fn into_return(self) -> Value;
}

impl ValueExt for Value {
    fn as_ptr(&self) -> Ptr { Rc::as_ptr(self) }

    fn into_return(self) -> Value {
        {
            let mut value = self.borrow_mut();
            let (inner_val, is_mutable) = match &*value {
                ValueEnum::Mutable(v) => (v.clone(), true),
                ValueEnum::Immutable(v) => (v.clone(), false),
            };

            *value = if is_mutable {
                ValueEnum::Mutable(ValueType::Return(Value::new(RefCell::new(ValueEnum::Mutable(inner_val)))))
            } else {
                ValueEnum::Immutable(ValueType::Return(Value::new(RefCell::new(ValueEnum::Immutable(inner_val)))))
            };
        }

        return self;
    }
}

impl ValueEnum {
    pub fn unit() -> Value { crate::val!(ValueType::Unit) }

    pub fn is_mutable(&self) -> bool { matches!(self, ValueEnum::Mutable(_)) }

    pub fn is_ref(&self) -> bool { matches!(self.inner(), ValueType::Reference { .. }) }

    pub fn deep_clone(&self) -> Value {
        match self {
            ValueEnum::Immutable(inner) => crate::val!(inner.deep_clone()),
            ValueEnum::Mutable(inner) => crate::val!(mut inner.deep_clone()),
        }
    }

    pub fn into_mutable(self) -> ValueEnum {
        match self {
            ValueEnum::Immutable(inner) => ValueEnum::Mutable(inner),
            already_mutable => already_mutable,
        }
    }

    pub fn into_immutable(self) -> ValueEnum {
        match self {
            ValueEnum::Mutable(inner) => ValueEnum::Immutable(inner),
            already_immutable => already_immutable,
        }
    }

    pub fn inner(&self) -> ValueType {
        match self {
            ValueEnum::Mutable(inner) | ValueEnum::Immutable(inner) => inner.clone(),
        }
    }

    pub fn inner_mut(&mut self) -> &mut ValueType {
        match self {
            ValueEnum::Mutable(inner) => inner,
            ValueEnum::Immutable(_) => panic!("Called inner_mut on immutable value"),
        }
    }

    pub fn as_bytes(&self) -> Cow<[u8]> {
        match self {
            ValueEnum::Immutable(ValueType::Str(s)) | ValueEnum::Mutable(ValueType::Str(s)) => Cow::Borrowed(s),
            _ => Cow::Owned(self.to_string().into_bytes()),
        }
    }

    pub fn new_str<S: AsRef<[u8]>>(s: S) -> Value {
        let rc = crate::val!(mut ValueType::Str(s.as_ref().to_vec()));

        crate::val!(ValueType::Reference {
            source_name: None,
            source_scope: None,

            original_ptr: Rc::as_ptr(&rc),
            _undropped: rc,
        })
    }

    pub fn get_source_info(&self) -> Option<(String, usize)> {
        match &self.inner() {
            ValueType::Reference {
                source_name: Some(name),
                source_scope: Some(scope),
                ..
            } => Some((name.clone(), *scope)),
            _ => None,
        }
    }

    pub fn kind(&self) -> String {
        match self.inner() {
            ValueType::Function(_) => String::from("function"),
            ValueType::TailCall { .. } => String::from("tail_call"),

            ValueType::I8(_) => String::from("i8"),
            ValueType::I16(_) => String::from("i16"),
            ValueType::I32(_) => String::from("i32"),
            ValueType::I64(_) => String::from("i64"),
            ValueType::I128(_) => String::from("i128"),
            ValueType::ISize(_) => String::from("isize"),

            ValueType::U8(_) => String::from("u8"),
            ValueType::U16(_) => String::from("u16"),
            ValueType::U32(_) => String::from("u32"),
            ValueType::U64(_) => String::from("u64"),
            ValueType::U128(_) => String::from("u128"),
            ValueType::USize(_) => String::from("usize"),

            ValueType::F32(_) => String::from("f32"),
            ValueType::F64(_) => String::from("f64"),

            ValueType::Str(_) => String::from("str"),
            ValueType::Pointer(_) => String::from("pointer"),
            ValueType::Boolean(_) => String::from("bool"),
            ValueType::Tuple(_) => String::from("tuple"),

            ValueType::Return(_) => String::from("return"),
            ValueType::Continue(_) => String::from("continue"),
            ValueType::Break(_, _) => String::from("break"),

            ValueType::StructDef { name, .. } => name,
            ValueType::EnumDef { name, .. } => name,

            ValueType::Struct { name, .. } => name,
            ValueType::Enum { enum_type, .. } => enum_type,

            ValueType::EnumConstructor { enum_name, variant_name, .. } => format!("{}::{}", enum_name, variant_name),
            ValueType::EnumStructConstructor { enum_name, variant_name, .. } => format!("{}::{}", enum_name, variant_name),

            ValueType::FieldRef { .. } => String::from("field_ref"),
            ValueType::Reference { .. } => String::from("reference"),
            ValueType::StaticMethod { .. } => String::from("static_method"),

            ValueType::Range { .. } => String::from("range"),
            ValueType::Array { .. } => String::from("array"),
            ValueType::Slice { .. } => String::from("slice"),
            ValueType::Iterator { .. } => String::from("iterator"),

            ValueType::Unbounded => String::from("unbounded"),
            ValueType::Unit => String::from("unit"),
        }
    }
}