Begin rewriting tests
This commit is contained in:
parent
4b38a93409
commit
8cc5661944
@ -40,77 +40,5 @@ name = "threads"
|
||||
harness = false
|
||||
|
||||
[[test]]
|
||||
name = "logic_and"
|
||||
path = "tests/logic/and.rs"
|
||||
|
||||
[[test]]
|
||||
name = "logic_and_and"
|
||||
path = "tests/logic/and_and.rs"
|
||||
|
||||
[[test]]
|
||||
name = "logic_or"
|
||||
path = "tests/logic/or.rs"
|
||||
|
||||
[[test]]
|
||||
name = "logic_variables"
|
||||
path = "tests/logic/variables.rs"
|
||||
|
||||
[[test]]
|
||||
name = "math_add"
|
||||
path = "tests/math/add.rs"
|
||||
|
||||
[[test]]
|
||||
name = "math_add_assign"
|
||||
path = "tests/math/add_assign.rs"
|
||||
|
||||
[[test]]
|
||||
name = "math_add_errors"
|
||||
path = "tests/math/add_errors.rs"
|
||||
|
||||
[[test]]
|
||||
name = "math_divide"
|
||||
path = "tests/math/divide.rs"
|
||||
|
||||
[[test]]
|
||||
name = "math_divide_assign"
|
||||
path = "tests/math/divide_assign.rs"
|
||||
|
||||
[[test]]
|
||||
name = "math_divide_erros"
|
||||
path = "tests/math/divide_errors.rs"
|
||||
|
||||
[[test]]
|
||||
name = "math_modulo"
|
||||
path = "tests/math/modulo.rs"
|
||||
|
||||
[[test]]
|
||||
name = "math_modulo_assign"
|
||||
path = "tests/math/modulo_assign.rs"
|
||||
|
||||
[[test]]
|
||||
name = "math_modulo_errors"
|
||||
path = "tests/math/modulo_errors.rs"
|
||||
|
||||
[[test]]
|
||||
name = "math_multiply"
|
||||
path = "tests/math/multiply.rs"
|
||||
|
||||
[[test]]
|
||||
name = "math_multiply_assign"
|
||||
path = "tests/math/multiply_assign.rs"
|
||||
|
||||
[[test]]
|
||||
name = "math_multiply_errors"
|
||||
path = "tests/math/multiply_errors.rs"
|
||||
|
||||
[[test]]
|
||||
name = "math_subtract"
|
||||
path = "tests/math/subtract.rs"
|
||||
|
||||
[[test]]
|
||||
name = "math_subtract_assign"
|
||||
path = "tests/math/subtract_assign.rs"
|
||||
|
||||
[[test]]
|
||||
name = "math_subtract_errors"
|
||||
path = "tests/math/subtract_errors.rs"
|
||||
name = "load_values"
|
||||
path = "tests/values/load_values.rs"
|
||||
|
@ -16,28 +16,26 @@
|
||||
//! that implements the [Write][] trait.
|
||||
//!
|
||||
//! ```text
|
||||
//! ╭─────────────────────────────────────────────────────────────────╮
|
||||
//! │ dust │
|
||||
//! │ │
|
||||
//! │ write_line("Hello world!") │
|
||||
//! │ │
|
||||
//! │ 3 instructions, 1 constants, 0 locals, returns none │
|
||||
//! │ │
|
||||
//! │ Instructions │
|
||||
//! │ ╭─────┬────────────┬─────────────────┬────────────────────────╮ │
|
||||
//! │ │ i │ POSITION │ OPERATION │ INFO │ │
|
||||
//! │ ├─────┼────────────┼─────────────────┼────────────────────────┤ │
|
||||
//! │ │ 0 │ (11, 25) │ LOAD_CONSTANT │ R0 = C0 │ │
|
||||
//! │ │ 1 │ (0, 26) │ CALL_NATIVE │ write_line(R0) │ │
|
||||
//! │ │ 2 │ (26, 26) │ RETURN │ RETURN │ │
|
||||
//! │ ╰─────┴────────────┴─────────────────┴────────────────────────╯ │
|
||||
//! │ Constants │
|
||||
//! │ ╭─────┬──────────────────────────┬──────────────────────────╮ │
|
||||
//! │ │ i │ TYPE │ VALUE │ │
|
||||
//! │ ├─────┼──────────────────────────┼──────────────────────────┤ │
|
||||
//! │ │ 0 │ str │ Hello world! │ │
|
||||
//! │ ╰─────┴──────────────────────────┴──────────────────────────╯ │
|
||||
//! ╰─────────────────────────────────────────────────────────────────╯
|
||||
//! ╭──────────────────────────────────────────────────────────────────────────────────╮
|
||||
//! │ write_line("hello world") │
|
||||
//! │ │
|
||||
//! │ 3 instructions, 1 constants, 0 locals, returns none │
|
||||
//! │ │
|
||||
//! │ Instructions │
|
||||
//! │ ╭─────┬────────────┬─────────────────┬─────────────────────────────────────────╮ │
|
||||
//! │ │ i │ POSITION │ OPERATION │ INFO │ │
|
||||
//! │ ├─────┼────────────┼─────────────────┼─────────────────────────────────────────┤ │
|
||||
//! │ │ 0 │ (11, 24) │ LOAD_CONSTANT │ R_STR_0 = C0 │ │
|
||||
//! │ │ 1 │ (0, 25) │ CALL_NATIVE │ write_line(R0) │ │
|
||||
//! │ │ 2 │ (25, 25) │ RETURN │ RETURN │ │
|
||||
//! │ ╰─────┴────────────┴─────────────────┴─────────────────────────────────────────╯ │
|
||||
//! │ Constants │
|
||||
//! │ ╭─────┬──────────────────────────┬──────────────────────────╮ │
|
||||
//! │ │ i │ TYPE │ VALUE │ │
|
||||
//! │ ├─────┼──────────────────────────┼──────────────────────────┤ │
|
||||
//! │ │ 0 │ str │ hello world │ │
|
||||
//! │ ╰─────┴──────────────────────────┴──────────────────────────╯ │
|
||||
//! ╰──────────────────────────────────────────────────────────────────────────────────╯
|
||||
//! ```
|
||||
use std::io::{self, Write};
|
||||
|
||||
@ -411,7 +409,10 @@ impl<'a, W: Write> Disassembler<'a, W> {
|
||||
if let Some(source) = self.source {
|
||||
let lazily_formatted = source.split_whitespace().collect::<Vec<&str>>().join(" ");
|
||||
|
||||
self.write_center_border("")?;
|
||||
if self.chunk.name.is_some() {
|
||||
self.write_center_border("")?;
|
||||
}
|
||||
|
||||
self.write_center_border(&lazily_formatted)?;
|
||||
self.write_center_border("")?;
|
||||
}
|
||||
|
@ -32,26 +32,26 @@ use crate::{ConcreteValue, DustString, Function, FunctionType, Instruction, Span
|
||||
/// Representation of a Dust program or function.
|
||||
///
|
||||
/// See the [module-level documentation](index.html) for more information.
|
||||
#[derive(Clone, PartialOrd, Serialize, Deserialize)]
|
||||
#[derive(Clone, Default, PartialOrd, Serialize, Deserialize)]
|
||||
pub struct Chunk {
|
||||
pub(crate) name: Option<DustString>,
|
||||
pub(crate) r#type: FunctionType,
|
||||
pub name: Option<DustString>,
|
||||
pub r#type: FunctionType,
|
||||
|
||||
pub(crate) instructions: Vec<Instruction>,
|
||||
pub(crate) positions: Vec<Span>,
|
||||
pub(crate) constants: Vec<ConcreteValue>,
|
||||
pub(crate) locals: Vec<Local>,
|
||||
pub(crate) prototypes: Vec<Arc<Chunk>>,
|
||||
pub instructions: Vec<Instruction>,
|
||||
pub positions: Vec<Span>,
|
||||
pub constants: Vec<ConcreteValue>,
|
||||
pub locals: Vec<Local>,
|
||||
pub prototypes: Vec<Arc<Chunk>>,
|
||||
|
||||
pub(crate) boolean_register_count: usize,
|
||||
pub(crate) byte_register_count: usize,
|
||||
pub(crate) character_register_count: usize,
|
||||
pub(crate) float_register_count: usize,
|
||||
pub(crate) integer_register_count: usize,
|
||||
pub(crate) string_register_count: usize,
|
||||
pub(crate) list_register_count: usize,
|
||||
pub(crate) function_register_count: usize,
|
||||
pub(crate) prototype_index: u16,
|
||||
pub boolean_register_count: usize,
|
||||
pub byte_register_count: usize,
|
||||
pub character_register_count: usize,
|
||||
pub float_register_count: usize,
|
||||
pub integer_register_count: usize,
|
||||
pub string_register_count: usize,
|
||||
pub list_register_count: usize,
|
||||
pub function_register_count: usize,
|
||||
pub prototype_index: u16,
|
||||
}
|
||||
|
||||
impl Chunk {
|
||||
|
@ -32,7 +32,7 @@ use std::{mem::replace, sync::Arc};
|
||||
use crate::{
|
||||
Chunk, ConcreteValue, DustError, DustString, FunctionType, Instruction, Lexer, Local,
|
||||
NativeFunction, Operand, Operation, Scope, Span, Token, TokenKind, Type,
|
||||
instruction::{CallNative, Jump, LoadList, Point, Return, TypeCode},
|
||||
instruction::{CallNative, Jump, Point, Return, TypeCode},
|
||||
};
|
||||
|
||||
/// Compiles the input and returns a chunk.
|
||||
@ -591,7 +591,7 @@ impl<'src> Compiler<'src> {
|
||||
if let Token::Boolean(text) = self.current_token {
|
||||
self.advance()?;
|
||||
|
||||
let boolean = text.parse::<bool>().unwrap() as u16;
|
||||
let boolean = text.parse::<bool>().unwrap() as u8;
|
||||
let destination = self.next_boolean_register();
|
||||
let load_encoded =
|
||||
Instruction::load_encoded(destination, boolean, TypeCode::BOOLEAN, false);
|
||||
@ -615,8 +615,7 @@ impl<'src> Compiler<'src> {
|
||||
self.advance()?;
|
||||
|
||||
let byte = u8::from_str_radix(&text[2..], 16)
|
||||
.map_err(|error| CompileError::ParseIntError { error, position })?
|
||||
as u16;
|
||||
.map_err(|error| CompileError::ParseIntError { error, position })?;
|
||||
let destination = self.next_byte_register();
|
||||
let load_encoded = Instruction::load_encoded(destination, byte, TypeCode::BYTE, false);
|
||||
|
||||
@ -1002,10 +1001,9 @@ impl<'src> Compiler<'src> {
|
||||
};
|
||||
let jump = Instruction::jump(1, true);
|
||||
let destination = self.next_boolean_register();
|
||||
let load_true =
|
||||
Instruction::load_encoded(destination, true as u16, TypeCode::BOOLEAN, true);
|
||||
let load_true = Instruction::load_encoded(destination, true as u8, TypeCode::BOOLEAN, true);
|
||||
let load_false =
|
||||
Instruction::load_encoded(destination, false as u16, TypeCode::BOOLEAN, false);
|
||||
Instruction::load_encoded(destination, false as u8, TypeCode::BOOLEAN, false);
|
||||
|
||||
self.emit_instruction(comparison, Type::Boolean, operator_position);
|
||||
self.emit_instruction(jump, Type::None, operator_position);
|
||||
@ -1243,30 +1241,57 @@ impl<'src> Compiler<'src> {
|
||||
self.advance()?;
|
||||
|
||||
let mut item_type = Type::None;
|
||||
let mut start_register = 0;
|
||||
let mut start_register = None;
|
||||
let mut length = 0;
|
||||
|
||||
while !self.allow(Token::RightBracket)? && !self.is_eof() {
|
||||
self.parse_expression()?;
|
||||
|
||||
item_type = self.get_last_instruction_type();
|
||||
start_register = match item_type {
|
||||
Type::Boolean => self.next_boolean_register() - 1,
|
||||
Type::Byte => self.next_byte_register() - 1,
|
||||
Type::Character => self.next_character_register() - 1,
|
||||
Type::Float => self.next_float_register() - 1,
|
||||
Type::Integer => self.next_integer_register() - 1,
|
||||
Type::String => self.next_string_register() - 1,
|
||||
_ => todo!(),
|
||||
};
|
||||
if item_type == Type::None {
|
||||
item_type = self.get_last_instruction_type();
|
||||
}
|
||||
|
||||
if start_register.is_none() {
|
||||
let first_index = match item_type {
|
||||
Type::Boolean => self.next_boolean_register() - 1,
|
||||
Type::Byte => self.next_byte_register() - 1,
|
||||
Type::Character => self.next_character_register() - 1,
|
||||
Type::Float => self.next_float_register() - 1,
|
||||
Type::Integer => self.next_integer_register() - 1,
|
||||
Type::String => self.next_string_register() - 1,
|
||||
Type::List(_) => self.next_list_register() - 1,
|
||||
Type::None => {
|
||||
return Err(CompileError::ExpectedExpression {
|
||||
found: self.previous_token.to_owned(),
|
||||
position: self.previous_position,
|
||||
});
|
||||
}
|
||||
_ => todo!(),
|
||||
};
|
||||
|
||||
start_register = Some(first_index);
|
||||
}
|
||||
|
||||
length += 1;
|
||||
|
||||
self.allow(Token::Comma)?;
|
||||
}
|
||||
|
||||
let destination = self.next_list_register();
|
||||
let end = self.previous_position.1;
|
||||
let load_list = Instruction::load_list(destination, start_register, false);
|
||||
let load_list = Instruction::load_list(
|
||||
destination,
|
||||
item_type.type_code(),
|
||||
start_register.unwrap_or(0),
|
||||
length,
|
||||
false,
|
||||
);
|
||||
|
||||
self.emit_instruction(load_list, Type::List(Box::new(item_type)), Span(start, end));
|
||||
self.emit_instruction(
|
||||
load_list,
|
||||
Type::List(item_type.type_code()),
|
||||
Span(start, end),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -1478,6 +1503,7 @@ impl<'src> Compiler<'src> {
|
||||
Type::Float => self.next_float_register(),
|
||||
Type::Integer => self.next_integer_register(),
|
||||
Type::String => self.next_string_register(),
|
||||
Type::None => 0,
|
||||
_ => todo!(),
|
||||
};
|
||||
let return_type = function.r#type().return_type;
|
||||
|
@ -6,7 +6,7 @@ use super::{InstructionFields, TypeCode};
|
||||
|
||||
pub struct LoadEncoded {
|
||||
pub destination: u16,
|
||||
pub value: u16,
|
||||
pub value: u8,
|
||||
pub value_type: TypeCode,
|
||||
pub jump_next: bool,
|
||||
}
|
||||
@ -15,7 +15,7 @@ impl From<Instruction> for LoadEncoded {
|
||||
fn from(instruction: Instruction) -> Self {
|
||||
LoadEncoded {
|
||||
destination: instruction.a_field(),
|
||||
value: instruction.b_field(),
|
||||
value: instruction.b_field() as u8,
|
||||
value_type: instruction.b_type(),
|
||||
jump_next: instruction.c_field() != 0,
|
||||
}
|
||||
@ -26,7 +26,7 @@ impl From<LoadEncoded> for Instruction {
|
||||
fn from(load_boolean: LoadEncoded) -> Self {
|
||||
let operation = Operation::LOAD_ENCODED;
|
||||
let a_field = load_boolean.destination;
|
||||
let b_field = load_boolean.value;
|
||||
let b_field = load_boolean.value as u16;
|
||||
let b_type = load_boolean.value_type;
|
||||
let c_field = load_boolean.jump_next as u16;
|
||||
|
||||
@ -57,11 +57,7 @@ impl Display for LoadEncoded {
|
||||
|
||||
write!(f, "R_BOOL_{destination} = {boolean}")?
|
||||
}
|
||||
TypeCode::BYTE => {
|
||||
let byte = *value as u8;
|
||||
|
||||
write!(f, "R_BYTE_{destination} = 0x{byte:0X}")?
|
||||
}
|
||||
TypeCode::BYTE => write!(f, "R_BYTE_{destination} = 0x{value:0X}")?,
|
||||
_ => panic!("Invalid type code {value_type} for LoadEncoded instruction"),
|
||||
}
|
||||
|
||||
|
@ -2,11 +2,13 @@ use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use crate::{Instruction, Operation};
|
||||
|
||||
use super::InstructionFields;
|
||||
use super::{InstructionFields, TypeCode};
|
||||
|
||||
pub struct LoadList {
|
||||
pub destination: u16,
|
||||
pub item_type: TypeCode,
|
||||
pub start_register: u16,
|
||||
pub length: u16,
|
||||
pub jump_next: bool,
|
||||
}
|
||||
|
||||
@ -14,11 +16,15 @@ impl From<Instruction> for LoadList {
|
||||
fn from(instruction: Instruction) -> Self {
|
||||
let destination = instruction.a_field();
|
||||
let start_register = instruction.b_field();
|
||||
let jump_next = instruction.c_field() != 0;
|
||||
let item_type = instruction.b_type();
|
||||
let length = instruction.c_field();
|
||||
let jump_next = instruction.d_field();
|
||||
|
||||
LoadList {
|
||||
destination,
|
||||
item_type,
|
||||
start_register,
|
||||
length,
|
||||
jump_next,
|
||||
}
|
||||
}
|
||||
@ -30,7 +36,9 @@ impl From<LoadList> for Instruction {
|
||||
operation: Operation::LOAD_LIST,
|
||||
a_field: load_list.destination,
|
||||
b_field: load_list.start_register,
|
||||
c_field: load_list.jump_next as u16,
|
||||
b_type: load_list.item_type,
|
||||
c_field: load_list.length,
|
||||
d_field: load_list.jump_next,
|
||||
..Default::default()
|
||||
}
|
||||
.build()
|
||||
@ -41,11 +49,24 @@ impl Display for LoadList {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let LoadList {
|
||||
destination,
|
||||
item_type,
|
||||
start_register,
|
||||
length,
|
||||
jump_next,
|
||||
} = self;
|
||||
let type_caps = item_type.to_string().to_uppercase();
|
||||
|
||||
write!(f, "R{destination} = [R{start_register}..R{destination}]")?;
|
||||
write!(f, "R_LIST_{destination} = [")?;
|
||||
|
||||
for (i, register_index) in (*start_register..(start_register + length)).enumerate() {
|
||||
if i > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
|
||||
write!(f, "R_{type_caps}_{register_index}")?;
|
||||
}
|
||||
|
||||
write!(f, "]")?;
|
||||
|
||||
if *jump_next {
|
||||
write!(f, " JUMP +1")?;
|
||||
|
@ -332,7 +332,7 @@ impl Instruction {
|
||||
|
||||
pub fn load_encoded(
|
||||
destination: u16,
|
||||
value: u16,
|
||||
value: u8,
|
||||
value_type: TypeCode,
|
||||
jump_next: bool,
|
||||
) -> Instruction {
|
||||
@ -366,10 +366,18 @@ impl Instruction {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn load_list(destination: u16, start_register: u16, jump_next: bool) -> Instruction {
|
||||
pub fn load_list(
|
||||
destination: u16,
|
||||
item_type: TypeCode,
|
||||
start_register: u16,
|
||||
length: u16,
|
||||
jump_next: bool,
|
||||
) -> Instruction {
|
||||
Instruction::from(LoadList {
|
||||
destination,
|
||||
item_type,
|
||||
start_register,
|
||||
length,
|
||||
jump_next,
|
||||
})
|
||||
}
|
||||
|
@ -51,13 +51,17 @@ impl Display for Return {
|
||||
} = self;
|
||||
|
||||
if *should_return_value {
|
||||
write!(f, "RETURN ")?;
|
||||
|
||||
match *r#type {
|
||||
TypeCode::BOOLEAN => write!(f, "RETURN R_BOOL_{return_register}"),
|
||||
TypeCode::BYTE => write!(f, "RETURN R_BYTE_{return_register}"),
|
||||
TypeCode::CHARACTER => write!(f, "RETURN R_CHAR_{return_register}"),
|
||||
TypeCode::FLOAT => write!(f, "RETURN R_FLOAT_{return_register}"),
|
||||
TypeCode::INTEGER => write!(f, "RETURN R_INT_{return_register}"),
|
||||
TypeCode::STRING => write!(f, "RETURN R_STR_{return_register}"),
|
||||
TypeCode::BOOLEAN => write!(f, "R_BOOL_{return_register}"),
|
||||
TypeCode::BYTE => write!(f, "R_BYTE_{return_register}"),
|
||||
TypeCode::CHARACTER => write!(f, "R_CHAR_{return_register}"),
|
||||
TypeCode::FLOAT => write!(f, "R_FLOAT_{return_register}"),
|
||||
TypeCode::INTEGER => write!(f, "R_INT_{return_register}"),
|
||||
TypeCode::STRING => write!(f, "R_STR_{return_register}"),
|
||||
TypeCode::LIST => write!(f, "R_LIST_{return_register}"),
|
||||
TypeCode::FUNCTION => write!(f, "R_FN_{return_register}"),
|
||||
unsupported => unreachable!("Unsupported return type: {:?}", unsupported),
|
||||
}
|
||||
} else {
|
||||
|
@ -1,6 +1,8 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct TypeCode(pub u8);
|
||||
|
||||
impl TypeCode {
|
||||
@ -28,6 +30,8 @@ impl Display for TypeCode {
|
||||
TypeCode::FLOAT => write!(f, "float"),
|
||||
TypeCode::INTEGER => write!(f, "int"),
|
||||
TypeCode::STRING => write!(f, "str"),
|
||||
TypeCode::LIST => write!(f, "list"),
|
||||
TypeCode::FUNCTION => write!(f, "fn"),
|
||||
_ => self.panic_from_unknown_code(),
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ pub enum Type {
|
||||
concrete_type: Option<Box<Type>>,
|
||||
},
|
||||
Integer,
|
||||
List(Box<Type>),
|
||||
List(TypeCode),
|
||||
Map {
|
||||
pairs: Vec<(u8, Type)>,
|
||||
},
|
||||
@ -45,10 +45,6 @@ impl Type {
|
||||
Type::Function(Box::new(function_type))
|
||||
}
|
||||
|
||||
pub fn list(element_type: Type) -> Self {
|
||||
Type::List(Box::new(element_type))
|
||||
}
|
||||
|
||||
pub fn type_code(&self) -> TypeCode {
|
||||
match self {
|
||||
Type::Boolean => TypeCode::BOOLEAN,
|
||||
@ -58,6 +54,8 @@ impl Type {
|
||||
Type::Integer => TypeCode::INTEGER,
|
||||
Type::None => TypeCode::NONE,
|
||||
Type::String => TypeCode::STRING,
|
||||
Type::List(_) => TypeCode::LIST,
|
||||
Type::Function(_) => TypeCode::FUNCTION,
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
@ -121,7 +119,7 @@ impl Type {
|
||||
}
|
||||
}
|
||||
(Type::List(left_type), Type::List(right_type)) => {
|
||||
if left_type.check(right_type).is_err() {
|
||||
if left_type != right_type {
|
||||
return Err(TypeConflict {
|
||||
actual: other.clone(),
|
||||
expected: self.clone(),
|
||||
@ -307,6 +305,16 @@ impl FunctionType {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FunctionType {
|
||||
fn default() -> Self {
|
||||
FunctionType {
|
||||
type_parameters: Vec::new(),
|
||||
value_parameters: Vec::new(),
|
||||
return_type: Type::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FunctionType {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "fn ")?;
|
||||
|
@ -2,6 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
||||
|
||||
use crate::{
|
||||
Type,
|
||||
instruction::TypeCode,
|
||||
vm::{Pointer, Thread},
|
||||
};
|
||||
|
||||
@ -9,7 +10,7 @@ use super::DustString;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct AbstractList {
|
||||
pub item_type: Type,
|
||||
pub item_type: TypeCode,
|
||||
pub item_pointers: Vec<Pointer>,
|
||||
}
|
||||
|
||||
@ -25,12 +26,12 @@ impl AbstractList {
|
||||
}
|
||||
|
||||
let item_display = match self.item_type {
|
||||
Type::Boolean => thread.get_pointer_to_boolean(pointer).to_string(),
|
||||
Type::Byte => thread.get_pointer_to_byte(pointer).to_string(),
|
||||
Type::Character => thread.get_pointer_to_character(pointer).to_string(),
|
||||
Type::Float => thread.get_pointer_to_float(pointer).to_string(),
|
||||
Type::Integer => thread.get_pointer_to_integer(pointer).to_string(),
|
||||
Type::String => thread.get_pointer_to_string(pointer).to_string(),
|
||||
TypeCode::BOOLEAN => thread.get_pointer_to_boolean(pointer).to_string(),
|
||||
TypeCode::BYTE => thread.get_pointer_to_byte(pointer).to_string(),
|
||||
TypeCode::CHARACTER => thread.get_pointer_to_character(pointer).to_string(),
|
||||
TypeCode::FLOAT => thread.get_pointer_to_float(pointer).to_string(),
|
||||
TypeCode::INTEGER => thread.get_pointer_to_integer(pointer).to_string(),
|
||||
TypeCode::STRING => thread.get_pointer_to_string(pointer).to_string(),
|
||||
_ => todo!(),
|
||||
};
|
||||
|
||||
|
@ -111,9 +111,12 @@ impl ConcreteValue {
|
||||
ConcreteValue::Float(_) => Type::Float,
|
||||
ConcreteValue::Integer(_) => Type::Integer,
|
||||
ConcreteValue::List(list) => {
|
||||
let item_type = list.first().map_or(Type::Any, |item| item.r#type());
|
||||
let item_type = list
|
||||
.first()
|
||||
.map_or(Type::Any, |item| item.r#type())
|
||||
.type_code();
|
||||
|
||||
Type::List(Box::new(item_type))
|
||||
Type::List(item_type)
|
||||
}
|
||||
ConcreteValue::Range(range) => range.r#type(),
|
||||
ConcreteValue::String(_) => Type::String,
|
||||
|
@ -117,9 +117,7 @@ impl Value {
|
||||
pub fn r#type(&self) -> Type {
|
||||
match self {
|
||||
Value::Concrete(concrete_value) => concrete_value.r#type(),
|
||||
Value::AbstractList(AbstractList { item_type, .. }) => {
|
||||
Type::List(Box::new(item_type.clone()))
|
||||
}
|
||||
Value::AbstractList(AbstractList { item_type, .. }) => Type::List(*item_type),
|
||||
Value::Function(Function { r#type, .. }) => Type::Function(Box::new(r#type.clone())),
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
Instruction, Value,
|
||||
AbstractList, ConcreteValue, Instruction, Value,
|
||||
instruction::{InstructionFields, TypeCode},
|
||||
};
|
||||
|
||||
@ -123,7 +123,7 @@ pub fn load_constant(instruction: InstructionFields, thread: &mut Thread) {
|
||||
thread.set_integer_register(destination, register);
|
||||
}
|
||||
TypeCode::STRING => {
|
||||
let register = Register::Pointer(Pointer::Constant(constant_index));
|
||||
let register = Register::Pointer(Pointer::ConstantString(constant_index));
|
||||
|
||||
thread.set_string_register(destination, register);
|
||||
}
|
||||
@ -135,7 +135,42 @@ pub fn load_constant(instruction: InstructionFields, thread: &mut Thread) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_list(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
pub fn load_list(instruction: InstructionFields, thread: &mut Thread) {
|
||||
let destination = instruction.a_field;
|
||||
let start_register = instruction.b_field;
|
||||
let item_type = instruction.b_type;
|
||||
let length = instruction.c_field;
|
||||
let jump_next = instruction.d_field;
|
||||
|
||||
let mut item_pointers = Vec::with_capacity(length as usize);
|
||||
|
||||
for register_index in start_register..start_register + length {
|
||||
let pointer = match item_type {
|
||||
TypeCode::BOOLEAN => Pointer::RegisterBoolean(register_index as usize),
|
||||
TypeCode::BYTE => Pointer::RegisterByte(register_index as usize),
|
||||
TypeCode::CHARACTER => Pointer::RegisterCharacter(register_index as usize),
|
||||
TypeCode::FLOAT => Pointer::RegisterFloat(register_index as usize),
|
||||
TypeCode::INTEGER => Pointer::RegisterInteger(register_index as usize),
|
||||
TypeCode::STRING => Pointer::RegisterString(register_index as usize),
|
||||
TypeCode::LIST => Pointer::RegisterList(register_index as usize),
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
item_pointers.push(pointer);
|
||||
}
|
||||
|
||||
let abstract_list = AbstractList {
|
||||
item_type,
|
||||
item_pointers,
|
||||
};
|
||||
let register = Register::Value(abstract_list);
|
||||
|
||||
thread.set_list_register(destination as usize, register);
|
||||
|
||||
if jump_next {
|
||||
thread.current_frame_mut().ip += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_function(instruction: InstructionFields, thread: &mut Thread) {}
|
||||
|
||||
@ -369,6 +404,17 @@ pub fn r#return(instruction: InstructionFields, thread: &mut Thread) {
|
||||
let return_value = thread.get_string_register(return_register).clone();
|
||||
thread.return_value = Some(Some(Value::string(return_value)));
|
||||
}
|
||||
TypeCode::LIST => {
|
||||
let abstract_list = thread.get_list_register(return_register).clone();
|
||||
let mut concrete_list = Vec::with_capacity(abstract_list.item_pointers.len());
|
||||
|
||||
for pointer in &abstract_list.item_pointers {
|
||||
concrete_list.push(thread.get_value_from_pointer(pointer));
|
||||
}
|
||||
|
||||
thread.return_value =
|
||||
Some(Some(Value::Concrete(ConcreteValue::List(concrete_list))));
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
} else {
|
||||
|
@ -5,7 +5,7 @@ use std::{
|
||||
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
||||
use crate::{Chunk, DustString};
|
||||
use crate::{AbstractList, Chunk, DustString, Function};
|
||||
|
||||
use super::action::ActionSequence;
|
||||
|
||||
@ -55,6 +55,8 @@ pub struct RegisterTable {
|
||||
pub floats: SmallVec<[Register<f64>; 64]>,
|
||||
pub integers: SmallVec<[Register<i64>; 64]>,
|
||||
pub strings: SmallVec<[Register<DustString>; 64]>,
|
||||
pub lists: SmallVec<[Register<AbstractList>; 64]>,
|
||||
pub functions: SmallVec<[Register<Function>; 64]>,
|
||||
}
|
||||
|
||||
impl RegisterTable {
|
||||
@ -66,6 +68,8 @@ impl RegisterTable {
|
||||
floats: smallvec![Register::Empty; 64],
|
||||
integers: smallvec![Register::Empty; 64],
|
||||
strings: smallvec![Register::Empty; 64],
|
||||
lists: smallvec![Register::Empty; 64],
|
||||
functions: smallvec![Register::Empty; 64],
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -88,26 +92,42 @@ impl<T: Display> Display for Register<T> {
|
||||
match self {
|
||||
Self::Empty => write!(f, "empty"),
|
||||
Self::Value(value) => write!(f, "{value}"),
|
||||
Self::Pointer(pointer) => write!(f, "{pointer}"),
|
||||
Self::Pointer(pointer) => write!(f, "Pointer({pointer:?})"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Pointer {
|
||||
Register(usize),
|
||||
Constant(usize),
|
||||
Stack(usize, usize),
|
||||
RegisterBoolean(usize),
|
||||
RegisterByte(usize),
|
||||
RegisterCharacter(usize),
|
||||
RegisterFloat(usize),
|
||||
RegisterInteger(usize),
|
||||
RegisterString(usize),
|
||||
RegisterList(usize),
|
||||
RegisterFunction(usize),
|
||||
ConstantCharacter(usize),
|
||||
ConstantFloat(usize),
|
||||
ConstantInteger(usize),
|
||||
ConstantString(usize),
|
||||
}
|
||||
|
||||
impl Display for Pointer {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Register(index) => write!(f, "PR{}", index),
|
||||
Self::Constant(index) => write!(f, "PC{}", index),
|
||||
Self::Stack(call_index, register_index) => {
|
||||
write!(f, "PS{}R{}", call_index, register_index)
|
||||
}
|
||||
Self::RegisterBoolean(index) => write!(f, "P_R_BOOL_{index}"),
|
||||
Self::RegisterByte(index) => write!(f, "P_R_BYTE_{index}"),
|
||||
Self::RegisterCharacter(index) => write!(f, "P_R_CHAR_{index}"),
|
||||
Self::RegisterFloat(index) => write!(f, "P_R_FLOAT_{index}"),
|
||||
Self::RegisterInteger(index) => write!(f, "P_R_INT_{index}"),
|
||||
Self::RegisterString(index) => write!(f, "P_R_STR_{index}"),
|
||||
Self::RegisterList(index) => write!(f, "P_R_LIST_{index}"),
|
||||
Self::RegisterFunction(index) => write!(f, "P_R_FN_{index}"),
|
||||
Self::ConstantCharacter(index) => write!(f, "P_C_CHAR_{index}"),
|
||||
Self::ConstantFloat(index) => write!(f, "P_C_FLOAT_{index}"),
|
||||
Self::ConstantInteger(index) => write!(f, "P_C_INT_{index}"),
|
||||
Self::ConstantString(index) => write!(f, "P_C_STR_{index}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,10 @@ use std::{collections::HashMap, sync::Arc, thread::JoinHandle};
|
||||
|
||||
use tracing::{info, trace};
|
||||
|
||||
use crate::{Chunk, ConcreteValue, DustString, Span, Value, vm::CallFrame};
|
||||
use crate::{
|
||||
AbstractList, Chunk, ConcreteValue, DustString, Span, Value, instruction::TypeCode,
|
||||
vm::CallFrame,
|
||||
};
|
||||
|
||||
use super::call_frame::{Pointer, Register};
|
||||
|
||||
@ -85,6 +88,76 @@ impl Thread {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_value_from_pointer(&self, pointer: &Pointer) -> ConcreteValue {
|
||||
match pointer {
|
||||
Pointer::RegisterBoolean(register_index) => {
|
||||
let boolean = *self.get_boolean_register(*register_index);
|
||||
|
||||
ConcreteValue::Boolean(boolean)
|
||||
}
|
||||
Pointer::RegisterByte(register_index) => {
|
||||
let byte = *self.get_byte_register(*register_index);
|
||||
|
||||
ConcreteValue::Byte(byte)
|
||||
}
|
||||
Pointer::RegisterCharacter(register_index) => {
|
||||
let character = *self.get_character_register(*register_index);
|
||||
|
||||
ConcreteValue::Character(character)
|
||||
}
|
||||
Pointer::RegisterFloat(register_index) => {
|
||||
let float = *self.get_float_register(*register_index);
|
||||
|
||||
ConcreteValue::Float(float)
|
||||
}
|
||||
Pointer::RegisterInteger(register_index) => {
|
||||
let integer = *self.get_integer_register(*register_index);
|
||||
|
||||
ConcreteValue::Integer(integer)
|
||||
}
|
||||
Pointer::RegisterString(register_index) => {
|
||||
let string = self.get_string_register(*register_index).clone();
|
||||
|
||||
ConcreteValue::String(string)
|
||||
}
|
||||
Pointer::RegisterList(register_index) => {
|
||||
let abstract_list = self.get_list_register(*register_index).clone();
|
||||
let mut concrete_list = Vec::with_capacity(abstract_list.item_pointers.len());
|
||||
|
||||
for pointer in &abstract_list.item_pointers {
|
||||
concrete_list.push(self.get_value_from_pointer(pointer));
|
||||
}
|
||||
|
||||
ConcreteValue::List(concrete_list)
|
||||
}
|
||||
Pointer::RegisterFunction(_) => unimplemented!(),
|
||||
Pointer::ConstantCharacter(constant_index) => {
|
||||
let character = *self.get_constant(*constant_index).as_character().unwrap();
|
||||
|
||||
ConcreteValue::Character(character)
|
||||
}
|
||||
Pointer::ConstantFloat(constant_index) => {
|
||||
let float = *self.get_constant(*constant_index).as_float().unwrap();
|
||||
|
||||
ConcreteValue::Float(float)
|
||||
}
|
||||
Pointer::ConstantInteger(constant_index) => {
|
||||
let integer = *self.get_constant(*constant_index).as_integer().unwrap();
|
||||
|
||||
ConcreteValue::Integer(integer)
|
||||
}
|
||||
Pointer::ConstantString(constant_index) => {
|
||||
let string = self
|
||||
.get_constant(*constant_index)
|
||||
.as_string()
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
ConcreteValue::String(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_boolean_register(&self, register_index: usize) -> &bool {
|
||||
let register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
@ -114,28 +187,8 @@ impl Thread {
|
||||
|
||||
pub fn get_pointer_to_boolean(&self, pointer: &Pointer) -> &bool {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_boolean_register(*register_index),
|
||||
Pointer::Constant(constant_index) => {
|
||||
self.get_constant(*constant_index).as_boolean().unwrap()
|
||||
}
|
||||
Pointer::Stack(call_index, register_index) => {
|
||||
let call_frame = if cfg!(debug_assertions) {
|
||||
self.call_stack.get(*call_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.call_stack.get_unchecked(*call_index) }
|
||||
};
|
||||
let register = if cfg!(debug_assertions) {
|
||||
call_frame.registers.booleans.get(*register_index).unwrap()
|
||||
} else {
|
||||
unsafe { call_frame.registers.booleans.get_unchecked(*register_index) }
|
||||
};
|
||||
|
||||
match register {
|
||||
Register::Value(value) => value,
|
||||
Register::Pointer(pointer) => self.get_pointer_to_boolean(pointer),
|
||||
Register::Empty => panic!("Attempted to get value from empty register"),
|
||||
}
|
||||
}
|
||||
Pointer::RegisterBoolean(register_index) => self.get_boolean_register(*register_index),
|
||||
_ => panic!("Attempted to get boolean from non-boolean pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,28 +244,8 @@ impl Thread {
|
||||
|
||||
pub fn get_pointer_to_byte(&self, pointer: &Pointer) -> &u8 {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_byte_register(*register_index),
|
||||
Pointer::Constant(constant_index) => {
|
||||
self.get_constant(*constant_index).as_byte().unwrap()
|
||||
}
|
||||
Pointer::Stack(call_index, register_index) => {
|
||||
let call_frame = if cfg!(debug_assertions) {
|
||||
self.call_stack.get(*call_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.call_stack.get_unchecked(*call_index) }
|
||||
};
|
||||
let register = if cfg!(debug_assertions) {
|
||||
call_frame.registers.bytes.get(*register_index).unwrap()
|
||||
} else {
|
||||
unsafe { call_frame.registers.bytes.get_unchecked(*register_index) }
|
||||
};
|
||||
|
||||
match register {
|
||||
Register::Value(value) => value,
|
||||
Register::Pointer(pointer) => self.get_pointer_to_byte(pointer),
|
||||
Register::Empty => panic!("Attempted to get value from empty register"),
|
||||
}
|
||||
}
|
||||
Pointer::RegisterByte(register_index) => self.get_byte_register(*register_index),
|
||||
_ => panic!("Attempted to get byte from non-byte pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -268,37 +301,13 @@ impl Thread {
|
||||
|
||||
pub fn get_pointer_to_character(&self, pointer: &Pointer) -> &char {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_character_register(*register_index),
|
||||
Pointer::Constant(constant_index) => {
|
||||
Pointer::RegisterCharacter(register_index) => {
|
||||
self.get_character_register(*register_index)
|
||||
}
|
||||
Pointer::ConstantCharacter(constant_index) => {
|
||||
self.get_constant(*constant_index).as_character().unwrap()
|
||||
}
|
||||
Pointer::Stack(call_index, register_index) => {
|
||||
let call_frame = if cfg!(debug_assertions) {
|
||||
self.call_stack.get(*call_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.call_stack.get_unchecked(*call_index) }
|
||||
};
|
||||
let register = if cfg!(debug_assertions) {
|
||||
call_frame
|
||||
.registers
|
||||
.characters
|
||||
.get(*register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
call_frame
|
||||
.registers
|
||||
.characters
|
||||
.get_unchecked(*register_index)
|
||||
}
|
||||
};
|
||||
|
||||
match register {
|
||||
Register::Value(value) => value,
|
||||
Register::Pointer(pointer) => self.get_pointer_to_character(pointer),
|
||||
Register::Empty => panic!("Attempted to get value from empty register"),
|
||||
}
|
||||
}
|
||||
_ => panic!("Attempted to get character from non-character pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -354,28 +363,11 @@ impl Thread {
|
||||
|
||||
pub fn get_pointer_to_float(&self, pointer: &Pointer) -> &f64 {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_float_register(*register_index),
|
||||
Pointer::Constant(constant_index) => {
|
||||
Pointer::RegisterFloat(register_index) => self.get_float_register(*register_index),
|
||||
Pointer::ConstantFloat(constant_index) => {
|
||||
self.get_constant(*constant_index).as_float().unwrap()
|
||||
}
|
||||
Pointer::Stack(call_index, register_index) => {
|
||||
let call_frame = if cfg!(debug_assertions) {
|
||||
self.call_stack.get(*call_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.call_stack.get_unchecked(*call_index) }
|
||||
};
|
||||
let register = if cfg!(debug_assertions) {
|
||||
call_frame.registers.floats.get(*register_index).unwrap()
|
||||
} else {
|
||||
unsafe { call_frame.registers.floats.get_unchecked(*register_index) }
|
||||
};
|
||||
|
||||
match register {
|
||||
Register::Value(value) => value,
|
||||
Register::Pointer(pointer) => self.get_pointer_to_float(pointer),
|
||||
Register::Empty => panic!("Attempted to get value from empty register"),
|
||||
}
|
||||
}
|
||||
_ => panic!("Attempted to get float from non-float pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -431,28 +423,11 @@ impl Thread {
|
||||
|
||||
pub fn get_pointer_to_integer(&self, pointer: &Pointer) -> &i64 {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_integer_register(*register_index),
|
||||
Pointer::Constant(constant_index) => {
|
||||
Pointer::RegisterInteger(register_index) => self.get_integer_register(*register_index),
|
||||
Pointer::ConstantInteger(constant_index) => {
|
||||
self.get_constant(*constant_index).as_integer().unwrap()
|
||||
}
|
||||
Pointer::Stack(call_index, register_index) => {
|
||||
let call_frame = if cfg!(debug_assertions) {
|
||||
self.call_stack.get(*call_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.call_stack.get_unchecked(*call_index) }
|
||||
};
|
||||
let register = if cfg!(debug_assertions) {
|
||||
call_frame.registers.integers.get(*register_index).unwrap()
|
||||
} else {
|
||||
unsafe { call_frame.registers.integers.get_unchecked(*register_index) }
|
||||
};
|
||||
|
||||
match register {
|
||||
Register::Value(value) => value,
|
||||
Register::Pointer(pointer) => self.get_pointer_to_integer(pointer),
|
||||
Register::Empty => panic!("Attempted to get value from empty register"),
|
||||
}
|
||||
}
|
||||
_ => panic!("Attempted to get integer from non-integer pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -508,28 +483,11 @@ impl Thread {
|
||||
|
||||
pub fn get_pointer_to_string(&self, pointer: &Pointer) -> &DustString {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_string_register(*register_index),
|
||||
Pointer::Constant(constant_index) => {
|
||||
Pointer::RegisterString(register_index) => self.get_string_register(*register_index),
|
||||
Pointer::ConstantString(constant_index) => {
|
||||
self.get_constant(*constant_index).as_string().unwrap()
|
||||
}
|
||||
Pointer::Stack(call_index, register_index) => {
|
||||
let call_frame = if cfg!(debug_assertions) {
|
||||
self.call_stack.get(*call_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.call_stack.get_unchecked(*call_index) }
|
||||
};
|
||||
let register = if cfg!(debug_assertions) {
|
||||
call_frame.registers.strings.get(*register_index).unwrap()
|
||||
} else {
|
||||
unsafe { call_frame.registers.strings.get_unchecked(*register_index) }
|
||||
};
|
||||
|
||||
match register {
|
||||
Register::Value(value) => value,
|
||||
Register::Pointer(pointer) => self.get_pointer_to_string(pointer),
|
||||
Register::Empty => panic!("Attempted to get value from empty register"),
|
||||
}
|
||||
}
|
||||
_ => panic!("Attempted to get string from non-string pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
@ -560,6 +518,67 @@ impl Thread {
|
||||
*old_register = new_register;
|
||||
}
|
||||
|
||||
pub fn get_list_register(&self, register_index: usize) -> &AbstractList {
|
||||
let register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap()
|
||||
.registers
|
||||
.lists
|
||||
.get(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.lists
|
||||
.get_unchecked(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
match register {
|
||||
Register::Value(value) => value,
|
||||
Register::Pointer(pointer) => self.get_pointer_to_list(pointer),
|
||||
Register::Empty => panic!("Attempted to get value from empty register"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pointer_to_list(&self, pointer: &Pointer) -> &AbstractList {
|
||||
match pointer {
|
||||
Pointer::RegisterList(register_index) => self.get_list_register(*register_index),
|
||||
_ => panic!("Attempted to get list from non-list pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_list_register(
|
||||
&mut self,
|
||||
register_index: usize,
|
||||
new_register: Register<AbstractList>,
|
||||
) {
|
||||
let old_register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.registers
|
||||
.lists
|
||||
.get_mut(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.lists
|
||||
.get_unchecked_mut(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
*old_register = new_register;
|
||||
}
|
||||
|
||||
pub fn get_constant(&self, constant_index: usize) -> &ConcreteValue {
|
||||
if cfg!(debug_assertions) {
|
||||
self.chunk.constants.get(constant_index).unwrap()
|
||||
|
@ -1,81 +0,0 @@
|
||||
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
|
||||
})
|
||||
);
|
||||
}
|
@ -1,129 +0,0 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn constant() {
|
||||
let source = "42";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Integer
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(0, 2)),
|
||||
(Instruction::r#return(true), Span(2, 2))
|
||||
],
|
||||
vec![ConcreteValue::Integer(42)],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(42))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
let source = "";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::None
|
||||
},
|
||||
vec![(Instruction::r#return(false), Span(0, 0))],
|
||||
vec![],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
assert_eq!(run(source), Ok(None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parentheses_precedence() {
|
||||
let source = "(1 + 2) * 3";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Integer
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::add(0, Operand::Constant(0), Operand::Constant(1)),
|
||||
Span(3, 4)
|
||||
),
|
||||
(
|
||||
Instruction::multiply(1, Operand::Register(0), Operand::Constant(2)),
|
||||
Span(8, 9)
|
||||
),
|
||||
(Instruction::r#return(true), Span(11, 11)),
|
||||
],
|
||||
vec![
|
||||
ConcreteValue::Integer(1),
|
||||
ConcreteValue::Integer(2),
|
||||
ConcreteValue::Integer(3)
|
||||
],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
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: Type::Integer,
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::add(0, Operand::Constant(0), Operand::Constant(1)),
|
||||
Span(2, 3)
|
||||
),
|
||||
(
|
||||
Instruction::multiply(1, Operand::Constant(2), Operand::Constant(3)),
|
||||
Span(10, 11)
|
||||
),
|
||||
(
|
||||
Instruction::divide(2, Operand::Register(1), Operand::Constant(4)),
|
||||
Span(14, 15)
|
||||
),
|
||||
(
|
||||
Instruction::subtract(3, Operand::Register(0), Operand::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))));
|
||||
}
|
@ -1,169 +0,0 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn equal() {
|
||||
let source = "1 == 2";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Boolean
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::equal(0, true, Operand::Constant(0), Operand::Constant(1)),
|
||||
Span(2, 4)
|
||||
),
|
||||
(Instruction::r#return(true), Span(6, 6)),
|
||||
],
|
||||
vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)],
|
||||
vec![]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Boolean(false))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn greater() {
|
||||
let source = "1 > 2";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Boolean
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::less_equal(0, false, Operand::Constant(0), Operand::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::Boolean(false))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn greater_than_or_equal() {
|
||||
let source = "1 >= 2";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Boolean
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::less(0, false, Operand::Constant(0), Operand::Constant(1)),
|
||||
Span(2, 4)
|
||||
),
|
||||
(Instruction::r#return(true), Span(6, 6)),
|
||||
],
|
||||
vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)],
|
||||
vec![]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Boolean(false))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn less_than() {
|
||||
let source = "1 < 2";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Boolean
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::less(0, true, Operand::Constant(0), Operand::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::Boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn less_than_or_equal() {
|
||||
let source = "1 <= 2";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Boolean
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::less_equal(0, true, Operand::Constant(0), Operand::Constant(1)),
|
||||
Span(2, 4)
|
||||
),
|
||||
(Instruction::r#return(true), Span(6, 6)),
|
||||
],
|
||||
vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)],
|
||||
vec![]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_equal() {
|
||||
let source = "1 != 2";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Boolean
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::equal(0, false, Operand::Constant(0), Operand::Constant(1)),
|
||||
Span(2, 4)
|
||||
),
|
||||
(Instruction::r#return(true), Span(6, 6)),
|
||||
],
|
||||
vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)],
|
||||
vec![]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Boolean(true))));
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
use dust_lang::*;
|
||||
use smallvec::smallvec;
|
||||
|
||||
#[test]
|
||||
fn function() {
|
||||
let source = "fn(a: int, b: int) -> int { a + b }";
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Ok(Some(ConcreteValue::function(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::function(FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: Some(smallvec![(0, Type::Integer), (1, Type::Integer)]),
|
||||
return_type: Type::Integer,
|
||||
})
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::add(2, Operand::Register(0), Operand::Register(1)),
|
||||
Span(30, 31)
|
||||
),
|
||||
(Instruction::r#return(true), Span(34, 35)),
|
||||
],
|
||||
vec![ConcreteValue::string("a"), ConcreteValue::string("b"),],
|
||||
vec![
|
||||
Local::new(0, 0, false, Scope::default()),
|
||||
Local::new(1, 1, false, Scope::default())
|
||||
]
|
||||
))))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_call() {
|
||||
let source = "fn(a: int, b: int) -> int { a + b }(1, 2)";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Integer
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(0, 35)),
|
||||
(Instruction::load_constant(1, 1, false), Span(36, 37)),
|
||||
(Instruction::load_constant(2, 2, false), Span(39, 40)),
|
||||
(Instruction::call(3, Operand::Constant(0), 2), Span(35, 41)),
|
||||
(Instruction::r#return(true), Span(41, 41)),
|
||||
],
|
||||
vec![
|
||||
ConcreteValue::function(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: Some(smallvec![(0, Type::Integer), (1, Type::Integer)]),
|
||||
return_type: Type::Integer
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::add(2, Operand::Register(0), Operand::Register(1)),
|
||||
Span(30, 31)
|
||||
),
|
||||
(Instruction::r#return(true), Span(34, 35)),
|
||||
],
|
||||
vec![ConcreteValue::string("a"), ConcreteValue::string("b"),],
|
||||
vec![
|
||||
Local::new(0, 0, false, Scope::default()),
|
||||
Local::new(1, 1, false, Scope::default())
|
||||
]
|
||||
)),
|
||||
ConcreteValue::Integer(1),
|
||||
ConcreteValue::Integer(2)
|
||||
],
|
||||
vec![]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(3))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_declaration() {
|
||||
let source = "fn add (a: int, b: int) -> int { a + b }";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::None
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(0, 40)),
|
||||
(Instruction::r#return(false), Span(40, 40))
|
||||
],
|
||||
vec![
|
||||
ConcreteValue::function(Chunk::with_data(
|
||||
Some("add".into()),
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: Some(smallvec![(0, Type::Integer), (1, Type::Integer)]),
|
||||
return_type: Type::Integer
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::add(2, Operand::Register(0), Operand::Register(1)),
|
||||
Span(35, 36)
|
||||
),
|
||||
(Instruction::r#return(true), Span(39, 40)),
|
||||
],
|
||||
vec![ConcreteValue::string("a"), ConcreteValue::string("b")],
|
||||
vec![
|
||||
Local::new(0, 0, false, Scope::default()),
|
||||
Local::new(1, 1, false, Scope::default())
|
||||
]
|
||||
)),
|
||||
ConcreteValue::string("add"),
|
||||
],
|
||||
vec![Local::new(1, 0, false, Scope::default(),),],
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(None));
|
||||
}
|
@ -1,159 +0,0 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn empty_list() {
|
||||
let source = "[]";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::List(Box::new(Type::Any)),
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_list(0, 0), Span(0, 2)),
|
||||
(Instruction::r#return(true), Span(2, 2)),
|
||||
],
|
||||
vec![],
|
||||
vec![]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::list([]))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list() {
|
||||
let source = "[1, 2, 3]";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::List(Box::new(Type::Integer)),
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(1, 2)),
|
||||
(Instruction::load_constant(1, 1, false), Span(4, 5)),
|
||||
(Instruction::load_constant(2, 2, false), Span(7, 8)),
|
||||
(Instruction::load_list(3, 0), Span(0, 9)),
|
||||
(Instruction::r#return(true), Span(9, 9)),
|
||||
],
|
||||
vec![
|
||||
ConcreteValue::Integer(1),
|
||||
ConcreteValue::Integer(2),
|
||||
ConcreteValue::Integer(3)
|
||||
],
|
||||
vec![]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Ok(Some(ConcreteValue::list([
|
||||
ConcreteValue::Integer(1),
|
||||
ConcreteValue::Integer(2),
|
||||
ConcreteValue::Integer(3)
|
||||
])))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list_with_complex_expression() {
|
||||
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: Type::List(Box::new(Type::Integer)),
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(1, 2)),
|
||||
(
|
||||
Instruction::add(1, Operand::Constant(1), Operand::Constant(2)),
|
||||
Span(6, 7)
|
||||
),
|
||||
(
|
||||
Instruction::multiply(2, Operand::Constant(3), Operand::Constant(4)),
|
||||
Span(14, 15)
|
||||
),
|
||||
(
|
||||
Instruction::subtract(3, Operand::Register(1), Operand::Register(2)),
|
||||
Span(10, 11)
|
||||
),
|
||||
(Instruction::close(1, 3), Span(17, 18)),
|
||||
(Instruction::load_list(4, 0), Span(0, 18)),
|
||||
(Instruction::r#return(true), Span(18, 18)),
|
||||
],
|
||||
vec![
|
||||
ConcreteValue::Integer(1),
|
||||
ConcreteValue::Integer(2),
|
||||
ConcreteValue::Integer(3),
|
||||
ConcreteValue::Integer(4),
|
||||
ConcreteValue::Integer(5)
|
||||
],
|
||||
vec![]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Ok(Some(ConcreteValue::list([
|
||||
ConcreteValue::Integer(1),
|
||||
ConcreteValue::Integer(-15)
|
||||
])))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list_with_simple_expression() {
|
||||
let source = "[1, 2 + 3, 4]";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::List(Box::new(Type::Integer)),
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(1, 2)),
|
||||
(
|
||||
Instruction::add(1, Operand::Constant(1), Operand::Constant(2)),
|
||||
Span(6, 7)
|
||||
),
|
||||
(Instruction::load_constant(2, 3, false), Span(11, 12)),
|
||||
(Instruction::load_list(3, 0), Span(0, 13)),
|
||||
(Instruction::r#return(true), Span(13, 13)),
|
||||
],
|
||||
vec![
|
||||
ConcreteValue::Integer(1),
|
||||
ConcreteValue::Integer(2),
|
||||
ConcreteValue::Integer(3),
|
||||
ConcreteValue::Integer(4),
|
||||
],
|
||||
vec![]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Ok(Some(ConcreteValue::list([
|
||||
ConcreteValue::Integer(1),
|
||||
ConcreteValue::Integer(5),
|
||||
ConcreteValue::Integer(4),
|
||||
])))
|
||||
);
|
||||
}
|
@ -1,146 +0,0 @@
|
||||
use dust_lang::*;
|
||||
use smallvec::smallvec;
|
||||
|
||||
#[test]
|
||||
fn true_and_true() {
|
||||
let source = "true && true";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Boolean,
|
||||
},
|
||||
smallvec![
|
||||
Instruction::load_encoded(0, true, false),
|
||||
Instruction::test(0, true),
|
||||
Instruction::jump(1, true),
|
||||
Instruction::load_encoded(1, true, false),
|
||||
Instruction::r#return(true),
|
||||
],
|
||||
smallvec![
|
||||
Span(0, 4),
|
||||
Span(5, 7),
|
||||
Span(5, 7),
|
||||
Span(8, 12),
|
||||
Span(12, 12),
|
||||
],
|
||||
smallvec![],
|
||||
smallvec![],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::boolean(true))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn false_and_false() {
|
||||
let source = "false && false";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Boolean,
|
||||
},
|
||||
smallvec![
|
||||
Instruction::load_encoded(0, false, false),
|
||||
Instruction::test(0, true),
|
||||
Instruction::jump(1, true),
|
||||
Instruction::load_encoded(1, false, false),
|
||||
Instruction::r#return(true),
|
||||
],
|
||||
smallvec![
|
||||
Span(0, 5),
|
||||
Span(6, 8),
|
||||
Span(6, 8),
|
||||
Span(9, 14),
|
||||
Span(14, 14),
|
||||
],
|
||||
smallvec![],
|
||||
smallvec![],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::boolean(false))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn false_and_true() {
|
||||
let source = "false && true";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Boolean,
|
||||
},
|
||||
smallvec![
|
||||
Instruction::load_encoded(0, false, false),
|
||||
Instruction::test(0, true),
|
||||
Instruction::jump(1, true),
|
||||
Instruction::load_encoded(1, true, false),
|
||||
Instruction::r#return(true),
|
||||
],
|
||||
smallvec![
|
||||
Span(0, 5),
|
||||
Span(6, 8),
|
||||
Span(6, 8),
|
||||
Span(9, 13),
|
||||
Span(13, 13)
|
||||
],
|
||||
smallvec![],
|
||||
smallvec![],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::boolean(false))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn true_and_false() {
|
||||
let source = "true && false";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Boolean,
|
||||
},
|
||||
smallvec![
|
||||
Instruction::load_encoded(0, true, false),
|
||||
Instruction::test(0, true),
|
||||
Instruction::jump(1, true),
|
||||
Instruction::load_encoded(1, false, false),
|
||||
Instruction::r#return(true),
|
||||
],
|
||||
smallvec![
|
||||
Span(0, 4),
|
||||
Span(5, 7),
|
||||
Span(5, 7),
|
||||
Span(8, 13),
|
||||
Span(13, 13)
|
||||
],
|
||||
smallvec![],
|
||||
smallvec![],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::boolean(false))));
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
use dust_lang::*;
|
||||
use smallvec::smallvec;
|
||||
|
||||
#[test]
|
||||
fn true_and_true_and_true() {
|
||||
let source = "true && true && true";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Boolean,
|
||||
},
|
||||
smallvec![
|
||||
Instruction::load_encoded(0, true, false),
|
||||
Instruction::test(0, true),
|
||||
Instruction::jump(1, true),
|
||||
Instruction::load_encoded(1, true, false),
|
||||
Instruction::test(1, true),
|
||||
Instruction::jump(1, true),
|
||||
Instruction::load_encoded(2, true, false),
|
||||
Instruction::r#return(true),
|
||||
],
|
||||
smallvec![
|
||||
Span(0, 4),
|
||||
Span(5, 7),
|
||||
Span(5, 7),
|
||||
Span(8, 12),
|
||||
Span(13, 15),
|
||||
Span(13, 15),
|
||||
Span(16, 20),
|
||||
Span(20, 20)
|
||||
],
|
||||
smallvec![],
|
||||
smallvec![],
|
||||
vec![],
|
||||
))
|
||||
);
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
use dust_lang::*;
|
||||
use smallvec::smallvec;
|
||||
|
||||
#[test]
|
||||
fn true_or_false() {
|
||||
let source = "true || false";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Boolean,
|
||||
},
|
||||
smallvec![
|
||||
Instruction::load_encoded(0, true, false),
|
||||
Instruction::test(0, false),
|
||||
Instruction::jump(1, true),
|
||||
Instruction::load_encoded(1, false, false),
|
||||
Instruction::r#return(true),
|
||||
],
|
||||
smallvec![
|
||||
Span(0, 4),
|
||||
Span(5, 7),
|
||||
Span(5, 7),
|
||||
Span(8, 13),
|
||||
Span(13, 13),
|
||||
],
|
||||
smallvec![],
|
||||
smallvec![],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::boolean(true))));
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn r#while() {
|
||||
let source = "let mut x = 0; while x < 5 { x = x + 1 } x";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Integer,
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(12, 13)),
|
||||
(
|
||||
Instruction::less(0, true, Operand::Register(0), Operand::Constant(2)),
|
||||
Span(23, 24)
|
||||
),
|
||||
(Instruction::jump(2, true), Span(41, 42)),
|
||||
(
|
||||
Instruction::add(0, Operand::Register(0), Operand::Constant(3)),
|
||||
Span(35, 36)
|
||||
),
|
||||
(Instruction::jump(3, false), Span(41, 42)),
|
||||
(Instruction::get_local(1, 0), Span(41, 42)),
|
||||
(Instruction::r#return(true), Span(42, 42)),
|
||||
],
|
||||
vec![
|
||||
ConcreteValue::Integer(0),
|
||||
ConcreteValue::string("x"),
|
||||
ConcreteValue::Integer(5),
|
||||
ConcreteValue::Integer(1),
|
||||
],
|
||||
vec![Local::new(1, 0, true, Scope::default())]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(5))));
|
||||
}
|
@ -1,270 +0,0 @@
|
||||
use dust_lang::*;
|
||||
use smallvec::smallvec;
|
||||
|
||||
#[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: Type::Byte,
|
||||
},
|
||||
smallvec![
|
||||
Instruction::add(0, Argument::Constant(0), Argument::Constant(1)),
|
||||
Instruction::r#return(true),
|
||||
],
|
||||
smallvec![Span(5, 6), Span(11, 11),],
|
||||
smallvec![Value::byte(0xfe), Value::byte(0x01)],
|
||||
smallvec![],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::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: Type::Byte,
|
||||
},
|
||||
smallvec![
|
||||
Instruction::add(0, Argument::Constant(0), Argument::Constant(1)),
|
||||
Instruction::r#return(true),
|
||||
],
|
||||
smallvec![Span(5, 6), Span(11, 11)],
|
||||
smallvec![Value::byte(0xff), Value::byte(0x01)],
|
||||
smallvec![],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::byte(0xff))));
|
||||
}
|
||||
|
||||
#[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: Type::String,
|
||||
},
|
||||
smallvec![
|
||||
Instruction::add(0, Argument::Constant(0), Argument::Constant(1)),
|
||||
Instruction::r#return(true)
|
||||
],
|
||||
smallvec![Span(4, 5), Span(11, 11)],
|
||||
smallvec![Value::character('a'), Value::character('b')],
|
||||
smallvec![],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::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: Type::String,
|
||||
},
|
||||
smallvec![
|
||||
Instruction::add(0, Argument::Constant(0), Argument::Constant(1)),
|
||||
Instruction::r#return(true),
|
||||
],
|
||||
smallvec![Span(4, 5), Span(9, 9),],
|
||||
smallvec![Value::character('a'), Value::string("b")],
|
||||
smallvec![],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::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: Type::Float,
|
||||
},
|
||||
smallvec![
|
||||
Instruction::add(0, Argument::Constant(0), Argument::Constant(1)),
|
||||
Instruction::r#return(true),
|
||||
],
|
||||
smallvec![Span(4, 5), Span(9, 9),],
|
||||
smallvec![Value::float(1.0), Value::float(2.0)],
|
||||
smallvec![],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::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: Type::Float,
|
||||
},
|
||||
smallvec![
|
||||
Instruction::add(0, Argument::Constant(0), Argument::Constant(1)),
|
||||
Instruction::r#return(true),
|
||||
],
|
||||
smallvec![Span(24, 25), Span(36, 36),],
|
||||
smallvec![Value::float(f64::MAX), Value::float(0.00000001)],
|
||||
smallvec![],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::float(f64::MAX))));
|
||||
}
|
||||
|
||||
#[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: Type::Integer,
|
||||
},
|
||||
smallvec![
|
||||
Instruction::add(0, Argument::Constant(0), Argument::Constant(1)),
|
||||
Instruction::r#return(true)
|
||||
],
|
||||
smallvec![Span(2, 3), Span(5, 5),],
|
||||
smallvec![Value::integer(1), Value::integer(2)],
|
||||
smallvec![],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::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: Type::Integer,
|
||||
},
|
||||
smallvec![
|
||||
Instruction::add(0, Argument::Constant(0), Argument::Constant(1)),
|
||||
Instruction::r#return(true)
|
||||
],
|
||||
smallvec![Span(20, 21), Span(23, 23),],
|
||||
smallvec![Value::integer(i64::MAX), Value::integer(1)],
|
||||
smallvec![],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(i64::MAX))));
|
||||
}
|
||||
|
||||
#[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: Type::String,
|
||||
},
|
||||
smallvec![
|
||||
Instruction::add(0, Argument::Constant(0), Argument::Constant(1)),
|
||||
Instruction::r#return(true),
|
||||
],
|
||||
smallvec![Span(10, 11), Span(20, 20)],
|
||||
smallvec![Value::string("Hello, "), Value::string("world!")],
|
||||
smallvec![],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#[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: Type::String,
|
||||
},
|
||||
smallvec![
|
||||
Instruction::add(0, Argument::Constant(0), Argument::Constant(1)),
|
||||
Instruction::r#return(true),
|
||||
],
|
||||
smallvec![Span(4, 5), Span(9, 9),],
|
||||
smallvec![Value::string("a"), Value::character('b')],
|
||||
smallvec![],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::string("ab"))));
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
use dust_lang::*;
|
||||
use smallvec::smallvec;
|
||||
|
||||
#[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: Type::Integer,
|
||||
},
|
||||
smallvec![
|
||||
Instruction::load_constant(0, 0, false),
|
||||
Instruction::add(0, Argument::Register(0), Argument::Constant(2)),
|
||||
Instruction::get_local(1, 0),
|
||||
Instruction::r#return(true)
|
||||
],
|
||||
smallvec![Span(12, 13), Span(17, 19), Span(23, 24), Span(24, 24)],
|
||||
smallvec![Value::integer(1), Value::string("a"), Value::integer(2)],
|
||||
smallvec![Local::new(1, 0, true, Scope::default())],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(3))));
|
||||
}
|
@ -1,405 +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: 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: 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_byte_and_character() {
|
||||
let source = "0xff + 'a'";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Byte,
|
||||
right_type: Type::Character,
|
||||
position: Span(0, 10)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_byte_and_integer() {
|
||||
let source = "0xff + 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Byte,
|
||||
right_type: Type::Integer,
|
||||
position: Span(0, 8)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_byte_and_string() {
|
||||
let source = "0xff + \"hello\"";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Byte,
|
||||
right_type: Type::String,
|
||||
position: Span(0, 14)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_character_and_byte() {
|
||||
let source = "'a' + 0xff";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Character,
|
||||
right_type: Type::Byte,
|
||||
position: Span(0, 10)
|
||||
},
|
||||
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,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_float_and_byte() {
|
||||
let source = "1.0 + 0xff";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Float,
|
||||
right_type: Type::Byte,
|
||||
position: Span(0, 10)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[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_byte() {
|
||||
let source = "1 + 0xff";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Integer,
|
||||
right_type: Type::Byte,
|
||||
position: Span(0, 8)
|
||||
},
|
||||
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_byte() {
|
||||
let source = "\"hello\" + 0xff";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::String,
|
||||
right_type: Type::Byte,
|
||||
position: Span(0, 14)
|
||||
},
|
||||
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,
|
||||
})
|
||||
);
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
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: Type::Byte,
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::divide(0, Operand::Constant(0), Operand::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]
|
||||
fn divide_floats() {
|
||||
let source = "2.0 / 2.0";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Float,
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::divide(0, Operand::Constant(0), Operand::Constant(0)),
|
||||
Span(4, 5)
|
||||
),
|
||||
(Instruction::r#return(true), Span(9, 9))
|
||||
],
|
||||
vec![ConcreteValue::Float(2.0)],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Float(1.0))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn divide_integers() {
|
||||
let source = "2 / 2";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Integer,
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::divide(0, Operand::Constant(0), Operand::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))));
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
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: Type::Integer,
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(12, 13)),
|
||||
(
|
||||
Instruction::divide(0, Operand::Register(0), Operand::Constant(0)),
|
||||
Span(17, 19)
|
||||
),
|
||||
(Instruction::get_local(1, 0), Span(23, 24)),
|
||||
(Instruction::r#return(true), Span(24, 24))
|
||||
],
|
||||
vec![ConcreteValue::Integer(2), ConcreteValue::string("a")],
|
||||
vec![Local::new(1, 0, true, Scope::default())]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(1))));
|
||||
}
|
@ -1,229 +0,0 @@
|
||||
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";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::Boolean,
|
||||
position: Span(4, 8)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn divide_character_left() {
|
||||
let source = "'a' / 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(0, 3)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn divide_character_right() {
|
||||
let source = "1 / 'a'";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(4, 7)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn divide_float_and_character() {
|
||||
let source = "1.0 / 'a'";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(6, 9)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn divide_float_and_integer() {
|
||||
let source = "1.0 / 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotDivideArguments {
|
||||
left_type: Type::Float,
|
||||
right_type: Type::Integer,
|
||||
position: Span(0, 7)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn divide_function_left() {
|
||||
let source = "fn(){} / 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::function(FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::None
|
||||
}),
|
||||
position: Span(0, 6)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn divide_function_right() {
|
||||
let source = "1 / fn(){}";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::function(FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::None
|
||||
}),
|
||||
position: Span(4, 10)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn divide_integer_and_float() {
|
||||
let source = "1 / 1.0";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotDivideArguments {
|
||||
left_type: Type::Integer,
|
||||
right_type: Type::Float,
|
||||
position: Span(0, 7)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn divide_list_left() {
|
||||
let source = "[1, 2] / 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::List(Box::new(Type::Integer)),
|
||||
position: Span(0, 6)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn divide_list_right() {
|
||||
let source = "1 / [1, 2]";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
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 divide_string_left() {
|
||||
let source = "\"hello\" / 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::String,
|
||||
position: Span(0, 7)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn divide_string_right() {
|
||||
let source = "1 / \"hello\"";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::String,
|
||||
position: Span(4, 11)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn modulo_floats() {
|
||||
let source = "2.0 % 2.0";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Float,
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::modulo(0, Operand::Constant(0), Operand::Constant(0)),
|
||||
Span(4, 5)
|
||||
),
|
||||
(Instruction::r#return(true), Span(9, 9))
|
||||
],
|
||||
vec![ConcreteValue::Float(2.0)],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Float(0.0))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modulo_integers() {
|
||||
let source = "2 % 2";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Integer,
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::modulo(0, Operand::Constant(0), Operand::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(0))));
|
||||
}
|
@ -1,229 +0,0 @@
|
||||
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: 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: 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,
|
||||
})
|
||||
);
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn multiply_floats() {
|
||||
let source = "2.0 * 2.0";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Float
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::multiply(0, Operand::Constant(0), Operand::Constant(0)),
|
||||
Span(4, 5)
|
||||
),
|
||||
(Instruction::r#return(true), Span(9, 9)),
|
||||
],
|
||||
vec![ConcreteValue::Float(2.0)],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Float(4.0))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiply_integers() {
|
||||
let source = "1 * 2";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Integer,
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::multiply(0, Operand::Constant(0), Operand::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))));
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
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: Type::Integer,
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(12, 13)),
|
||||
(
|
||||
Instruction::multiply(0, Operand::Register(0), Operand::Constant(2)),
|
||||
Span(17, 19)
|
||||
),
|
||||
(Instruction::get_local(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, 0, true, Scope::default())]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(6))));
|
||||
}
|
@ -1,229 +0,0 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn multiply_boolean_left() {
|
||||
let source = "true * 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::Boolean,
|
||||
position: Span(0, 4)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiply_boolean_right() {
|
||||
let source = "1 * true";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::Boolean,
|
||||
position: Span(4, 8)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiply_character_left() {
|
||||
let source = "'a' * 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(0, 3)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiply_character_right() {
|
||||
let source = "1 * 'a'";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(4, 7)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiply_float_and_character() {
|
||||
let source = "1.0 * 'a'";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(6, 9)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiply_float_and_integer() {
|
||||
let source = "1.0 * 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotMultiplyArguments {
|
||||
left_type: Type::Float,
|
||||
right_type: Type::Integer,
|
||||
position: Span(0, 7)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiply_function_left() {
|
||||
let source = "fn(){} * 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::function(FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::None
|
||||
}),
|
||||
position: Span(0, 6)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiply_function_right() {
|
||||
let source = "1 * fn(){}";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::function(FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::None
|
||||
}),
|
||||
position: Span(4, 10)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiply_integer_and_float() {
|
||||
let source = "1 * 1.0";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotMultiplyArguments {
|
||||
left_type: Type::Integer,
|
||||
right_type: Type::Float,
|
||||
position: Span(0, 7)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiply_list_left() {
|
||||
let source = "[1, 2] * 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::List(Box::new(Type::Integer)),
|
||||
position: Span(0, 6)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiply_list_right() {
|
||||
let source = "1 * [1, 2]";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
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 multiply_string_left() {
|
||||
let source = "\"hello\" * 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::String,
|
||||
position: Span(0, 7)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiply_string_right() {
|
||||
let source = "1 * \"hello\"";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::String,
|
||||
position: Span(4, 11)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
@ -1,116 +0,0 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn subtract_floats() {
|
||||
let source = "2.0 - 2.0";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Float,
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::subtract(0, Operand::Constant(0), Operand::Constant(0)),
|
||||
Span(4, 5)
|
||||
),
|
||||
(Instruction::r#return(true), Span(9, 9)),
|
||||
],
|
||||
vec![ConcreteValue::Float(2.0)],
|
||||
vec![]
|
||||
))
|
||||
);
|
||||
|
||||
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: Type::Float,
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::subtract(0, Operand::Constant(0), Operand::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]
|
||||
fn subtract_integers() {
|
||||
let source = "1 - 2";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Integer,
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::subtract(0, Operand::Constant(0), Operand::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_integers_saturate() {
|
||||
let source = "-9223372036854775808 - 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Integer,
|
||||
},
|
||||
vec![
|
||||
(
|
||||
Instruction::subtract(0, Operand::Constant(0), Operand::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))));
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
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: Type::Integer,
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(12, 14)),
|
||||
(
|
||||
Instruction::subtract(0, Operand::Register(0), Operand::Constant(2)),
|
||||
Span(18, 20)
|
||||
),
|
||||
(Instruction::get_local(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, 0, true, Scope::default())]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(40))));
|
||||
}
|
@ -1,229 +0,0 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn subtract_boolean_left() {
|
||||
let source = "true - 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::Boolean,
|
||||
position: Span(0, 4)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtract_boolean_right() {
|
||||
let source = "1 - true";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::Boolean,
|
||||
position: Span(4, 8)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtract_character_left() {
|
||||
let source = "'a' - 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(0, 3)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtract_character_right() {
|
||||
let source = "1 - 'a'";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(4, 7)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtract_float_and_character() {
|
||||
let source = "1.0 - 'a'";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(6, 9)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtract_float_and_integer() {
|
||||
let source = "1.0 - 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotSubtractArguments {
|
||||
left_type: Type::Float,
|
||||
right_type: Type::Integer,
|
||||
position: Span(0, 7)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtract_function_left() {
|
||||
let source = "fn(){} - 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::function(FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::None
|
||||
}),
|
||||
position: Span(0, 6)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtract_function_right() {
|
||||
let source = "1 - fn(){}";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::function(FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::None
|
||||
}),
|
||||
position: Span(4, 10)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtract_integer_and_float() {
|
||||
let source = "1 - 1.0";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotSubtractArguments {
|
||||
left_type: Type::Integer,
|
||||
right_type: Type::Float,
|
||||
position: Span(0, 7)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtract_list_left() {
|
||||
let source = "[1, 2] - 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::List(Box::new(Type::Integer)),
|
||||
position: Span(0, 6)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtract_list_right() {
|
||||
let source = "1 - [1, 2]";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
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 subtract_string_left() {
|
||||
let source = "\"hello\" - 1";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::String,
|
||||
position: Span(0, 7)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtract_string_right() {
|
||||
let source = "1 - \"hello\"";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::String,
|
||||
position: Span(4, 11)
|
||||
},
|
||||
source,
|
||||
})
|
||||
);
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn panic() {
|
||||
let source = "panic(\"Goodbye world!\", 42)";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::None,
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(6, 22)),
|
||||
(Instruction::load_constant(1, 1, false), Span(24, 26)),
|
||||
(
|
||||
Instruction::call_native(2, NativeFunction::Panic, 2),
|
||||
Span(0, 27)
|
||||
),
|
||||
(Instruction::r#return(false), Span(27, 27))
|
||||
],
|
||||
vec![
|
||||
ConcreteValue::string("Goodbye world!"),
|
||||
ConcreteValue::Integer(42)
|
||||
],
|
||||
vec![]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Err(DustError::Runtime {
|
||||
error: VmError::NativeFunction(NativeFunctionError::Panic {
|
||||
message: Some("Goodbye world! 42".to_string()),
|
||||
position: Span(0, 27)
|
||||
}),
|
||||
source
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_string() {
|
||||
let source = "to_string(42)";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::String,
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(10, 12)),
|
||||
(
|
||||
Instruction::call_native(1, NativeFunction::ToString, 1),
|
||||
Span(0, 13)
|
||||
),
|
||||
(Instruction::r#return(true), Span(13, 13))
|
||||
],
|
||||
vec![ConcreteValue::Integer(42)],
|
||||
vec![]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::string("42"))))
|
||||
}
|
@ -1,239 +0,0 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn allow_access_to_parent_scope() {
|
||||
let source = r#"
|
||||
let x = 1;
|
||||
{
|
||||
x
|
||||
}
|
||||
"#;
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(1))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_scope() {
|
||||
let source = "
|
||||
let a = 0;
|
||||
{
|
||||
let b = 42;
|
||||
{
|
||||
let c = 1;
|
||||
}
|
||||
let d = 2;
|
||||
}
|
||||
let e = 1;
|
||||
";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::None,
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(17, 18)),
|
||||
(Instruction::load_constant(1, 2, false), Span(50, 52)),
|
||||
(Instruction::load_constant(2, 4, false), Span(92, 93)),
|
||||
(Instruction::load_constant(3, 6, false), Span(129, 130)),
|
||||
(Instruction::load_constant(4, 4, false), Span(158, 159)),
|
||||
(Instruction::r#return(false), Span(165, 165))
|
||||
],
|
||||
vec![
|
||||
ConcreteValue::Integer(0),
|
||||
ConcreteValue::string("a"),
|
||||
ConcreteValue::Integer(42),
|
||||
ConcreteValue::string("b"),
|
||||
ConcreteValue::Integer(1),
|
||||
ConcreteValue::string("c"),
|
||||
ConcreteValue::Integer(2),
|
||||
ConcreteValue::string("d"),
|
||||
ConcreteValue::string("e"),
|
||||
],
|
||||
vec![
|
||||
Local::new(1, 0, false, Scope::new(0, 0)),
|
||||
Local::new(3, 2, false, Scope::new(1, 1)),
|
||||
Local::new(5, 4, false, Scope::new(2, 2)),
|
||||
Local::new(7, 6, false, Scope::new(1, 1)),
|
||||
Local::new(8, 7, false, Scope::new(0, 0)),
|
||||
]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_block_scopes() {
|
||||
let source = "
|
||||
let a = 0;
|
||||
{
|
||||
let b = 42;
|
||||
{
|
||||
let c = 1;
|
||||
}
|
||||
let d = b;
|
||||
}
|
||||
let q = a;
|
||||
{
|
||||
let b = 42;
|
||||
{
|
||||
let c = 1;
|
||||
}
|
||||
let d = b;
|
||||
}
|
||||
let e = a;
|
||||
";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::None,
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(17, 18)),
|
||||
(Instruction::load_constant(1, 2, false), Span(50, 52)),
|
||||
(Instruction::load_constant(2, 4, false), Span(92, 93)),
|
||||
(Instruction::get_local(3, 1), Span(129, 130)),
|
||||
(Instruction::get_local(4, 0), Span(158, 159)),
|
||||
(Instruction::load_constant(5, 2, false), Span(191, 193)),
|
||||
(Instruction::load_constant(4, 4, false), Span(233, 234)),
|
||||
(Instruction::get_local(7, 5), Span(270, 271)),
|
||||
(Instruction::get_local(8, 0), Span(299, 300)),
|
||||
(Instruction::r#return(false), Span(306, 306))
|
||||
],
|
||||
vec![
|
||||
ConcreteValue::Integer(0),
|
||||
ConcreteValue::string("a"),
|
||||
ConcreteValue::Integer(42),
|
||||
ConcreteValue::string("b"),
|
||||
ConcreteValue::Integer(1),
|
||||
ConcreteValue::string("c"),
|
||||
ConcreteValue::string("d"),
|
||||
ConcreteValue::string("q"),
|
||||
ConcreteValue::string("e"),
|
||||
],
|
||||
vec![
|
||||
Local::new(1, 0, false, Scope::new(0, 0)),
|
||||
Local::new(3, 2, false, Scope::new(1, 1)),
|
||||
Local::new(5, 4, false, Scope::new(2, 2)),
|
||||
Local::new(6, 5, false, Scope::new(1, 1)),
|
||||
Local::new(7, 6, false, Scope::new(0, 0)),
|
||||
Local::new(3, 1, false, Scope::new(1, 3)),
|
||||
Local::new(5, 1, false, Scope::new(2, 4)),
|
||||
Local::new(6, 1, false, Scope::new(1, 3)),
|
||||
Local::new(8, 1, false, Scope::new(0, 0)),
|
||||
]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disallow_access_to_child_scope() {
|
||||
let source = r#"
|
||||
{
|
||||
let x = 1;
|
||||
}
|
||||
x
|
||||
"#;
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::VariableOutOfScope {
|
||||
identifier: "x".to_string(),
|
||||
position: Span(52, 53),
|
||||
variable_scope: Scope::new(1, 1),
|
||||
access_scope: Scope::new(0, 0),
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disallow_access_to_child_scope_nested() {
|
||||
let source = r#"
|
||||
{
|
||||
{
|
||||
let x = 1;
|
||||
}
|
||||
x
|
||||
}
|
||||
"#;
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::VariableOutOfScope {
|
||||
identifier: "x".to_string(),
|
||||
position: Span(78, 79),
|
||||
variable_scope: Scope::new(2, 2),
|
||||
access_scope: Scope::new(1, 1),
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disallow_access_to_sibling_scope() {
|
||||
let source = r#"
|
||||
{
|
||||
let x = 1;
|
||||
}
|
||||
{
|
||||
x
|
||||
}
|
||||
"#;
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::VariableOutOfScope {
|
||||
identifier: "x".to_string(),
|
||||
variable_scope: Scope::new(1, 1),
|
||||
access_scope: Scope::new(1, 2),
|
||||
position: Span(66, 67),
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disallow_access_to_sibling_scope_nested() {
|
||||
let source = r#"
|
||||
{
|
||||
{
|
||||
let x = 1;
|
||||
}
|
||||
{
|
||||
x
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::VariableOutOfScope {
|
||||
identifier: "x".to_string(),
|
||||
variable_scope: Scope::new(2, 2),
|
||||
access_scope: Scope::new(2, 3),
|
||||
position: Span(96, 97),
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn negate() {
|
||||
let source = "-(42)";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Integer,
|
||||
},
|
||||
vec![
|
||||
(Instruction::negate(0, Operand::Constant(0)), Span(0, 1)),
|
||||
(Instruction::r#return(true), Span(5, 5)),
|
||||
],
|
||||
vec![ConcreteValue::Integer(42)],
|
||||
vec![]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(-42))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not() {
|
||||
let source = "!true";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Boolean,
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_encoded(0, true, false), Span(1, 5)),
|
||||
(Instruction::not(1, Operand::Register(0)), Span(0, 1)),
|
||||
(Instruction::r#return(true), Span(5, 5)),
|
||||
],
|
||||
vec![],
|
||||
vec![]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Boolean(false))));
|
||||
}
|
369
dust-lang/tests/values/load_values.rs
Normal file
369
dust-lang/tests/values/load_values.rs
Normal file
@ -0,0 +1,369 @@
|
||||
use dust_lang::{
|
||||
AbstractList, Chunk, ConcreteValue, DustString, FunctionType, Instruction, Span, Type, Value,
|
||||
compile, instruction::TypeCode, run, vm::Pointer,
|
||||
};
|
||||
|
||||
#[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, 2, 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, 2, 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, 2, 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, 2, 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, 3, 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, 2, 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, 2, false),
|
||||
Instruction::load_constant(2, 2, TypeCode::INTEGER, false),
|
||||
Instruction::load_constant(3, 3, TypeCode::INTEGER, false),
|
||||
Instruction::load_list(1, TypeCode::INTEGER, 2, 2, false),
|
||||
Instruction::load_list(2, TypeCode::LIST, 0, 2, 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());
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn define_local() {
|
||||
let source = "let x = 42;";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::None,
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(8, 10)),
|
||||
(Instruction::r#return(false), Span(11, 11))
|
||||
],
|
||||
vec![ConcreteValue::Integer(42), ConcreteValue::string("x")],
|
||||
vec![Local::new(1, 0, false, Scope::default())]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn let_statement_expects_identifier() {
|
||||
let source = "let 1 = 2";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
error: CompileError::ExpectedToken {
|
||||
expected: TokenKind::Identifier,
|
||||
found: Token::Integer("1").to_owned(),
|
||||
position: Span(4, 5)
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_local() {
|
||||
let source = "let mut x = 41; x = 42; x";
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Ok(Chunk::with_data(
|
||||
None,
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Type::Integer,
|
||||
},
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(12, 14)),
|
||||
(Instruction::load_constant(1, 2, false), Span(20, 22)),
|
||||
(Instruction::set_local(1, 0), Span(16, 17)),
|
||||
(Instruction::get_local(2, 0), Span(24, 25)),
|
||||
(Instruction::r#return(true), Span(25, 25)),
|
||||
],
|
||||
vec![
|
||||
ConcreteValue::Integer(41),
|
||||
ConcreteValue::string("x"),
|
||||
ConcreteValue::Integer(42)
|
||||
],
|
||||
vec![Local::new(1, 0, true, Scope::default())]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(ConcreteValue::Integer(42))));
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user