loft 0.0.1-alpha.22

Rusty embedded scripting language
Documentation
use super::*;

fn is_string_value(value: &Value) -> bool {
    let borrowed = value.borrow();
    match borrowed.inner() {
        ValueType::Str(_) => true,
        ValueType::Reference { original_ptr, .. } if !original_ptr.is_null() => unsafe {
            let ref_borrowed = (*original_ptr).borrow();
            matches!(ref_borrowed.inner(), ValueType::Str(_))
        },
        _ => false,
    }
}

impl fmt::Display for ValueEnum {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let value_type = self.inner();

        match value_type {
            ValueType::Function(func) => write!(f, "{:?}", func.name),

            ValueType::Str(v) => write!(f, "{}", String::from_utf8_lossy(&v)),

            ValueType::I8(v) => write!(f, "{v}"),

            ValueType::I16(v) => write!(f, "{v}"),

            ValueType::I32(v) => write!(f, "{v}"),

            ValueType::I64(v) => write!(f, "{v}"),

            ValueType::I128(v) => write!(f, "{v}"),

            ValueType::ISize(v) => write!(f, "{v}"),

            ValueType::U8(v) => write!(f, "{v}"),

            ValueType::U16(v) => write!(f, "{v}"),

            ValueType::U32(v) => write!(f, "{v}"),

            ValueType::U64(v) => write!(f, "{v}"),

            ValueType::U128(v) => write!(f, "{v}"),

            ValueType::USize(v) => write!(f, "{v}"),

            ValueType::F32(v) => write!(f, "{v}"),

            ValueType::F64(v) => write!(f, "{v}"),

            ValueType::Unit => write!(f, "()"),

            ValueType::Unbounded => write!(f, ".."),

            ValueType::Boolean(v) => write!(f, "{}", v),

            ValueType::Return(v) => write!(f, "{}", v.borrow()),

            ValueType::Continue(_) => write!(f, "continue"),

            ValueType::Break(_, _) => write!(f, "break"),

            ValueType::Pointer(ptr) => write!(f, "{:p}", ptr),

            ValueType::StructDef { name, .. } => write!(f, "<struct {name}>"),

            ValueType::EnumDef { name, .. } => write!(f, "<enum {name}>"),

            ValueType::Range { start, end, inclusive } => write!(f, "{}..{2}{}", start.borrow(), end.borrow(), if inclusive { "=" } else { "" }),

            ValueType::Iterator { current, end, inclusive, kind, .. } => write!(f, "<{kind} {}..{2}{}>", current.borrow(), end.borrow(), if inclusive { "=" } else { "" }),

            ValueType::StaticMethod { struct_name, method, .. } => write!(f, "{}::{}", struct_name, method),

            ValueType::EnumConstructor { enum_name, variant_name, .. } => write!(f, "<constructor {}::{}>", enum_name, variant_name),

            ValueType::EnumStructConstructor { enum_name, variant_name, .. } => write!(f, "<struct-constructor {}::{}>", enum_name, variant_name),

            ValueType::TailCall { function, arguments } => {
                write!(f, "tail_call(")?;
                write!(f, "{}", function.borrow())?;
                write!(f, ", [")?;
                for (i, arg) in arguments.iter().enumerate() {
                    if i > 0 {
                        write!(f, ", ")?;
                    }
                    write!(f, "{}", arg.borrow())?;
                }
                write!(f, "])")
            }

            ValueType::FieldRef { base, chain, .. } => {
                if self.is_mutable() {
                    write!(f, "&mut ")?;
                }
                write!(f, "{}", base.borrow())?;
                for field in chain {
                    write!(f, ".{field}")?;
                }
                Ok(())
            }

            ValueType::Reference { source_name, original_ptr, .. } => {
                if !original_ptr.is_null() {
                    unsafe { write!(f, "{}", (*original_ptr).borrow()) }
                } else if let Some(name) = source_name {
                    if self.is_mutable() { write!(f, "&mut {name}") } else { write!(f, "&{name}") }
                } else {
                    write!(f, "&<unnamed>")
                }
            }

            ValueType::Tuple(values) => {
                write!(f, "(")?;
                for (i, value) in values.iter().enumerate() {
                    if i > 0 {
                        write!(f, ", ")?;
                    }
                    if is_string_value(value) {
                        write!(f, "\"{}\"", value.borrow())?;
                    } else {
                        write!(f, "{}", value.borrow())?;
                    }
                }
                write!(f, ")")
            }

            ValueType::Array { el, .. } => {
                write!(f, "[")?;
                for (i, value) in el.iter().enumerate() {
                    if i > 0 {
                        write!(f, ", ")?;
                    }
                    if is_string_value(value) {
                        write!(f, "\"{}\"", value.borrow())?;
                    } else {
                        write!(f, "{}", value.borrow())?;
                    }
                }
                write!(f, "]")
            }

            ValueType::Slice { el, .. } => {
                write!(f, "[")?;
                for (i, value) in el.iter().enumerate() {
                    if i > 0 {
                        write!(f, ", ")?;
                    }
                    if is_string_value(value) {
                        write!(f, "\"{}\"", value.borrow())?;
                    } else {
                        write!(f, "{}", value.borrow())?;
                    }
                }
                write!(f, "]")
            }

            ValueType::Enum { variant, data, .. } => {
                write!(f, "{variant}")?;
                if let Some(values) = data {
                    write!(f, "(")?;
                    for (i, value) in values.iter().enumerate() {
                        if i > 0 {
                            write!(f, ", ")?;
                        }
                        if is_string_value(value) {
                            write!(f, "\"{}\"", value.borrow())?;
                        } else {
                            write!(f, "{}", value.borrow())?;
                        }
                    }
                    write!(f, ")")
                } else {
                    Ok(())
                }
            }

            ValueType::Struct { name, fields } => {
                if fields.keys().all(|k| k.parse::<usize>().is_ok()) {
                    let mut sorted_fields: Vec<_> = fields.iter().collect();
                    sorted_fields.sort_by_key(|(k, _)| k.parse::<usize>().unwrap());

                    write!(f, "{name}(")?;
                    for (i, (_, value)) in sorted_fields.iter().enumerate() {
                        if i > 0 {
                            write!(f, ", ")?;
                        }
                        if is_string_value(value) {
                            write!(f, "\"{}\"", value.borrow())?;
                        } else {
                            write!(f, "{}", value.borrow())?;
                        }
                    }
                    write!(f, ")")
                } else {
                    write!(f, "{name} {{ ")?;
                    for (i, (field_name, value)) in fields.iter().enumerate() {
                        if i > 0 {
                            write!(f, ", ")?;
                        }
                        if is_string_value(value) {
                            write!(f, "{}: \"{}\"", field_name, value.borrow())?;
                        } else {
                            write!(f, "{}: {}", field_name, value.borrow())?;
                        }
                    }
                    write!(f, " }}")
                }
            }
        }
    }
}