diff --git a/dust-lang/src/compiler.rs b/dust-lang/src/compiler.rs index 01271ac..36aacfc 100644 --- a/dust-lang/src/compiler.rs +++ b/dust-lang/src/compiler.rs @@ -651,9 +651,18 @@ impl<'src> Compiler<'src> { Token::Plus | Token::PlusEqual => { Compiler::expect_addable_type(&left_type, &left_position)? } + Token::Minus | Token::MinusEqual => { + Compiler::expect_subtractable_type(&left_type, &left_position)? + } Token::Slash | Token::SlashEqual => { Compiler::expect_dividable_type(&left_type, &left_position)? } + Token::Star | Token::StarEqual => { + Compiler::expect_multipliable_type(&left_type, &left_position)? + } + Token::Percent | Token::PercentEqual => { + Compiler::expect_modulable_type(&left_type, &left_position)? + } _ => {} } @@ -699,6 +708,15 @@ impl<'src> Compiler<'src> { &right_position, )?; } + Token::Star | Token::StarEqual => { + Compiler::expect_multipliable_type(&right_type, &right_position)?; + Compiler::expect_multipliable_types( + &left_type, + &left_position, + &right_type, + &right_position, + )?; + } Token::Percent | Token::PercentEqual => { Compiler::expect_modulable_type(&right_type, &right_position)?; Compiler::expect_modulable_types( @@ -1754,10 +1772,7 @@ impl<'src> Compiler<'src> { } } - fn expect_multiplicable_type( - argument_type: &Type, - position: &Span, - ) -> Result<(), CompileError> { + fn expect_multipliable_type(argument_type: &Type, position: &Span) -> Result<(), CompileError> { if matches!(argument_type, Type::Byte | Type::Float | Type::Integer) { Ok(()) } else { @@ -1768,7 +1783,7 @@ impl<'src> Compiler<'src> { } } - fn expect_multiplicable_types( + fn expect_multipliable_types( left: &Type, left_position: &Span, right: &Type, @@ -1787,6 +1802,37 @@ impl<'src> Compiler<'src> { }) } } + + fn expect_subtractable_type(argument_type: &Type, position: &Span) -> Result<(), CompileError> { + if matches!(argument_type, Type::Byte | Type::Float | Type::Integer) { + Ok(()) + } else { + Err(CompileError::CannotSubtractType { + argument_type: argument_type.clone(), + position: *position, + }) + } + } + + fn expect_subtractable_types( + left: &Type, + left_position: &Span, + right: &Type, + right_position: &Span, + ) -> Result<(), CompileError> { + if matches!( + (left, right), + (Type::Byte, Type::Byte) | (Type::Float, Type::Float) | (Type::Integer, Type::Integer) + ) { + Ok(()) + } else { + Err(CompileError::CannotSubtractArguments { + left_type: left.clone(), + right_type: right.clone(), + position: Span(left_position.0, right_position.1), + }) + } + } } /// Operator precedence levels. @@ -2205,11 +2251,11 @@ pub enum CompileError { right_type: Type, position: Span, }, - CannotSubtractLeft { + CannotSubtractType { argument_type: Type, position: Span, }, - CannotSubtract { + CannotSubtractArguments { left_type: Type, right_type: Type, position: Span, @@ -2283,8 +2329,8 @@ impl AnnotatedError for CompileError { Self::CannotMultiplyType { .. } => "Cannot multiply this type", Self::CannotResolveRegisterType { .. } => "Cannot resolve register type", Self::CannotResolveVariableType { .. } => "Cannot resolve type", - Self::CannotSubtract { .. } => "Cannot subtract these types", - Self::CannotSubtractLeft { .. } => "Cannot subtract from this type", + Self::CannotSubtractType { .. } => "Cannot subtract from this type", + Self::CannotSubtractArguments { .. } => "Cannot subtract these types", Self::ConstantIndexOutOfBounds { .. } => "Constant index out of bounds", Self::ExpectedExpression { .. } => "Expected an expression", Self::ExpectedFunction { .. } => "Expected a function", @@ -2392,8 +2438,8 @@ impl AnnotatedError for CompileError { Self::CannotMultiplyType { position, .. } => *position, Self::CannotResolveRegisterType { position, .. } => *position, Self::CannotResolveVariableType { position, .. } => *position, - Self::CannotSubtract { position, .. } => *position, - Self::CannotSubtractLeft { position, .. } => *position, + Self::CannotSubtractArguments { position, .. } => *position, + Self::CannotSubtractType { position, .. } => *position, Self::ConstantIndexOutOfBounds { position, .. } => *position, Self::ExpectedExpression { position, .. } => *position, Self::ExpectedFunction { position, .. } => *position, diff --git a/dust-lang/tests/math_modulo_errors.rs b/dust-lang/tests/math_modulo_errors.rs new file mode 100644 index 0000000..d50daf5 --- /dev/null +++ b/dust-lang/tests/math_modulo_errors.rs @@ -0,0 +1,229 @@ +use dust_lang::*; + +#[test] +fn modulo_boolean_left() { + let source = "true % 1"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotModuloType { + argument_type: Type::Boolean, + position: Span(0, 4) + }, + source, + }) + ); +} + +#[test] +fn modulo_boolean_right() { + let source = "1 % true"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotModuloType { + argument_type: Type::Boolean, + position: Span(4, 8) + }, + source, + }) + ); +} + +#[test] +fn modulo_character_left() { + let source = "'a' % 1"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotModuloType { + argument_type: Type::Character, + position: Span(0, 3) + }, + source, + }) + ); +} + +#[test] +fn modulo_character_right() { + let source = "1 % 'a'"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotModuloType { + argument_type: Type::Character, + position: Span(4, 7) + }, + source, + }) + ); +} + +#[test] +fn modulo_float_and_character() { + let source = "1.0 % 'a'"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotModuloType { + argument_type: Type::Character, + position: Span(6, 9) + }, + source, + }) + ); +} + +#[test] +fn modulo_float_and_integer() { + let source = "1.0 % 1"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotModuloArguments { + left_type: Type::Float, + right_type: Type::Integer, + position: Span(0, 7) + }, + source, + }) + ); +} + +#[test] +fn modulo_function_left() { + let source = "fn(){} % 1"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotModuloType { + argument_type: Type::Function(FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::None) + }), + position: Span(0, 6) + }, + source, + }) + ); +} + +#[test] +fn modulo_function_right() { + let source = "1 % fn(){}"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotModuloType { + argument_type: Type::Function(FunctionType { + type_parameters: None, + value_parameters: None, + return_type: Box::new(Type::None) + }), + position: Span(4, 10) + }, + source, + }) + ); +} + +#[test] +fn modulo_integer_and_float() { + let source = "1 % 1.0"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotModuloArguments { + left_type: Type::Integer, + right_type: Type::Float, + position: Span(0, 7) + }, + source, + }) + ); +} + +#[test] +fn modulo_list_left() { + let source = "[1, 2] % 1"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotModuloType { + argument_type: Type::List(Box::new(Type::Integer)), + position: Span(0, 6) + }, + source, + }) + ); +} + +#[test] +fn modulo_list_right() { + let source = "1 % [1, 2]"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotModuloType { + 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 modulo_string_left() { + let source = "\"hello\" % 1"; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotModuloType { + argument_type: Type::String, + position: Span(0, 7) + }, + source, + }) + ); +} + +#[test] +fn modulo_string_right() { + let source = "1 % \"hello\""; + + assert_eq!( + compile(source), + Err(DustError::Compile { + error: CompileError::CannotModuloType { + argument_type: Type::String, + position: Span(4, 11) + }, + source, + }) + ); +}