diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index f65c8e8..c2d24e7 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -82,8 +82,8 @@ impl Value { Value::Raw(ValueData::String(to_string.to_string())) } - pub fn list(value: Vec) -> Self { - Value::Raw(ValueData::List(value)) + pub fn list>>(values: T) -> Self { + Value::Raw(ValueData::List(values.into())) } pub fn map>>(into_map: T) -> Self { @@ -737,6 +737,54 @@ impl Display for Value { } } +impl From for Value { + fn from(value: bool) -> Self { + Value::boolean(value) + } +} + +impl From for Value { + fn from(value: u8) -> Self { + Value::byte(value) + } +} + +impl From for Value { + fn from(value: char) -> Self { + Value::character(value) + } +} + +impl From for Value { + fn from(value: f64) -> Self { + Value::float(value) + } +} + +impl From for Value { + fn from(value: i32) -> Self { + Value::integer(value as i64) + } +} + +impl From for Value { + fn from(value: i64) -> Self { + Value::integer(value) + } +} + +impl From for Value { + fn from(value: String) -> Self { + Value::string(value) + } +} + +impl From<&str> for Value { + fn from(str: &str) -> Self { + Value::string(str) + } +} + impl Eq for Value {} impl PartialEq for Value { @@ -1118,54 +1166,6 @@ impl ValueData { } } -impl From for ValueData { - fn from(value: bool) -> Self { - ValueData::Boolean(value) - } -} - -impl From for ValueData { - fn from(value: u8) -> Self { - ValueData::Byte(value) - } -} - -impl From for ValueData { - fn from(value: char) -> Self { - ValueData::Character(value) - } -} - -impl From for ValueData { - fn from(value: f64) -> Self { - ValueData::Float(value) - } -} - -impl From for ValueData { - fn from(value: i32) -> Self { - ValueData::Integer(value as i64) - } -} - -impl From for ValueData { - fn from(value: i64) -> Self { - ValueData::Integer(value) - } -} - -impl From for ValueData { - fn from(value: String) -> Self { - ValueData::String(value) - } -} - -impl From<&str> for ValueData { - fn from(value: &str) -> Self { - ValueData::String(value.to_string()) - } -} - impl Display for ValueData { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index f06ed2b..74cd42f 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -7,6 +7,7 @@ use std::{ collections::HashMap, fmt::{self, Display, Formatter}, + rc::Weak, sync::{Arc, Mutex}, }; @@ -242,11 +243,18 @@ impl Vm { let position = value.position(); let value = self .run_expression(value, collect_garbage)? - .expect_value(position)? - .into_reference(); + .expect_value(position)?; + + let reference = match value { + Value::Raw(_) => value.into_reference(), + Value::Reference(_) => value, + Value::Mutable(_) => { + return Err(RuntimeError::CannotAssignToMutable { position }); + } + }; self.context - .set_variable_value(identifier.inner, value) + .set_variable_value(identifier.inner, reference) .map_err(|error| RuntimeError::ContextError { error, position })?; Ok(()) @@ -1080,6 +1088,9 @@ impl Vm { #[derive(Clone, Debug, PartialEq)] pub enum RuntimeError { + CannotAssignToMutable { + position: Span, + }, ConstructError { error: ConstructError, position: Span, @@ -1182,6 +1193,7 @@ pub enum RuntimeError { impl RuntimeError { pub fn position(&self) -> Span { match self { + Self::CannotAssignToMutable { position } => *position, Self::ConstructError { position, .. } => *position, Self::ContextError { position, .. } => *position, Self::BuiltInFunctionError { position, .. } => *position, @@ -1233,6 +1245,13 @@ impl From for RuntimeError { impl Display for RuntimeError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { + Self::CannotAssignToMutable { position } => { + write!( + f, + "Cannot use immutable assignment with a mutable value at {:?}", + position + ) + } Self::ConstructError { error, position } => { write!(f, "Constructor error at {:?}: {}", position, error) } @@ -1398,6 +1417,44 @@ mod tests { use super::*; + #[test] + fn mutate_copied_variable() { + let source = "let mut x = 42; let y = [x; 3]; x += 1; y"; + + assert_eq!( + run(source), + Ok(Some(Value::list([43.into(), 43.into(), 43.into()]))) + ); + } + + #[test] + fn auto_fill_list() { + let source = "[42; 3]"; + + assert_eq!( + run(source), + Ok(Some(Value::list(vec![ + Value::integer(42), + Value::integer(42), + Value::integer(42) + ]))) + ); + } + + #[test] + fn mutate_assigned_variable() { + let source = "let mut x = 42; let mut y = x; x += 1; y"; + + assert_eq!(run(source), Ok(Some(Value::integer(43)))); + } + + #[test] + fn assign_to_variable() { + let source = "let x = 42; let y = x; y"; + + assert_eq!(run(source), Ok(Some(Value::integer(42)))); + } + #[test] fn block_scope_captures_parent() { let source = "let x = 42; { x }";