Add tests; Support capital "E" in floats
This commit is contained in:
parent
827a3df815
commit
e660c0acfb
@ -647,7 +647,15 @@ impl<'src> Compiler<'src> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Compiler::expect_addable_type(&left_type, &left_position)?;
|
match operator {
|
||||||
|
Token::Plus | Token::PlusEqual => {
|
||||||
|
Compiler::expect_addable_type(&left_type, &left_position)?
|
||||||
|
}
|
||||||
|
Token::Slash | Token::SlashEqual => {
|
||||||
|
Compiler::expect_dividable_type(&left_type, &left_position)?
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
let r#type = if is_assignment {
|
let r#type = if is_assignment {
|
||||||
Type::None
|
Type::None
|
||||||
@ -663,8 +671,45 @@ impl<'src> Compiler<'src> {
|
|||||||
let (right_instruction, right_type, right_position) = self.pop_last_instruction()?;
|
let (right_instruction, right_type, right_position) = self.pop_last_instruction()?;
|
||||||
let (right, push_back_right) = self.handle_binary_argument(&right_instruction)?;
|
let (right, push_back_right) = self.handle_binary_argument(&right_instruction)?;
|
||||||
|
|
||||||
Compiler::expect_addable_type(&right_type, &right_position)?;
|
match operator {
|
||||||
Compiler::expect_addable_types(&left_type, &left_position, &right_type, &right_position)?;
|
Token::Plus | Token::PlusEqual => {
|
||||||
|
Compiler::expect_addable_type(&right_type, &right_position)?;
|
||||||
|
Compiler::expect_addable_types(
|
||||||
|
&left_type,
|
||||||
|
&left_position,
|
||||||
|
&right_type,
|
||||||
|
&right_position,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Token::Minus | Token::MinusEqual => {
|
||||||
|
Compiler::expect_addable_type(&right_type, &right_position)?;
|
||||||
|
Compiler::expect_addable_types(
|
||||||
|
&left_type,
|
||||||
|
&left_position,
|
||||||
|
&right_type,
|
||||||
|
&right_position,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Token::Slash | Token::SlashEqual => {
|
||||||
|
Compiler::expect_dividable_type(&right_type, &right_position)?;
|
||||||
|
Compiler::expect_dividable_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(
|
||||||
|
&left_type,
|
||||||
|
&left_position,
|
||||||
|
&right_type,
|
||||||
|
&right_position,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
if push_back_right {
|
if push_back_right {
|
||||||
self.instructions
|
self.instructions
|
||||||
@ -1629,7 +1674,8 @@ impl<'src> Compiler<'src> {
|
|||||||
) -> Result<(), CompileError> {
|
) -> Result<(), CompileError> {
|
||||||
if matches!(
|
if matches!(
|
||||||
(left, right),
|
(left, right),
|
||||||
(Type::Character, Type::String)
|
(Type::Byte, Type::Byte)
|
||||||
|
| (Type::Character, Type::String)
|
||||||
| (Type::Character, Type::Character)
|
| (Type::Character, Type::Character)
|
||||||
| (Type::Float, Type::Float)
|
| (Type::Float, Type::Float)
|
||||||
| (Type::Integer, Type::Integer)
|
| (Type::Integer, Type::Integer)
|
||||||
@ -1645,6 +1691,105 @@ impl<'src> Compiler<'src> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expect_dividable_type(argument_type: &Type, position: &Span) -> Result<(), CompileError> {
|
||||||
|
if matches!(
|
||||||
|
argument_type,
|
||||||
|
Type::Byte | Type::Character | Type::Float | Type::Integer
|
||||||
|
) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(CompileError::CannotDivideType {
|
||||||
|
argument_type: argument_type.clone(),
|
||||||
|
position: *position,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect_dividable_types(
|
||||||
|
left: &Type,
|
||||||
|
left_position: &Span,
|
||||||
|
right: &Type,
|
||||||
|
right_position: &Span,
|
||||||
|
) -> Result<(), CompileError> {
|
||||||
|
if matches!(
|
||||||
|
(left, right),
|
||||||
|
(Type::Float, Type::Float) | (Type::Integer, Type::Integer)
|
||||||
|
) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(CompileError::CannotDivideArguments {
|
||||||
|
left_type: left.clone(),
|
||||||
|
right_type: right.clone(),
|
||||||
|
position: Span(left_position.0, right_position.1),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect_modulable_type(argument_type: &Type, position: &Span) -> Result<(), CompileError> {
|
||||||
|
if matches!(argument_type, Type::Byte | Type::Integer | Type::Float) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(CompileError::CannotModuloType {
|
||||||
|
argument_type: argument_type.clone(),
|
||||||
|
position: *position,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect_modulable_types(
|
||||||
|
left: &Type,
|
||||||
|
left_position: &Span,
|
||||||
|
right: &Type,
|
||||||
|
right_position: &Span,
|
||||||
|
) -> Result<(), CompileError> {
|
||||||
|
if matches!(
|
||||||
|
(left, right),
|
||||||
|
(Type::Byte, Type::Byte) | (Type::Integer, Type::Integer) | (Type::Float, Type::Float)
|
||||||
|
) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(CompileError::CannotModuloArguments {
|
||||||
|
left_type: left.clone(),
|
||||||
|
right_type: right.clone(),
|
||||||
|
position: Span(left_position.0, right_position.1),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect_multiplicable_type(
|
||||||
|
argument_type: &Type,
|
||||||
|
position: &Span,
|
||||||
|
) -> Result<(), CompileError> {
|
||||||
|
if matches!(argument_type, Type::Byte | Type::Float | Type::Integer) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(CompileError::CannotMultiplyType {
|
||||||
|
argument_type: argument_type.clone(),
|
||||||
|
position: *position,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect_multiplicable_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::CannotMultiplyArguments {
|
||||||
|
left_type: left.clone(),
|
||||||
|
right_type: right.clone(),
|
||||||
|
position: Span(left_position.0, right_position.1),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Operator precedence levels.
|
/// Operator precedence levels.
|
||||||
@ -2036,6 +2181,33 @@ pub enum CompileError {
|
|||||||
right_type: Type,
|
right_type: Type,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
|
CannotDivideType {
|
||||||
|
argument_type: Type,
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
|
CannotDivideArguments {
|
||||||
|
left_type: Type,
|
||||||
|
right_type: Type,
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
|
CannotModuloType {
|
||||||
|
argument_type: Type,
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
|
CannotModuloArguments {
|
||||||
|
left_type: Type,
|
||||||
|
right_type: Type,
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
|
CannotMultiplyType {
|
||||||
|
argument_type: Type,
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
|
CannotMultiplyArguments {
|
||||||
|
left_type: Type,
|
||||||
|
right_type: Type,
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
CannotSubtractLeft {
|
CannotSubtractLeft {
|
||||||
argument_type: Type,
|
argument_type: Type,
|
||||||
position: Span,
|
position: Span,
|
||||||
@ -2105,7 +2277,13 @@ impl AnnotatedError for CompileError {
|
|||||||
Self::CannotAddArguments { .. } => "Cannot add these types",
|
Self::CannotAddArguments { .. } => "Cannot add these types",
|
||||||
Self::CannotAddType { .. } => "Cannot add to this type",
|
Self::CannotAddType { .. } => "Cannot add to this type",
|
||||||
Self::CannotChainComparison { .. } => "Cannot chain comparison operations",
|
Self::CannotChainComparison { .. } => "Cannot chain comparison operations",
|
||||||
|
Self::CannotDivideArguments { .. } => "Cannot divide these types",
|
||||||
|
Self::CannotDivideType { .. } => "Cannot divide this type",
|
||||||
|
Self::CannotModuloArguments { .. } => "Cannot modulo these types",
|
||||||
|
Self::CannotModuloType { .. } => "Cannot modulo this type",
|
||||||
Self::CannotMutateImmutableVariable { .. } => "Cannot mutate immutable variable",
|
Self::CannotMutateImmutableVariable { .. } => "Cannot mutate immutable variable",
|
||||||
|
Self::CannotMultiplyArguments { .. } => "Cannot multiply these types",
|
||||||
|
Self::CannotMultiplyType { .. } => "Cannot multiply this type",
|
||||||
Self::CannotResolveRegisterType { .. } => "Cannot resolve register type",
|
Self::CannotResolveRegisterType { .. } => "Cannot resolve register type",
|
||||||
Self::CannotResolveVariableType { .. } => "Cannot resolve type",
|
Self::CannotResolveVariableType { .. } => "Cannot resolve type",
|
||||||
Self::CannotSubtract { .. } => "Cannot subtract these types",
|
Self::CannotSubtract { .. } => "Cannot subtract these types",
|
||||||
@ -2208,7 +2386,13 @@ impl AnnotatedError for CompileError {
|
|||||||
Self::CannotAddArguments { position, .. } => *position,
|
Self::CannotAddArguments { position, .. } => *position,
|
||||||
Self::CannotAddType { position, .. } => *position,
|
Self::CannotAddType { position, .. } => *position,
|
||||||
Self::CannotChainComparison { position } => *position,
|
Self::CannotChainComparison { position } => *position,
|
||||||
|
Self::CannotDivideArguments { position, .. } => *position,
|
||||||
|
Self::CannotDivideType { position, .. } => *position,
|
||||||
|
Self::CannotModuloArguments { position, .. } => *position,
|
||||||
|
Self::CannotModuloType { position, .. } => *position,
|
||||||
Self::CannotMutateImmutableVariable { position, .. } => *position,
|
Self::CannotMutateImmutableVariable { position, .. } => *position,
|
||||||
|
Self::CannotMultiplyArguments { position, .. } => *position,
|
||||||
|
Self::CannotMultiplyType { position, .. } => *position,
|
||||||
Self::CannotResolveRegisterType { position, .. } => *position,
|
Self::CannotResolveRegisterType { position, .. } => *position,
|
||||||
Self::CannotResolveVariableType { position, .. } => *position,
|
Self::CannotResolveVariableType { position, .. } => *position,
|
||||||
Self::CannotSubtract { position, .. } => *position,
|
Self::CannotSubtract { position, .. } => *position,
|
||||||
|
@ -211,14 +211,14 @@ impl<'src> Lexer<'src> {
|
|||||||
|
|
||||||
let peek_second_char = self.peek_second_char();
|
let peek_second_char = self.peek_second_char();
|
||||||
|
|
||||||
if let ('e', Some('0'..='9')) = (peek_char, peek_second_char) {
|
if let ('e' | 'E', Some('0'..='9')) = (peek_char, peek_second_char) {
|
||||||
self.next_char();
|
self.next_char();
|
||||||
self.next_char();
|
self.next_char();
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ('e', Some('-')) = (peek_char, peek_second_char) {
|
if let ('e' | 'E', Some('+')) = (peek_char, peek_second_char) {
|
||||||
self.next_char();
|
self.next_char();
|
||||||
self.next_char();
|
self.next_char();
|
||||||
|
|
||||||
@ -226,7 +226,9 @@ impl<'src> Lexer<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Err(LexError::ExpectedCharacterMultiple {
|
return Err(LexError::ExpectedCharacterMultiple {
|
||||||
expected: &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'e', '-'],
|
expected: &[
|
||||||
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'e', 'E', '-',
|
||||||
|
],
|
||||||
actual: peek_char,
|
actual: peek_char,
|
||||||
position: self.position,
|
position: self.position,
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,69 @@
|
|||||||
use dust_lang::*;
|
use dust_lang::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_bytes() {
|
||||||
|
let source = "0xfe + 0x01";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
compile(source),
|
||||||
|
Ok(Chunk::with_data(
|
||||||
|
None,
|
||||||
|
FunctionType {
|
||||||
|
type_parameters: None,
|
||||||
|
value_parameters: None,
|
||||||
|
return_type: Box::new(Type::Byte),
|
||||||
|
},
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
Instruction::add(
|
||||||
|
Destination::Register(0),
|
||||||
|
Argument::Constant(0),
|
||||||
|
Argument::Constant(1)
|
||||||
|
),
|
||||||
|
Span(5, 6)
|
||||||
|
),
|
||||||
|
(Instruction::r#return(true), Span(11, 11))
|
||||||
|
],
|
||||||
|
vec![ConcreteValue::Byte(0xfe), ConcreteValue::Byte(0x01)],
|
||||||
|
vec![]
|
||||||
|
))
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(run(source), Ok(Some(ConcreteValue::Byte(0xff))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_bytes_saturate() {
|
||||||
|
let source = "0xff + 0x01";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
compile(source),
|
||||||
|
Ok(Chunk::with_data(
|
||||||
|
None,
|
||||||
|
FunctionType {
|
||||||
|
type_parameters: None,
|
||||||
|
value_parameters: None,
|
||||||
|
return_type: Box::new(Type::Byte),
|
||||||
|
},
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
Instruction::add(
|
||||||
|
Destination::Register(0),
|
||||||
|
Argument::Constant(0),
|
||||||
|
Argument::Constant(1)
|
||||||
|
),
|
||||||
|
Span(5, 6)
|
||||||
|
),
|
||||||
|
(Instruction::r#return(true), Span(11, 11))
|
||||||
|
],
|
||||||
|
vec![ConcreteValue::Byte(0xff), ConcreteValue::Byte(0x01)],
|
||||||
|
vec![]
|
||||||
|
))
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(run(source), Ok(Some(ConcreteValue::Byte(0xff))));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_characters() {
|
fn add_characters() {
|
||||||
let source = "'a' + 'b'";
|
let source = "'a' + 'b'";
|
||||||
@ -99,6 +163,41 @@ fn add_floats() {
|
|||||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Float(3.0))));
|
assert_eq!(run(source), Ok(Some(ConcreteValue::Float(3.0))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_floats_saturatate() {
|
||||||
|
let source = "1.7976931348623157E+308 + 0.00000001";
|
||||||
|
|
||||||
|
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(24, 25)
|
||||||
|
),
|
||||||
|
(Instruction::r#return(true), Span(36, 36))
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
ConcreteValue::Float(f64::MAX),
|
||||||
|
ConcreteValue::Float(0.00000001)
|
||||||
|
],
|
||||||
|
vec![]
|
||||||
|
))
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(run(source), Ok(Some(ConcreteValue::Float(f64::MAX))));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_integers() {
|
fn add_integers() {
|
||||||
let source = "1 + 2";
|
let source = "1 + 2";
|
||||||
@ -131,6 +230,38 @@ fn add_integers() {
|
|||||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(3))));
|
assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(3))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_integers_saturate() {
|
||||||
|
let source = "9223372036854775807 + 1";
|
||||||
|
|
||||||
|
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(20, 21)
|
||||||
|
),
|
||||||
|
(Instruction::r#return(true), Span(23, 23))
|
||||||
|
],
|
||||||
|
vec![ConcreteValue::Integer(i64::MAX), ConcreteValue::Integer(1)],
|
||||||
|
vec![]
|
||||||
|
))
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(i64::MAX))));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_strings() {
|
fn add_strings() {
|
||||||
let source = "\"Hello, \" + \"world!\"";
|
let source = "\"Hello, \" + \"world!\"";
|
||||||
|
@ -1,5 +1,37 @@
|
|||||||
use dust_lang::*;
|
use dust_lang::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_bytes() {
|
||||||
|
let source = "0xff / 0x01";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
compile(source),
|
||||||
|
Ok(Chunk::with_data(
|
||||||
|
None,
|
||||||
|
FunctionType {
|
||||||
|
type_parameters: None,
|
||||||
|
value_parameters: None,
|
||||||
|
return_type: Box::new(Type::Byte),
|
||||||
|
},
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
Instruction::divide(
|
||||||
|
Destination::Register(0),
|
||||||
|
Argument::Constant(0),
|
||||||
|
Argument::Constant(0)
|
||||||
|
),
|
||||||
|
Span(0, 7)
|
||||||
|
),
|
||||||
|
(Instruction::r#return(true), Span(11, 11))
|
||||||
|
],
|
||||||
|
vec![ConcreteValue::Byte(0xff), ConcreteValue::Byte(0x01)],
|
||||||
|
vec![]
|
||||||
|
))
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(run(source), Ok(Some(ConcreteValue::Byte(0xff))));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn divide_floats() {
|
fn divide_floats() {
|
||||||
let source = "2.0 / 2.0";
|
let source = "2.0 / 2.0";
|
||||||
|
87
dust-lang/tests/math_divide_errors.rs
Normal file
87
dust-lang/tests/math_divide_errors.rs
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
use dust_lang::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_boolean_left() {
|
||||||
|
let source = "true / 1";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
compile(source),
|
||||||
|
Err(DustError::Compile {
|
||||||
|
error: CompileError::CannotDivideType {
|
||||||
|
argument_type: Type::Boolean,
|
||||||
|
position: Span(0, 4)
|
||||||
|
},
|
||||||
|
source,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_boolean_right() {
|
||||||
|
let source = "1 / true";
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_character_left() {
|
||||||
|
let source = "'a' / 1";
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_character_right() {
|
||||||
|
let source = "1 / 'a'";
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_function_left() {
|
||||||
|
let source = "fn(){} / 1";
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_function_right() {
|
||||||
|
let source = "1 / fn(){}";
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_list_left() {
|
||||||
|
let source = "[1, 2] / 1";
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_list_right() {
|
||||||
|
let source = "1 / [1, 2]";
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn add_range_left() {
|
||||||
|
// todo!("Add ranges")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// #[test]
|
||||||
|
// fn add_range_right() {
|
||||||
|
// todo!("Add ranges")
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_string_left() {
|
||||||
|
let source = "\"hello\" / 1";
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_string_right() {
|
||||||
|
let source = "1 / \"hello\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_float_and_character() {
|
||||||
|
let source = "1.0 / 'a'";
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_float_and_integer() {
|
||||||
|
let source = "1.0 / 1";
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn divide_integer_and_float() {
|
||||||
|
let source = "1 / 1.0";
|
||||||
|
}
|
@ -32,6 +32,41 @@ fn subtract_floats() {
|
|||||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Float(0.0))));
|
assert_eq!(run(source), Ok(Some(ConcreteValue::Float(0.0))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn subtract_floats_saturate() {
|
||||||
|
let source = "-1.7976931348623157E+308 - 0.0000001";
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
compile(source),
|
||||||
|
Ok(Chunk::with_data(
|
||||||
|
None,
|
||||||
|
FunctionType {
|
||||||
|
type_parameters: None,
|
||||||
|
value_parameters: None,
|
||||||
|
return_type: Box::new(Type::Float),
|
||||||
|
},
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
Instruction::subtract(
|
||||||
|
Destination::Register(0),
|
||||||
|
Argument::Constant(0),
|
||||||
|
Argument::Constant(1)
|
||||||
|
),
|
||||||
|
Span(25, 26)
|
||||||
|
),
|
||||||
|
(Instruction::r#return(true), Span(36, 36)),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
ConcreteValue::Float(f64::MIN),
|
||||||
|
ConcreteValue::Float(0.0000001),
|
||||||
|
],
|
||||||
|
vec![]
|
||||||
|
))
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(run(source), Ok(Some(ConcreteValue::Float(f64::MIN))));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn subtract_integers() {
|
fn subtract_integers() {
|
||||||
let source = "1 - 2";
|
let source = "1 - 2";
|
||||||
@ -63,3 +98,35 @@ fn subtract_integers() {
|
|||||||
|
|
||||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(-1))));
|
assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(-1))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn subtract_integers_saturate() {
|
||||||
|
let source = "-9223372036854775808 - 1";
|
||||||
|
|
||||||
|
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(21, 22)
|
||||||
|
),
|
||||||
|
(Instruction::r#return(true), Span(24, 24)),
|
||||||
|
],
|
||||||
|
vec![ConcreteValue::Integer(i64::MIN), ConcreteValue::Integer(1),],
|
||||||
|
vec![]
|
||||||
|
))
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(i64::MIN))));
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user