diff --git a/dust-lang/src/lexer.rs b/dust-lang/src/lexer.rs index 6694e20..d2b9f6c 100644 --- a/dust-lang/src/lexer.rs +++ b/dust-lang/src/lexer.rs @@ -429,6 +429,7 @@ impl Lexer { "is_even" => Token::IsEven, "is_odd" => Token::IsOdd, "length" => Token::Length, + "mut" => Token::Mut, "read_line" => Token::ReadLine, "struct" => Token::Struct, "to_string" => Token::ToString, @@ -506,34 +507,6 @@ impl Display for LexError { mod tests { use super::*; - #[test] - fn all_keywords() { - let input = "async bool else false float if int is_even is_odd length read_line struct to_string true while write_line"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Async, (0, 5)), - (Token::Bool, (6, 10)), - (Token::Else, (11, 15)), - (Token::Boolean("false"), (16, 21)), - (Token::FloatKeyword, (22, 27)), - (Token::If, (28, 30)), - (Token::Int, (31, 34)), - (Token::IsEven, (35, 42)), - (Token::IsOdd, (43, 49)), - (Token::Length, (50, 56)), - (Token::ReadLine, (57, 66)), - (Token::Struct, (67, 73)), - (Token::ToString, (74, 83)), - (Token::Boolean("true"), (84, 88)), - (Token::While, (89, 94)), - (Token::WriteLine, (95, 105)), - (Token::Eof, (105, 105)), - ]) - ); - } - #[test] fn unit_struct() { let input = "struct Foo"; diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index bbb683f..617617f 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -1211,6 +1211,29 @@ mod tests { use super::*; + #[test] + fn mutable_variable() { + let input = "mut x = 42"; + + assert_eq!( + parse(input), + Ok(AbstractSyntaxTree { + nodes: [Node::new( + Statement::Assignment { + identifier: Node::new(Identifier::new("x"), (4, 5)), + operator: Node::new(AssignmentOperator::Assign, (6, 7)), + value: Box::new(Node::new( + Statement::Constant(Value::integer(42)), + (8, 10) + )), + }, + (0, 10) + )] + .into() + }) + ); + } + #[test] fn async_block() { let input = "async { x = 42; y = 4.0 }"; diff --git a/dust-lang/src/token.rs b/dust-lang/src/token.rs index b0b2bf8..6e61561 100644 --- a/dust-lang/src/token.rs +++ b/dust-lang/src/token.rs @@ -26,6 +26,7 @@ pub enum Token<'src> { IsEven, IsOdd, Length, + Mut, ReadLine, Str, Struct, @@ -98,6 +99,7 @@ impl<'src> Token<'src> { Token::LessEqual => TokenOwned::LessOrEqual, Token::Minus => TokenOwned::Minus, Token::MinusEqual => TokenOwned::MinusEqual, + Token::Mut => TokenOwned::Mut, Token::Percent => TokenOwned::Percent, Token::Plus => TokenOwned::Plus, Token::PlusEqual => TokenOwned::PlusEqual, @@ -153,6 +155,7 @@ impl<'src> Token<'src> { Token::LessEqual => "<=", Token::Minus => "-", Token::MinusEqual => "-=", + Token::Mut => "mut", Token::Percent => "%", Token::Plus => "+", Token::PlusEqual => "+=", @@ -205,6 +208,7 @@ impl<'src> Token<'src> { Token::LessEqual => TokenKind::LessOrEqual, Token::Minus => TokenKind::Minus, Token::MinusEqual => TokenKind::MinusEqual, + Token::Mut => TokenKind::Mut, Token::Percent => TokenKind::Percent, Token::Plus => TokenKind::Plus, Token::PlusEqual => TokenKind::PlusEqual, @@ -306,6 +310,7 @@ pub enum TokenOwned { IsEven, IsOdd, Length, + Mut, ReadLine, Str, ToString, @@ -379,6 +384,7 @@ impl Display for TokenOwned { TokenOwned::LessOrEqual => Token::LessEqual.fmt(f), TokenOwned::Minus => Token::Minus.fmt(f), TokenOwned::MinusEqual => Token::MinusEqual.fmt(f), + TokenOwned::Mut => Token::Mut.fmt(f), TokenOwned::Percent => Token::Percent.fmt(f), TokenOwned::Plus => Token::Plus.fmt(f), TokenOwned::PlusEqual => Token::PlusEqual.fmt(f), @@ -447,6 +453,7 @@ pub enum TokenKind { LessOrEqual, Minus, MinusEqual, + Mut, Percent, Plus, PlusEqual, @@ -494,6 +501,7 @@ impl Display for TokenKind { TokenKind::LessOrEqual => Token::LessEqual.fmt(f), TokenKind::Minus => Token::Minus.fmt(f), TokenKind::MinusEqual => Token::MinusEqual.fmt(f), + TokenKind::Mut => Token::Mut.fmt(f), TokenKind::Percent => Token::Percent.fmt(f), TokenKind::Plus => Token::Plus.fmt(f), TokenKind::PlusEqual => Token::PlusEqual.fmt(f), @@ -518,7 +526,7 @@ impl Display for TokenKind { pub(crate) mod tests { use super::*; - pub fn all_tokens<'src>() -> [Token<'src>; 47] { + pub fn all_tokens<'src>() -> [Token<'src>; 48] { [ Token::Async, Token::Bang, @@ -552,6 +560,7 @@ pub(crate) mod tests { Token::LessEqual, Token::Minus, Token::MinusEqual, + Token::Mut, Token::Percent, Token::Plus, Token::PlusEqual, diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index a7c503f..b263301 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -91,6 +91,10 @@ impl Value { Value::Immutable(Arc::new(ValueData::Struct(r#struct))) } + pub fn boolean_mut(boolean: bool) -> Self { + Value::Mutable(Arc::new(RwLock::new(ValueData::Boolean(boolean)))) + } + pub fn r#type(&self) -> Type { match self { Value::Immutable(inner) => inner.r#type(), @@ -1421,6 +1425,7 @@ pub enum ValueError { CannotLessThanOrEqual(Value, Value), CannotModulo(Value, Value), CannotMultiply(Value, Value), + CannotMutate(Value), CannotSubtract(Value, Value), CannotOr(Value, Value), DivisionByZero, @@ -1448,6 +1453,7 @@ impl Display for ValueError { ValueError::CannotMultiply(left, right) => { write!(f, "Cannot multiply {} and {}", left, right) } + ValueError::CannotMutate(value) => write!(f, "Cannot mutate {}", value), ValueError::CannotSubtract(left, right) => { write!(f, "Cannot subtract {} and {}", left, right) }