diff --git a/dust-lang/src/compiler.rs b/dust-lang/src/compiler.rs index e577672..f1ee144 100644 --- a/dust-lang/src/compiler.rs +++ b/dust-lang/src/compiler.rs @@ -1628,8 +1628,9 @@ impl<'src> Compiler<'src> { ) -> Result<(), CompileError> { if matches!( (left, right), - (Type::Integer, Type::Integer) + (Type::Character, Type::Character) | (Type::Float, Type::Float) + | (Type::Integer, Type::Integer) | (Type::String, Type::String), ) { Ok(()) diff --git a/dust-lang/src/value/concrete_value.rs b/dust-lang/src/value/concrete_value.rs index 994de90..e87646e 100644 --- a/dust-lang/src/value/concrete_value.rs +++ b/dust-lang/src/value/concrete_value.rs @@ -67,6 +67,9 @@ impl ConcreteValue { let sum = match (self, other) { (Byte(left), Byte(right)) => ConcreteValue::Byte(left.saturating_add(*right)), + (Character(left), Character(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)), diff --git a/dust-lang/tests/add.rs b/dust-lang/tests/add.rs new file mode 100644 index 0000000..323711c --- /dev/null +++ b/dust-lang/tests/add.rs @@ -0,0 +1,130 @@ +use dust_lang::*; + +#[test] +fn add_characters() { + 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::Character('b')], + vec![] + )) + ); + + assert_eq!(run(source), Ok(Some(ConcreteValue::string("ab")))); +} + +#[test] +fn add_floats() { + let source = "1.0 + 2.0"; + + assert_eq!( + compile(source), + Ok(Chunk::with_data( + None, + FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::Float), + }, + vec![ + ( + Instruction::add( + Destination::Register(0), + Argument::Constant(0), + Argument::Constant(1) + ), + Span(4, 5) + ), + (Instruction::r#return(true), Span(9, 9)) + ], + vec![ConcreteValue::Float(1.0), ConcreteValue::Float(2.0)], + vec![] + )) + ); + + assert_eq!(run(source), Ok(Some(ConcreteValue::Float(3.0)))); +} + +#[test] +fn add_integers() { + let source = "1 + 2"; + + assert_eq!( + compile(source), + Ok(Chunk::with_data( + None, + FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::Integer), + }, + vec![ + ( + Instruction::add( + Destination::Register(0), + Argument::Constant(0), + Argument::Constant(1) + ), + Span(2, 3) + ), + (Instruction::r#return(true), Span(5, 5)) + ], + vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)], + vec![] + )) + ); + + assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(3)))); +} + +#[test] +fn add_strings() { + let source = "\"Hello, \" + \"world!\""; + + 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(10, 11) + ), + (Instruction::r#return(true), Span(20, 20)) + ], + vec![ + ConcreteValue::String("Hello, ".to_string()), + ConcreteValue::String("world!".to_string()) + ], + vec![] + )) + ); +} diff --git a/dust-lang/tests/add_assign.rs b/dust-lang/tests/add_assign.rs new file mode 100644 index 0000000..8b7c834 --- /dev/null +++ b/dust-lang/tests/add_assign.rs @@ -0,0 +1,46 @@ +use dust_lang::*; + +#[test] +fn add_assign() { + let source = "let mut a = 1; a += 2; a"; + + assert_eq!( + compile(source), + Ok(Chunk::with_data( + None, + FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::Integer), + }, + vec![ + ( + Instruction::load_constant(Destination::Register(0), 0, false), + Span(12, 13) + ), + (Instruction::define_local(0, 0, true), Span(8, 9)), + ( + Instruction::add( + Destination::Local(0), + Argument::Local(0), + Argument::Constant(2) + ), + Span(17, 19) + ), + ( + Instruction::get_local(Destination::Register(1), 0), + Span(23, 24) + ), + (Instruction::r#return(true), Span(24, 24)) + ], + vec![ + ConcreteValue::Integer(1), + ConcreteValue::string("a"), + ConcreteValue::Integer(2) + ], + vec![Local::new(1, Type::Integer, true, Scope::default())] + )) + ); + + assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(3)))); +} diff --git a/dust-lang/tests/add_type_errors.rs b/dust-lang/tests/add_type_errors.rs new file mode 100644 index 0000000..f8c2ef4 --- /dev/null +++ b/dust-lang/tests/add_type_errors.rs @@ -0,0 +1,302 @@ +use dust_lang::*; + +#[test] +fn add_boolean_left() { + let source = "true + 1"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddType { + argument_type: Type::Boolean, + position: Span(0, 4) + }, + source, + }) + ); +} + +#[test] +fn add_boolean_right() { + let source = "1 + true"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddType { + argument_type: Type::Boolean, + position: Span(4, 8) + }, + source, + }) + ); +} + +#[test] +fn add_function_left() { + let source = "fn(){} + 1"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddType { + argument_type: Type::Function(FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::None) + }), + position: Span(0, 6) + }, + source, + }) + ); +} + +#[test] +fn add_function_right() { + let source = "1 + fn(){}"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddType { + argument_type: Type::Function(FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::None) + }), + position: Span(4, 10) + }, + source, + }) + ); +} + +#[test] +fn add_list_left() { + let source = "[1, 2] + 1"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddType { + argument_type: Type::List(Box::new(Type::Integer)), + position: Span(0, 6) + }, + source, + }) + ); +} + +#[test] +fn add_list_right() { + let source = "1 + [1, 2]"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddType { + argument_type: Type::List(Box::new(Type::Integer)), + position: Span(4, 10) + }, + source, + }) + ); +} + +// #[test] +// fn add_range_left() { +// todo!("Add ranges") +// } + +// #[test] +// fn add_range_right() { +// todo!("Add ranges") +// } + +#[test] +fn add_float_and_character() { + let source = "1.0 + 'a'"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddArguments { + left_type: Type::Float, + right_type: Type::Character, + position: Span(0, 9) + }, + source, + }) + ); +} + +#[test] +fn add_float_and_integer() { + let source = "1.0 + 1"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddArguments { + left_type: Type::Float, + right_type: Type::Integer, + position: Span(0, 7) + }, + source, + }) + ); +} + +#[test] +fn add_float_and_string() { + let source = "1.0 + \"hello\""; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddArguments { + left_type: Type::Float, + right_type: Type::String, + position: Span(0, 13) + }, + source, + }) + ); +} + +#[test] +fn add_integer_and_character() { + let source = "1 + 'a'"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddArguments { + left_type: Type::Integer, + right_type: Type::Character, + position: Span(0, 7) + }, + source, + }) + ); +} + +#[test] +fn add_integer_and_float() { + let source = "1 + 1.0"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddArguments { + left_type: Type::Integer, + right_type: Type::Float, + position: Span(0, 7) + }, + source, + }) + ); +} + +#[test] +fn add_integer_and_string() { + let source = "1 + \"hello\""; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddArguments { + left_type: Type::Integer, + right_type: Type::String, + position: Span(0, 11) + }, + source, + }) + ); +} + +#[test] +fn add_string_and_character() { + let source = "\"hello\" + 'a'"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddArguments { + left_type: Type::String, + right_type: Type::Character, + position: Span(0, 13) + }, + source, + }) + ); +} + +#[test] +fn add_string_and_float() { + let source = "\"hello\" + 1.0"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddArguments { + left_type: Type::String, + right_type: Type::Float, + position: Span(0, 13) + }, + source, + }) + ); +} + +#[test] +fn add_string_and_integer() { + let source = "\"hello\" + 1"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddArguments { + left_type: Type::String, + right_type: Type::Integer, + position: Span(0, 11) + }, + source, + }) + ); +} + +#[test] +fn add_character_and_float() { + let source = "'a' + 1.0"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddArguments { + left_type: Type::Character, + right_type: Type::Float, + position: Span(0, 9) + }, + source, + }) + ); +} + +#[test] +fn add_character_and_integer() { + let source = "'a' + 1"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotAddArguments { + left_type: Type::Character, + right_type: Type::Integer, + position: Span(0, 7) + }, + source, + }) + ); +} diff --git a/dust-lang/tests/assignment_errors.rs b/dust-lang/tests/assignment_errors.rs new file mode 100644 index 0000000..a117612 --- /dev/null +++ b/dust-lang/tests/assignment_errors.rs @@ -0,0 +1,81 @@ +use dust_lang::*; + +#[test] +fn add_assign_expects_mutable_variable() { + let source = "1 += 2"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::ExpectedMutableVariable { + found: Token::Integer("1").to_owned(), + position: Span(0, 1) + }, + source + }) + ); +} + +#[test] +fn divide_assign_expects_mutable_variable() { + let source = "1 -= 2"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::ExpectedMutableVariable { + found: Token::Integer("1").to_owned(), + position: Span(0, 1) + }, + source + }) + ); +} + +#[test] +fn multiply_assign_expects_mutable_variable() { + let source = "1 *= 2"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::ExpectedMutableVariable { + found: Token::Integer("1").to_owned(), + position: Span(0, 1) + }, + source + }) + ); +} + +#[test] +fn subtract_assign_expects_mutable_variable() { + let source = "1 -= 2"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::ExpectedMutableVariable { + found: Token::Integer("1").to_owned(), + position: Span(0, 1) + }, + source + }) + ); +} + +#[test] +fn modulo_assign_expects_mutable_variable() { + let source = "1 %= 2"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::ExpectedMutableVariable { + found: Token::Integer("1").to_owned(), + position: Span(0, 1) + }, + source + }) + ); +} diff --git a/dust-lang/tests/basic.rs b/dust-lang/tests/basic.rs index c6378bb..f89d43c 100644 --- a/dust-lang/tests/basic.rs +++ b/dust-lang/tests/basic.rs @@ -92,3 +92,65 @@ fn parentheses_precedence() { assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(9)))); } + +#[test] +fn math_operator_precedence() { + let source = "1 + 2 - 3 * 4 / 5"; + + assert_eq!( + compile(source), + Ok(Chunk::with_data( + None, + FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::Integer), + }, + vec![ + ( + Instruction::add( + Destination::Register(0), + Argument::Constant(0), + Argument::Constant(1) + ), + Span(2, 3) + ), + ( + Instruction::multiply( + Destination::Register(1), + Argument::Constant(2), + Argument::Constant(3) + ), + Span(10, 11) + ), + ( + Instruction::divide( + Destination::Register(2), + Argument::Register(1), + Argument::Constant(4) + ), + Span(14, 15) + ), + ( + Instruction::subtract( + Destination::Register(3), + Argument::Register(0), + Argument::Register(2) + ), + Span(6, 7) + ), + (Instruction::r#return(true), Span(17, 17)), + ], + vec![ + ConcreteValue::Integer(1), + ConcreteValue::Integer(2), + ConcreteValue::Integer(3), + ConcreteValue::Integer(4), + ConcreteValue::Integer(5), + ], + vec![] + )) + ); + + assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(1)))); +} diff --git a/dust-lang/tests/divide.rs b/dust-lang/tests/divide.rs new file mode 100644 index 0000000..428d2a0 --- /dev/null +++ b/dust-lang/tests/divide.rs @@ -0,0 +1,33 @@ +use dust_lang::*; + +#[test] +fn divide() { + let source = "2 / 2"; + + assert_eq!( + compile(source), + Ok(Chunk::with_data( + None, + FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::Integer), + }, + vec![ + ( + Instruction::divide( + Destination::Register(0), + Argument::Constant(0), + Argument::Constant(0) + ), + Span(2, 3) + ), + (Instruction::r#return(true), Span(5, 5)) + ], + vec![ConcreteValue::Integer(2)], + vec![] + )) + ); + + assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(1)))); +} diff --git a/dust-lang/tests/divide_assign.rs b/dust-lang/tests/divide_assign.rs new file mode 100644 index 0000000..9f9dcc6 --- /dev/null +++ b/dust-lang/tests/divide_assign.rs @@ -0,0 +1,42 @@ +use dust_lang::*; + +#[test] +fn divide_assign() { + let source = "let mut a = 2; a /= 2; a"; + + assert_eq!( + compile(source), + Ok(Chunk::with_data( + None, + FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::Integer), + }, + vec![ + ( + Instruction::load_constant(Destination::Register(0), 0, false), + Span(12, 13) + ), + (Instruction::define_local(0, 0, true), Span(8, 9)), + ( + Instruction::divide( + Destination::Local(0), + Argument::Local(0), + Argument::Constant(0) + ), + Span(17, 19) + ), + ( + Instruction::get_local(Destination::Register(1), 0), + Span(23, 24) + ), + (Instruction::r#return(true), Span(24, 24)) + ], + vec![ConcreteValue::Integer(2), ConcreteValue::string("a")], + vec![Local::new(1, Type::Integer, true, Scope::default())] + )) + ); + + assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(1)))); +} diff --git a/dust-lang/tests/math.rs b/dust-lang/tests/math.rs deleted file mode 100644 index 34b8256..0000000 --- a/dust-lang/tests/math.rs +++ /dev/null @@ -1,447 +0,0 @@ -use dust_lang::*; - -#[test] -fn add() { - let source = "1 + 2"; - - assert_eq!( - compile(source), - Ok(Chunk::with_data( - None, - FunctionType { - type_parameters: None, - value_parameters: None, - return_type: Box::new(Type::Integer), - }, - vec![ - ( - Instruction::add( - Destination::Register(0), - Argument::Constant(0), - Argument::Constant(1) - ), - Span(2, 3) - ), - (Instruction::r#return(true), Span(5, 5)) - ], - vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)], - vec![] - )) - ); - - assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(3)))); -} - -#[test] -fn add_assign() { - let source = "let mut a = 1; a += 2; a"; - - assert_eq!( - compile(source), - Ok(Chunk::with_data( - None, - FunctionType { - type_parameters: None, - value_parameters: None, - return_type: Box::new(Type::Integer), - }, - vec![ - ( - Instruction::load_constant(Destination::Register(0), 0, false), - Span(12, 13) - ), - (Instruction::define_local(0, 0, true), Span(8, 9)), - ( - Instruction::add( - Destination::Local(0), - Argument::Local(0), - Argument::Constant(2) - ), - Span(17, 19) - ), - ( - Instruction::get_local(Destination::Register(1), 0), - Span(23, 24) - ), - (Instruction::r#return(true), Span(24, 24)) - ], - vec![ - ConcreteValue::Integer(1), - ConcreteValue::string("a"), - ConcreteValue::Integer(2) - ], - vec![Local::new(1, Type::Integer, true, Scope::default())] - )) - ); - - assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(3)))); -} - -#[test] -fn add_assign_expects_mutable_variable() { - let source = "1 += 2"; - - assert_eq!( - compile(source), - Err(DustError::Compile { - error: CompileError::ExpectedMutableVariable { - found: Token::Integer("1").to_owned(), - position: Span(0, 1) - }, - source - }) - ); -} - -// #[test] -// fn add_expects_integer_float_or_string() { -// let source = "true + false"; - -// assert_eq!( -// parse(source), -// Err(DustError::Parse { -// error: ParseError::ExpectedIntegerFloatOrString { -// found: Token::True, -// position: Span(0, 3) -// }, -// source -// }) -// ); -// } - -#[test] -fn divide() { - let source = "2 / 2"; - - assert_eq!( - compile(source), - Ok(Chunk::with_data( - None, - FunctionType { - type_parameters: None, - value_parameters: None, - return_type: Box::new(Type::Integer), - }, - vec![ - ( - Instruction::divide( - Destination::Register(0), - Argument::Constant(0), - Argument::Constant(0) - ), - Span(2, 3) - ), - (Instruction::r#return(true), Span(5, 5)) - ], - vec![ConcreteValue::Integer(2)], - vec![] - )) - ); - - assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(1)))); -} - -#[test] -fn divide_assign() { - let source = "let mut a = 2; a /= 2; a"; - - assert_eq!( - compile(source), - Ok(Chunk::with_data( - None, - FunctionType { - type_parameters: None, - value_parameters: None, - return_type: Box::new(Type::Integer), - }, - vec![ - ( - Instruction::load_constant(Destination::Register(0), 0, false), - Span(12, 13) - ), - (Instruction::define_local(0, 0, true), Span(8, 9)), - ( - Instruction::divide( - Destination::Local(0), - Argument::Local(0), - Argument::Constant(0) - ), - Span(17, 19) - ), - ( - Instruction::get_local(Destination::Register(1), 0), - Span(23, 24) - ), - (Instruction::r#return(true), Span(24, 24)) - ], - vec![ConcreteValue::Integer(2), ConcreteValue::string("a")], - vec![Local::new(1, Type::Integer, true, Scope::default())] - )) - ); - - assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(1)))); -} - -#[test] -fn divide_assign_expects_mutable_variable() { - let source = "1 -= 2"; - - assert_eq!( - compile(source), - Err(DustError::Compile { - error: CompileError::ExpectedMutableVariable { - found: Token::Integer("1").to_owned(), - position: Span(0, 1) - }, - source - }) - ); -} - -#[test] -fn math_operator_precedence() { - let source = "1 + 2 - 3 * 4 / 5"; - - assert_eq!( - compile(source), - Ok(Chunk::with_data( - None, - FunctionType { - type_parameters: None, - value_parameters: None, - return_type: Box::new(Type::Integer), - }, - vec![ - ( - Instruction::add( - Destination::Register(0), - Argument::Constant(0), - Argument::Constant(1) - ), - Span(2, 3) - ), - ( - Instruction::multiply( - Destination::Register(1), - Argument::Constant(2), - Argument::Constant(3) - ), - Span(10, 11) - ), - ( - Instruction::divide( - Destination::Register(2), - Argument::Register(1), - Argument::Constant(4) - ), - Span(14, 15) - ), - ( - Instruction::subtract( - Destination::Register(3), - Argument::Register(0), - Argument::Register(2) - ), - Span(6, 7) - ), - (Instruction::r#return(true), Span(17, 17)), - ], - vec![ - ConcreteValue::Integer(1), - ConcreteValue::Integer(2), - ConcreteValue::Integer(3), - ConcreteValue::Integer(4), - ConcreteValue::Integer(5), - ], - vec![] - )) - ); - - assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(1)))); -} - -#[test] -fn multiply() { - let source = "1 * 2"; - - assert_eq!( - compile(source), - Ok(Chunk::with_data( - None, - FunctionType { - type_parameters: None, - value_parameters: None, - return_type: Box::new(Type::Integer), - }, - vec![ - ( - Instruction::multiply( - Destination::Register(0), - Argument::Constant(0), - Argument::Constant(1) - ), - Span(2, 3) - ), - (Instruction::r#return(true), Span(5, 5)), - ], - vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)], - vec![] - )) - ); - - assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(2)))); -} - -#[test] -fn multiply_assign() { - let source = "let mut a = 2; a *= 3 a"; - - assert_eq!( - compile(source), - Ok(Chunk::with_data( - None, - FunctionType { - type_parameters: None, - value_parameters: None, - return_type: Box::new(Type::Integer), - }, - vec![ - ( - Instruction::load_constant(Destination::Register(0), 0, false), - Span(12, 13) - ), - (Instruction::define_local(0, 0, true), Span(8, 9)), - ( - Instruction::multiply( - Destination::Local(0), - Argument::Local(0), - Argument::Constant(2) - ), - Span(17, 19) - ), - ( - Instruction::get_local(Destination::Register(1), 0), - Span(22, 23) - ), - (Instruction::r#return(true), Span(23, 23)) - ], - vec![ - ConcreteValue::Integer(2), - ConcreteValue::string("a"), - ConcreteValue::Integer(3) - ], - vec![Local::new(1, Type::Integer, true, Scope::default())] - )) - ); - - assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(6)))); -} - -#[test] -fn multiply_assign_expects_mutable_variable() { - let source = "1 *= 2"; - - assert_eq!( - compile(source), - Err(DustError::Compile { - error: CompileError::ExpectedMutableVariable { - found: Token::Integer("1").to_owned(), - position: Span(0, 1) - }, - source - }) - ); -} - -#[test] -fn subtract() { - let source = "1 - 2"; - - assert_eq!( - compile(source), - Ok(Chunk::with_data( - None, - FunctionType { - type_parameters: None, - value_parameters: None, - return_type: Box::new(Type::Integer), - }, - vec![ - ( - Instruction::subtract( - Destination::Register(0), - Argument::Constant(0), - Argument::Constant(1) - ), - Span(2, 3) - ), - (Instruction::r#return(true), Span(5, 5)), - ], - vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)], - vec![] - )) - ); - - assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(-1)))); -} - -#[test] -fn subtract_assign() { - let source = "let mut x = 42; x -= 2; x"; - - assert_eq!( - compile(source), - Ok(Chunk::with_data( - None, - FunctionType { - type_parameters: None, - value_parameters: None, - return_type: Box::new(Type::Integer), - }, - vec![ - ( - Instruction::load_constant(Destination::Register(0), 0, false), - Span(12, 14) - ), - (Instruction::define_local(0, 0, true), Span(8, 9)), - ( - Instruction::subtract( - Destination::Local(0), - Argument::Local(0), - Argument::Constant(2) - ), - Span(18, 20) - ), - ( - Instruction::get_local(Destination::Register(1), 0), - Span(24, 25) - ), - (Instruction::r#return(true), Span(25, 25)), - ], - vec![ - ConcreteValue::Integer(42), - ConcreteValue::string("x"), - ConcreteValue::Integer(2) - ], - vec![Local::new(1, Type::Integer, true, Scope::default())] - )), - ); - - assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(40)))); -} - -#[test] -fn subtract_assign_expects_mutable_variable() { - let source = "1 -= 2"; - - assert_eq!( - compile(source), - Err(DustError::Compile { - error: CompileError::ExpectedMutableVariable { - found: Token::Integer("1").to_owned(), - position: Span(0, 1) - }, - source - }) - ); -} diff --git a/dust-lang/tests/modulo.rs b/dust-lang/tests/modulo.rs new file mode 100644 index 0000000..e69de29 diff --git a/dust-lang/tests/modulo_assign.rs b/dust-lang/tests/modulo_assign.rs new file mode 100644 index 0000000..e69de29 diff --git a/dust-lang/tests/multiply.rs b/dust-lang/tests/multiply.rs new file mode 100644 index 0000000..20c90bb --- /dev/null +++ b/dust-lang/tests/multiply.rs @@ -0,0 +1,33 @@ +use dust_lang::*; + +#[test] +fn multiply() { + let source = "1 * 2"; + + assert_eq!( + compile(source), + Ok(Chunk::with_data( + None, + FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::Integer), + }, + vec![ + ( + Instruction::multiply( + Destination::Register(0), + Argument::Constant(0), + Argument::Constant(1) + ), + Span(2, 3) + ), + (Instruction::r#return(true), Span(5, 5)), + ], + vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)], + vec![] + )) + ); + + assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(2)))); +} diff --git a/dust-lang/tests/multiply_assign.rs b/dust-lang/tests/multiply_assign.rs new file mode 100644 index 0000000..0ae299a --- /dev/null +++ b/dust-lang/tests/multiply_assign.rs @@ -0,0 +1,46 @@ +use dust_lang::*; + +#[test] +fn multiply_assign() { + let source = "let mut a = 2; a *= 3 a"; + + assert_eq!( + compile(source), + Ok(Chunk::with_data( + None, + FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::Integer), + }, + vec![ + ( + Instruction::load_constant(Destination::Register(0), 0, false), + Span(12, 13) + ), + (Instruction::define_local(0, 0, true), Span(8, 9)), + ( + Instruction::multiply( + Destination::Local(0), + Argument::Local(0), + Argument::Constant(2) + ), + Span(17, 19) + ), + ( + Instruction::get_local(Destination::Register(1), 0), + Span(22, 23) + ), + (Instruction::r#return(true), Span(23, 23)) + ], + vec![ + ConcreteValue::Integer(2), + ConcreteValue::string("a"), + ConcreteValue::Integer(3) + ], + vec![Local::new(1, Type::Integer, true, Scope::default())] + )) + ); + + assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(6)))); +} diff --git a/dust-lang/tests/subtract.rs b/dust-lang/tests/subtract.rs new file mode 100644 index 0000000..a2699eb --- /dev/null +++ b/dust-lang/tests/subtract.rs @@ -0,0 +1,33 @@ +use dust_lang::*; + +#[test] +fn subtract() { + let source = "1 - 2"; + + assert_eq!( + compile(source), + Ok(Chunk::with_data( + None, + FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::Integer), + }, + vec![ + ( + Instruction::subtract( + Destination::Register(0), + Argument::Constant(0), + Argument::Constant(1) + ), + Span(2, 3) + ), + (Instruction::r#return(true), Span(5, 5)), + ], + vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)], + vec![] + )) + ); + + assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(-1)))); +} diff --git a/dust-lang/tests/subtract_assign.rs b/dust-lang/tests/subtract_assign.rs new file mode 100644 index 0000000..c796fdf --- /dev/null +++ b/dust-lang/tests/subtract_assign.rs @@ -0,0 +1,46 @@ +use dust_lang::*; + +#[test] +fn subtract_assign() { + let source = "let mut x = 42; x -= 2; x"; + + assert_eq!( + compile(source), + Ok(Chunk::with_data( + None, + FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::Integer), + }, + vec![ + ( + Instruction::load_constant(Destination::Register(0), 0, false), + Span(12, 14) + ), + (Instruction::define_local(0, 0, true), Span(8, 9)), + ( + Instruction::subtract( + Destination::Local(0), + Argument::Local(0), + Argument::Constant(2) + ), + Span(18, 20) + ), + ( + Instruction::get_local(Destination::Register(1), 0), + Span(24, 25) + ), + (Instruction::r#return(true), Span(25, 25)), + ], + vec![ + ConcreteValue::Integer(42), + ConcreteValue::string("x"), + ConcreteValue::Integer(2) + ], + vec![Local::new(1, Type::Integer, true, Scope::default())] + )), + ); + + assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(40)))); +} diff --git a/dust-lang/tests/type_errors_add.rs b/dust-lang/tests/type_errors_add.rs deleted file mode 100644 index a140e95..0000000 --- a/dust-lang/tests/type_errors_add.rs +++ /dev/null @@ -1,160 +0,0 @@ -use dust_lang::*; - -#[test] -fn add_boolean_left() { - let source = "true + 1"; - - assert_eq!( - compile(source), - Err(DustError::Compile { - error: CompileError::CannotAddType { - argument_type: Type::Boolean, - position: Span(0, 4) - }, - source, - }) - ); -} - -#[test] -fn add_boolean_right() { - let source = "1 + true"; - - assert_eq!( - compile(source), - Err(DustError::Compile { - error: CompileError::CannotAddType { - argument_type: Type::Boolean, - position: Span(4, 8) - }, - source, - }) - ); -} - -#[test] -fn add_function_left() { - let source = "fn(){} + 1"; - - assert_eq!( - compile(source), - Err(DustError::Compile { - error: CompileError::CannotAddType { - argument_type: Type::Function(FunctionType { - type_parameters: None, - value_parameters: None, - return_type: Box::new(Type::None) - }), - position: Span(0, 6) - }, - source, - }) - ); -} - -#[test] -fn add_function_right() { - let source = "1 + fn(){}"; - - assert_eq!( - compile(source), - Err(DustError::Compile { - error: CompileError::CannotAddType { - argument_type: Type::Function(FunctionType { - type_parameters: None, - value_parameters: None, - return_type: Box::new(Type::None) - }), - position: Span(4, 10) - }, - source, - }) - ); -} - -#[test] -fn add_list_left() { - let source = "[1, 2] + 1"; - - assert_eq!( - compile(source), - Err(DustError::Compile { - error: CompileError::CannotAddType { - argument_type: Type::List(Box::new(Type::Integer)), - position: Span(0, 6) - }, - source, - }) - ); -} - -#[test] -fn add_list_right() { - let source = "1 + [1, 2]"; - - assert_eq!( - compile(source), - Err(DustError::Compile { - error: CompileError::CannotAddType { - argument_type: Type::List(Box::new(Type::Integer)), - position: Span(4, 10) - }, - source, - }) - ); -} - -// #[test] -// fn add_range_left() { -// todo!("Add ranges") -// } - -// #[test] -// fn add_range_right() { -// todo!("Add ranges") -// } - -#[test] -fn add_character_and_float() { - let source = "'a' + 1.0"; -} - -#[test] -fn add_character_and_integer() { - todo!() -} - -#[test] -fn add_character_and_string() { - todo!() -} - -#[test] -fn add_float_and_character() { - todo!() -} - -#[test] -fn add_float_and_integer() { - todo!() -} - -#[test] -fn add_float_and_string() { - todo!() -} - -#[test] -fn add_integer_and_character() { - todo!() -} - -#[test] -fn add_integer_and_float() { - todo!() -} - -#[test] -fn add_integer_and_string() { - todo!() -}