From 544edaf5f4095def0d0dceb0386aca14b6d4947b Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 3 Dec 2024 14:12:40 -0500 Subject: [PATCH] Add new "add" tests; Allow adding strings to characters and visa versa --- dust-lang/src/compiler.rs | 29 ++++++----- dust-lang/src/value/concrete_value.rs | 2 + dust-lang/tests/add.rs | 73 +++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 13 deletions(-) diff --git a/dust-lang/src/compiler.rs b/dust-lang/src/compiler.rs index f1ee144..67a7434 100644 --- a/dust-lang/src/compiler.rs +++ b/dust-lang/src/compiler.rs @@ -629,20 +629,16 @@ impl<'src> Compiler<'src> { }; let operator = self.current_token; let operator_position = self.current_position; - - Compiler::expect_addable_type(&left_type, &left_position)?; - let rule = ParseRule::from(&operator); let is_assignment = matches!( operator, Token::PlusEqual | Token::MinusEqual | Token::StarEqual | Token::SlashEqual ); - let r#type = if is_assignment { - Type::None - } else { - left_type.clone() - }; + if push_back_left { + self.instructions + .push((left_instruction, left_type.clone(), left_position)); + } if is_assignment && !left_is_mutable_local { return Err(CompileError::ExpectedMutableVariable { @@ -651,10 +647,15 @@ impl<'src> Compiler<'src> { }); } - if push_back_left { - self.instructions - .push((left_instruction, left_type.clone(), left_position)); - } + Compiler::expect_addable_type(&left_type, &left_position)?; + + let r#type = if is_assignment { + Type::None + } else if left_type == Type::Character { + Type::String + } else { + left_type.clone() + }; self.advance()?; self.parse_sub_expression(&rule.precedence)?; @@ -1628,9 +1629,11 @@ impl<'src> Compiler<'src> { ) -> Result<(), CompileError> { if matches!( (left, right), - (Type::Character, Type::Character) + (Type::Character, Type::String) + | (Type::Character, Type::Character) | (Type::Float, Type::Float) | (Type::Integer, Type::Integer) + | (Type::String, Type::Character) | (Type::String, Type::String), ) { Ok(()) diff --git a/dust-lang/src/value/concrete_value.rs b/dust-lang/src/value/concrete_value.rs index e87646e..88dc768 100644 --- a/dust-lang/src/value/concrete_value.rs +++ b/dust-lang/src/value/concrete_value.rs @@ -70,9 +70,11 @@ impl ConcreteValue { (Character(left), Character(right)) => { ConcreteValue::string(format!("{}{}", left, right)) } + (Character(left), String(right)) => ConcreteValue::string(format!("{}{}", left, right)), (Float(left), Float(right)) => ConcreteValue::Float(*left + *right), (Integer(left), Integer(right)) => ConcreteValue::Integer(left.saturating_add(*right)), (String(left), String(right)) => ConcreteValue::string(format!("{}{}", left, right)), + (String(left), Character(right)) => ConcreteValue::string(format!("{}{}", left, right)), _ => { return Err(ValueError::CannotAdd( self.clone().to_value(), diff --git a/dust-lang/tests/add.rs b/dust-lang/tests/add.rs index 323711c..be167fd 100644 --- a/dust-lang/tests/add.rs +++ b/dust-lang/tests/add.rs @@ -32,6 +32,41 @@ fn add_characters() { assert_eq!(run(source), Ok(Some(ConcreteValue::string("ab")))); } +#[test] +fn add_character_and_string() { + let source = "'a' + \"b\""; + + assert_eq!( + compile(source), + Ok(Chunk::with_data( + None, + FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::String), + }, + vec![ + ( + Instruction::add( + Destination::Register(0), + Argument::Constant(0), + Argument::Constant(1) + ), + Span(4, 5) + ), + (Instruction::r#return(true), Span(9, 9)) + ], + vec![ + ConcreteValue::Character('a'), + ConcreteValue::String("b".to_string()) + ], + vec![] + )) + ); + + assert_eq!(run(source), Ok(Some(ConcreteValue::string("ab")))); +} + #[test] fn add_floats() { let source = "1.0 + 2.0"; @@ -128,3 +163,41 @@ fn add_strings() { )) ); } + +#[test] +fn add_string_and_character() { + let source = "\"a\" + 'b'"; + + assert_eq!( + compile(source), + Ok(Chunk::with_data( + None, + FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::String), + }, + vec![ + ( + Instruction::add( + Destination::Register(0), + Argument::Constant(0), + Argument::Constant(1) + ), + Span(4, 5) + ), + (Instruction::r#return(true), Span(9, 9)) + ], + vec![ + ConcreteValue::String("a".to_string()), + ConcreteValue::Character('b') + ], + vec![] + )) + ); + + assert_eq!( + run(source), + Ok(Some(ConcreteValue::String("ab".to_string()))) + ); +}