445 lines
15 KiB
Rust
445 lines
15 KiB
Rust
use dust_lang::{
|
|
Chunk, ConcreteValue, DustString, FunctionType, Instruction, Span, Type, Value, compile,
|
|
instruction::TypeCode, run,
|
|
};
|
|
|
|
#[test]
|
|
fn load_boolean_true() {
|
|
let source = "true";
|
|
let chunk = Chunk {
|
|
r#type: FunctionType {
|
|
return_type: Type::Boolean,
|
|
..FunctionType::default()
|
|
},
|
|
instructions: vec![
|
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, false),
|
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
|
],
|
|
positions: vec![Span(0, 4), Span(4, 4)],
|
|
..Chunk::default()
|
|
};
|
|
let return_value = Some(Value::boolean(true));
|
|
|
|
assert_eq!(chunk, compile(source).unwrap());
|
|
assert_eq!(return_value, run(source).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn load_boolean_false() {
|
|
let source = "false";
|
|
let chunk = Chunk {
|
|
r#type: FunctionType {
|
|
return_type: Type::Boolean,
|
|
..FunctionType::default()
|
|
},
|
|
instructions: vec![
|
|
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
|
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
|
],
|
|
positions: vec![Span(0, 5), Span(5, 5)],
|
|
..Chunk::default()
|
|
};
|
|
let return_value = Some(Value::boolean(false));
|
|
|
|
assert_eq!(chunk, compile(source).unwrap());
|
|
assert_eq!(return_value, run(source).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn load_byte() {
|
|
let source = "0x2a";
|
|
let chunk = Chunk {
|
|
r#type: FunctionType {
|
|
return_type: Type::Byte,
|
|
..FunctionType::default()
|
|
},
|
|
instructions: vec![
|
|
Instruction::load_encoded(0, 0x2a, TypeCode::BYTE, false),
|
|
Instruction::r#return(true, 0, TypeCode::BYTE),
|
|
],
|
|
positions: vec![Span(0, 6), Span(6, 6)],
|
|
..Chunk::default()
|
|
};
|
|
let return_value = Some(Value::byte(0x2a));
|
|
|
|
assert_eq!(chunk, compile(source).unwrap());
|
|
assert_eq!(return_value, run(source).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn load_character() {
|
|
let source = "'a'";
|
|
let chunk = Chunk {
|
|
r#type: FunctionType {
|
|
return_type: Type::Character,
|
|
..FunctionType::default()
|
|
},
|
|
instructions: vec![
|
|
Instruction::load_constant(0, 0, TypeCode::CHARACTER, false),
|
|
Instruction::r#return(true, 0, TypeCode::CHARACTER),
|
|
],
|
|
positions: vec![Span(0, 3), Span(3, 3)],
|
|
constants: vec![ConcreteValue::Character('a')],
|
|
..Chunk::default()
|
|
};
|
|
let return_value = Some(Value::character('a'));
|
|
|
|
assert_eq!(chunk, compile(source).unwrap());
|
|
assert_eq!(return_value, run(source).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn load_float() {
|
|
let source = "42.42";
|
|
let chunk = Chunk {
|
|
r#type: FunctionType {
|
|
return_type: Type::Float,
|
|
..FunctionType::default()
|
|
},
|
|
instructions: vec![
|
|
Instruction::load_constant(0, 0, TypeCode::FLOAT, false),
|
|
Instruction::r#return(true, 0, TypeCode::FLOAT),
|
|
],
|
|
positions: vec![Span(0, 4), Span(4, 4)],
|
|
constants: vec![ConcreteValue::Float(42.42)],
|
|
..Chunk::default()
|
|
};
|
|
let return_value = Some(Value::float(42.42));
|
|
|
|
assert_eq!(chunk, compile(source).unwrap());
|
|
assert_eq!(return_value, run(source).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn load_integer() {
|
|
let source = "42";
|
|
let chunk = Chunk {
|
|
r#type: FunctionType {
|
|
return_type: Type::Integer,
|
|
..FunctionType::default()
|
|
},
|
|
instructions: vec![
|
|
Instruction::load_constant(0, 0, TypeCode::INTEGER, false),
|
|
Instruction::r#return(true, 0, TypeCode::INTEGER),
|
|
],
|
|
positions: vec![Span(0, 2), Span(2, 2)],
|
|
constants: vec![ConcreteValue::Integer(42)],
|
|
..Chunk::default()
|
|
};
|
|
let return_value = Some(Value::integer(42));
|
|
|
|
assert_eq!(chunk, compile(source).unwrap());
|
|
assert_eq!(return_value, run(source).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn load_string() {
|
|
let source = "\"Hello, World!\"";
|
|
let chunk = Chunk {
|
|
r#type: FunctionType {
|
|
return_type: Type::String,
|
|
..FunctionType::default()
|
|
},
|
|
instructions: vec![
|
|
Instruction::load_constant(0, 0, TypeCode::STRING, false),
|
|
Instruction::r#return(true, 0, TypeCode::STRING),
|
|
],
|
|
positions: vec![Span(0, 15), Span(15, 15)],
|
|
constants: vec![ConcreteValue::String(DustString::from("Hello, World!"))],
|
|
..Chunk::default()
|
|
};
|
|
let return_value = Some(Value::string("Hello, World!"));
|
|
|
|
assert_eq!(chunk, compile(source).unwrap());
|
|
assert_eq!(return_value, run(source).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn load_boolean_list() {
|
|
let source = "[true, false]";
|
|
let chunk = Chunk {
|
|
r#type: FunctionType {
|
|
return_type: Type::List(TypeCode::BOOLEAN),
|
|
..FunctionType::default()
|
|
},
|
|
instructions: vec![
|
|
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, false),
|
|
Instruction::load_encoded(1, false as u8, TypeCode::BOOLEAN, false),
|
|
Instruction::load_list(0, TypeCode::BOOLEAN, 0, 1, false),
|
|
Instruction::r#return(true, 0, TypeCode::LIST),
|
|
],
|
|
positions: vec![Span(0, 13), Span(13, 13)],
|
|
..Chunk::default()
|
|
};
|
|
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
|
ConcreteValue::Boolean(true),
|
|
ConcreteValue::Boolean(false),
|
|
])));
|
|
|
|
assert_eq!(chunk, compile(source).unwrap());
|
|
assert_eq!(return_value, run(source).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn load_byte_list() {
|
|
let source = "[0x2a, 0x42]";
|
|
let chunk = Chunk {
|
|
r#type: FunctionType {
|
|
return_type: Type::List(TypeCode::BYTE),
|
|
..FunctionType::default()
|
|
},
|
|
instructions: vec![
|
|
Instruction::load_encoded(0, 0x2a, TypeCode::BYTE, false),
|
|
Instruction::load_encoded(1, 0x42, TypeCode::BYTE, false),
|
|
Instruction::load_list(0, TypeCode::BYTE, 0, 1, false),
|
|
Instruction::r#return(true, 0, TypeCode::LIST),
|
|
],
|
|
positions: vec![Span(0, 15), Span(15, 15)],
|
|
..Chunk::default()
|
|
};
|
|
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
|
ConcreteValue::Byte(0x2a),
|
|
ConcreteValue::Byte(0x42),
|
|
])));
|
|
|
|
assert_eq!(chunk, compile(source).unwrap());
|
|
assert_eq!(return_value, run(source).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn load_character_list() {
|
|
let source = "['a', 'b']";
|
|
let chunk = Chunk {
|
|
r#type: FunctionType {
|
|
return_type: Type::List(TypeCode::CHARACTER),
|
|
..FunctionType::default()
|
|
},
|
|
instructions: vec![
|
|
Instruction::load_constant(0, 0, TypeCode::CHARACTER, false),
|
|
Instruction::load_constant(1, 1, TypeCode::CHARACTER, false),
|
|
Instruction::load_list(0, TypeCode::CHARACTER, 0, 1, false),
|
|
Instruction::r#return(true, 0, TypeCode::LIST),
|
|
],
|
|
positions: vec![Span(0, 9), Span(9, 9)],
|
|
constants: vec![ConcreteValue::Character('a'), ConcreteValue::Character('b')],
|
|
..Chunk::default()
|
|
};
|
|
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
|
ConcreteValue::Character('a'),
|
|
ConcreteValue::Character('b'),
|
|
])));
|
|
|
|
assert_eq!(chunk, compile(source).unwrap());
|
|
assert_eq!(return_value, run(source).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn load_float_list() {
|
|
let source = "[42.42, 24.24]";
|
|
let chunk = Chunk {
|
|
r#type: FunctionType {
|
|
return_type: Type::List(TypeCode::FLOAT),
|
|
..FunctionType::default()
|
|
},
|
|
instructions: vec![
|
|
Instruction::load_constant(0, 0, TypeCode::FLOAT, false),
|
|
Instruction::load_constant(1, 1, TypeCode::FLOAT, false),
|
|
Instruction::load_list(0, TypeCode::FLOAT, 0, 1, false),
|
|
Instruction::r#return(true, 0, TypeCode::LIST),
|
|
],
|
|
positions: vec![Span(0, 15), Span(15, 15)],
|
|
constants: vec![ConcreteValue::Float(42.42), ConcreteValue::Float(24.24)],
|
|
..Chunk::default()
|
|
};
|
|
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
|
ConcreteValue::Float(42.42),
|
|
ConcreteValue::Float(24.24),
|
|
])));
|
|
|
|
assert_eq!(chunk, compile(source).unwrap());
|
|
assert_eq!(return_value, run(source).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn load_integer_list() {
|
|
let source = "[1, 2, 3]";
|
|
let chunk = Chunk {
|
|
r#type: FunctionType {
|
|
return_type: Type::List(TypeCode::INTEGER),
|
|
..FunctionType::default()
|
|
},
|
|
instructions: vec![
|
|
Instruction::load_constant(0, 0, TypeCode::INTEGER, false),
|
|
Instruction::load_constant(1, 1, TypeCode::INTEGER, false),
|
|
Instruction::load_constant(2, 2, TypeCode::INTEGER, false),
|
|
Instruction::load_list(0, TypeCode::INTEGER, 0, 2, false),
|
|
Instruction::r#return(true, 0, TypeCode::LIST),
|
|
],
|
|
positions: vec![Span(0, 9), Span(9, 9)],
|
|
constants: vec![
|
|
ConcreteValue::Integer(1),
|
|
ConcreteValue::Integer(2),
|
|
ConcreteValue::Integer(3),
|
|
],
|
|
..Chunk::default()
|
|
};
|
|
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
|
ConcreteValue::Integer(1),
|
|
ConcreteValue::Integer(2),
|
|
ConcreteValue::Integer(3),
|
|
])));
|
|
|
|
assert_eq!(chunk, compile(source).unwrap());
|
|
assert_eq!(return_value, run(source).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn load_string_list() {
|
|
let source = "[\"Hello\", \"World\"]";
|
|
let chunk = Chunk {
|
|
r#type: FunctionType {
|
|
return_type: Type::List(TypeCode::STRING),
|
|
..FunctionType::default()
|
|
},
|
|
instructions: vec![
|
|
Instruction::load_constant(0, 0, TypeCode::STRING, false),
|
|
Instruction::load_constant(1, 1, TypeCode::STRING, false),
|
|
Instruction::load_list(0, TypeCode::STRING, 0, 1, false),
|
|
Instruction::r#return(true, 0, TypeCode::LIST),
|
|
],
|
|
positions: vec![Span(0, 19), Span(19, 19)],
|
|
constants: vec![
|
|
ConcreteValue::String(DustString::from("Hello")),
|
|
ConcreteValue::String(DustString::from("World")),
|
|
],
|
|
..Chunk::default()
|
|
};
|
|
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
|
ConcreteValue::String(DustString::from("Hello")),
|
|
ConcreteValue::String(DustString::from("World")),
|
|
])));
|
|
|
|
assert_eq!(chunk, compile(source).unwrap());
|
|
assert_eq!(return_value, run(source).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn load_nested_list() {
|
|
let source = "[[1, 2], [3, 4]]";
|
|
let chunk = Chunk {
|
|
r#type: FunctionType {
|
|
return_type: Type::List(TypeCode::LIST),
|
|
..FunctionType::default()
|
|
},
|
|
instructions: vec![
|
|
Instruction::load_constant(0, 0, TypeCode::INTEGER, false),
|
|
Instruction::load_constant(1, 1, TypeCode::INTEGER, false),
|
|
Instruction::load_list(0, TypeCode::INTEGER, 0, 1, false),
|
|
Instruction::load_constant(2, 2, TypeCode::INTEGER, false),
|
|
Instruction::load_constant(3, 3, TypeCode::INTEGER, false),
|
|
Instruction::load_list(1, TypeCode::INTEGER, 2, 3, false),
|
|
Instruction::load_list(2, TypeCode::LIST, 0, 1, false),
|
|
Instruction::r#return(true, 2, TypeCode::LIST),
|
|
],
|
|
positions: vec![
|
|
Span(2, 3),
|
|
Span(5, 6),
|
|
Span(1, 7),
|
|
Span(10, 11),
|
|
Span(13, 14),
|
|
Span(9, 15),
|
|
Span(0, 16),
|
|
Span(16, 16),
|
|
],
|
|
constants: vec![
|
|
ConcreteValue::Integer(1),
|
|
ConcreteValue::Integer(2),
|
|
ConcreteValue::Integer(3),
|
|
ConcreteValue::Integer(4),
|
|
],
|
|
..Chunk::default()
|
|
};
|
|
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
|
ConcreteValue::List(vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)]),
|
|
ConcreteValue::List(vec![ConcreteValue::Integer(3), ConcreteValue::Integer(4)]),
|
|
])));
|
|
|
|
assert_eq!(chunk, compile(source).unwrap());
|
|
assert_eq!(return_value, run(source).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn load_deeply_nested_list() {
|
|
let source = "[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]";
|
|
let chunk = Chunk {
|
|
r#type: FunctionType {
|
|
return_type: Type::List(TypeCode::LIST),
|
|
..FunctionType::default()
|
|
},
|
|
instructions: vec![
|
|
Instruction::load_constant(0, 0, TypeCode::INTEGER, false),
|
|
Instruction::load_constant(1, 1, TypeCode::INTEGER, false),
|
|
Instruction::load_list(0, TypeCode::INTEGER, 0, 1, false),
|
|
Instruction::load_constant(2, 2, TypeCode::INTEGER, false),
|
|
Instruction::load_constant(3, 3, TypeCode::INTEGER, false),
|
|
Instruction::load_list(1, TypeCode::INTEGER, 2, 3, false),
|
|
Instruction::load_list(2, TypeCode::LIST, 0, 1, false),
|
|
Instruction::close(0, 1, TypeCode::LIST),
|
|
Instruction::load_constant(4, 4, TypeCode::INTEGER, false),
|
|
Instruction::load_constant(5, 5, TypeCode::INTEGER, false),
|
|
Instruction::load_list(3, TypeCode::INTEGER, 4, 5, false),
|
|
Instruction::load_constant(6, 6, TypeCode::INTEGER, false),
|
|
Instruction::load_constant(7, 7, TypeCode::INTEGER, false),
|
|
Instruction::load_list(4, TypeCode::INTEGER, 6, 7, false),
|
|
Instruction::load_list(5, TypeCode::LIST, 3, 4, false),
|
|
Instruction::close(3, 4, TypeCode::LIST),
|
|
Instruction::load_list(6, TypeCode::LIST, 2, 5, false),
|
|
Instruction::r#return(true, 6, TypeCode::LIST),
|
|
],
|
|
positions: vec![
|
|
Span(3, 4),
|
|
Span(6, 7),
|
|
Span(2, 8),
|
|
Span(11, 12),
|
|
Span(14, 15),
|
|
Span(10, 16),
|
|
Span(1, 17),
|
|
Span(17, 18),
|
|
Span(21, 22),
|
|
Span(24, 25),
|
|
Span(20, 26),
|
|
Span(29, 30),
|
|
Span(32, 33),
|
|
Span(28, 34),
|
|
Span(19, 35),
|
|
Span(35, 36),
|
|
Span(0, 36),
|
|
Span(36, 36),
|
|
],
|
|
constants: vec![
|
|
ConcreteValue::Integer(1),
|
|
ConcreteValue::Integer(2),
|
|
ConcreteValue::Integer(3),
|
|
ConcreteValue::Integer(4),
|
|
ConcreteValue::Integer(5),
|
|
ConcreteValue::Integer(6),
|
|
ConcreteValue::Integer(7),
|
|
ConcreteValue::Integer(8),
|
|
],
|
|
..Chunk::default()
|
|
};
|
|
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
|
ConcreteValue::List(vec![
|
|
ConcreteValue::List(vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)]),
|
|
ConcreteValue::List(vec![ConcreteValue::Integer(3), ConcreteValue::Integer(4)]),
|
|
]),
|
|
ConcreteValue::List(vec![
|
|
ConcreteValue::List(vec![ConcreteValue::Integer(5), ConcreteValue::Integer(6)]),
|
|
ConcreteValue::List(vec![ConcreteValue::Integer(7), ConcreteValue::Integer(8)]),
|
|
]),
|
|
])));
|
|
|
|
assert_eq!(chunk, compile(source).unwrap());
|
|
assert_eq!(return_value, run(source).unwrap());
|
|
}
|