loft 0.0.1-alpha.22

Rusty embedded scripting language
Documentation
use super::*;

impl<'st> Interpreter {
    #[inline]
    pub(crate) fn parse_let_statement(&mut self, attr: &Stmt) -> Result<Value, String> {
        unbind! { Stmt::Let { pattern, initializer, type_annotation, .. } = attr }

        let value = if let Some(init) = initializer {
            let init_value = self.evaluate_expression(init)?;
            if let Some(target_type) = type_annotation {
                self.perform_cast(init_value, target_type)?
            } else {
                init_value
            }
        } else {
            ValueEnum::unit()
        };

        match pattern {
            Pattern::Identifier { name, mutable } => {
                let declared_mutability = *mutable;
                let is_initialized = initializer.is_some();
                let value_inner = { value.borrow().inner() };

                if let ValueType::Reference { source_name, .. } = value_inner {
                    if source_name.is_none() {
                        self.env.scope_resolver.declare_variable(name, declared_mutability);

                        if is_initialized {
                            self.env.scope_resolver.mark_as_initialized(name)?;
                        }

                        let mut value_ref = value.borrow_mut();
                        *value_ref = if declared_mutability {
                            value_ref.clone().into_mutable()
                        } else {
                            value_ref.clone().into_immutable()
                        };
                    } else {
                        self.env.scope_resolver.declare_variable(name, value.borrow().is_mutable());
                        self.env.scope_resolver.mark_as_initialized(name)?;
                    }
                } else {
                    self.env.scope_resolver.declare_variable(name, declared_mutability);

                    if is_initialized {
                        self.env.scope_resolver.mark_as_initialized(name)?;
                    }

                    let mut value_ref = value.borrow_mut();
                    *value_ref = if declared_mutability {
                        value_ref.clone().into_mutable()
                    } else {
                        value_ref.clone().into_immutable()
                    };
                }

                self.env.set_variable_raw(name, value)?;
            }

            Pattern::Tuple(patterns) => {
                let value_inner = value.borrow().inner();

                match value_inner {
                    ValueType::Tuple(elements) => {
                        if patterns.len() != elements.len() {
                            return Err(format!("Expected tuple with {} elements but got {} elements", patterns.len(), elements.len()));
                        }

                        for (i, pattern) in patterns.iter().enumerate() {
                            match pattern {
                                Pattern::Identifier { name, mutable } => {
                                    let element_value = elements[i].clone();
                                    let is_ref = matches!(element_value.borrow().inner(), ValueType::Reference { .. });
                                    let declared_mutability = if is_ref { element_value.borrow().is_mutable() } else { *mutable };

                                    self.env.scope_resolver.declare_variable(name, declared_mutability);
                                    self.env.scope_resolver.mark_as_initialized(name)?;

                                    if !is_ref {
                                        let mut element_ref = element_value.borrow_mut();
                                        *element_ref = if declared_mutability {
                                            element_ref.clone().into_mutable()
                                        } else {
                                            element_ref.clone().into_immutable()
                                        };
                                    }

                                    self.env.set_variable_raw(name, element_value)?;
                                }
                                _ => return Err("Nested destructuring patterns are not supported yet".to_string()),
                            }
                        }
                    }
                    _ => return Err("Cannot destructure non-tuple value".to_string()),
                }
            }

            Pattern::Struct { path, fields, rest } => {
                let value_inner = value.borrow().inner();
                match value_inner {
                    ValueType::Struct {
                        name: struct_name,
                        fields: ref struct_fields,
                    } => {
                        let expected_name = &path.segments[0].ident;
                        if &struct_name != expected_name {
                            return Err(format!("Expected struct '{}' but got '{}'", expected_name, struct_name));
                        }

                        for (field_name, field_pattern) in fields {
                            match struct_fields.get(field_name) {
                                Some(field_value) => match field_pattern {
                                    Pattern::Identifier { name, mutable } => {
                                        self.env.scope_resolver.declare_variable(name, *mutable);
                                        self.env.scope_resolver.mark_as_initialized(name)?;
                                        let mut field_value_ref = field_value.borrow_mut();
                                        *field_value_ref = if *mutable {
                                            field_value_ref.clone().into_mutable()
                                        } else {
                                            field_value_ref.clone().into_immutable()
                                        };
                                        self.env.set_variable_raw(name, field_value.clone())?;
                                    }
                                    _ => {
                                        return Err("Nested destructuring patterns for structs are not supported yet".to_string());
                                    }
                                },
                                None => return Err(format!("Field '{}' not found in struct '{}'", field_name, struct_name)),
                            }
                        }

                        if !*rest && struct_fields.len() != fields.len() {
                            return Err("Struct pattern does not cover all fields".to_string());
                        }
                    }
                    _ => return Err("Cannot destructure non-struct value".to_string()),
                }
            }

            _ => return Err("Unsupported pattern in let binding".to_string()),
        }

        Ok(ValueEnum::unit())
    }
}