diff --git a/dust-lang/Cargo.toml b/dust-lang/Cargo.toml index a1f819b..d88f264 100644 --- a/dust-lang/Cargo.toml +++ b/dust-lang/Cargo.toml @@ -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" diff --git a/dust-lang/src/chunk/disassembler.rs b/dust-lang/src/chunk/disassembler.rs index ea4790e..00ba4db 100644 --- a/dust-lang/src/chunk/disassembler.rs +++ b/dust-lang/src/chunk/disassembler.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::>().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("")?; } diff --git a/dust-lang/src/chunk/mod.rs b/dust-lang/src/chunk/mod.rs index 3cbbcdd..dda8ed4 100644 --- a/dust-lang/src/chunk/mod.rs +++ b/dust-lang/src/chunk/mod.rs @@ -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, - pub(crate) r#type: FunctionType, + pub name: Option, + pub r#type: FunctionType, - pub(crate) instructions: Vec, - pub(crate) positions: Vec, - pub(crate) constants: Vec, - pub(crate) locals: Vec, - pub(crate) prototypes: Vec>, + pub instructions: Vec, + pub positions: Vec, + pub constants: Vec, + pub locals: Vec, + pub prototypes: Vec>, - 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 { diff --git a/dust-lang/src/compiler/mod.rs b/dust-lang/src/compiler/mod.rs index d00ab41..67da724 100644 --- a/dust-lang/src/compiler/mod.rs +++ b/dust-lang/src/compiler/mod.rs @@ -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::().unwrap() as u16; + let boolean = text.parse::().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; diff --git a/dust-lang/src/instruction/load_encoded.rs b/dust-lang/src/instruction/load_encoded.rs index ed7664c..a982c4c 100644 --- a/dust-lang/src/instruction/load_encoded.rs +++ b/dust-lang/src/instruction/load_encoded.rs @@ -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 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 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"), } diff --git a/dust-lang/src/instruction/load_list.rs b/dust-lang/src/instruction/load_list.rs index fd5c3f0..55fb339 100644 --- a/dust-lang/src/instruction/load_list.rs +++ b/dust-lang/src/instruction/load_list.rs @@ -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 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 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")?; diff --git a/dust-lang/src/instruction/mod.rs b/dust-lang/src/instruction/mod.rs index 2d08305..a301954 100644 --- a/dust-lang/src/instruction/mod.rs +++ b/dust-lang/src/instruction/mod.rs @@ -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, }) } diff --git a/dust-lang/src/instruction/return.rs b/dust-lang/src/instruction/return.rs index ace01ad..7e3a926 100644 --- a/dust-lang/src/instruction/return.rs +++ b/dust-lang/src/instruction/return.rs @@ -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 { diff --git a/dust-lang/src/instruction/type_code.rs b/dust-lang/src/instruction/type_code.rs index 11c3746..3b12b87 100644 --- a/dust-lang/src/instruction/type_code.rs +++ b/dust-lang/src/instruction/type_code.rs @@ -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(), } } diff --git a/dust-lang/src/type.rs b/dust-lang/src/type.rs index a36e31d..b70f320 100644 --- a/dust-lang/src/type.rs +++ b/dust-lang/src/type.rs @@ -24,7 +24,7 @@ pub enum Type { concrete_type: Option>, }, Integer, - List(Box), + 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 ")?; diff --git a/dust-lang/src/value/abstract_list.rs b/dust-lang/src/value/abstract_list.rs index 391f043..4a9d9ed 100644 --- a/dust-lang/src/value/abstract_list.rs +++ b/dust-lang/src/value/abstract_list.rs @@ -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, } @@ -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!(), }; diff --git a/dust-lang/src/value/concrete_value.rs b/dust-lang/src/value/concrete_value.rs index 416a730..235c876 100644 --- a/dust-lang/src/value/concrete_value.rs +++ b/dust-lang/src/value/concrete_value.rs @@ -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, diff --git a/dust-lang/src/value/mod.rs b/dust-lang/src/value/mod.rs index 7e5b9a8..e47d4f1 100644 --- a/dust-lang/src/value/mod.rs +++ b/dust-lang/src/value/mod.rs @@ -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())), } } diff --git a/dust-lang/src/vm/action.rs b/dust-lang/src/vm/action.rs index 42c01ad..2a60133 100644 --- a/dust-lang/src/vm/action.rs +++ b/dust-lang/src/vm/action.rs @@ -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 { diff --git a/dust-lang/src/vm/call_frame.rs b/dust-lang/src/vm/call_frame.rs index bd6462c..730f569 100644 --- a/dust-lang/src/vm/call_frame.rs +++ b/dust-lang/src/vm/call_frame.rs @@ -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; 64]>, pub integers: SmallVec<[Register; 64]>, pub strings: SmallVec<[Register; 64]>, + pub lists: SmallVec<[Register; 64]>, + pub functions: SmallVec<[Register; 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 Display for Register { 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}"), } } } diff --git a/dust-lang/src/vm/thread.rs b/dust-lang/src/vm/thread.rs index 2db34bb..a794602 100644 --- a/dust-lang/src/vm/thread.rs +++ b/dust-lang/src/vm/thread.rs @@ -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, + ) { + 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() diff --git a/dust-lang/tests/assignment_errors.rs b/dust-lang/tests/assignment_errors.rs deleted file mode 100644 index a117612..0000000 --- a/dust-lang/tests/assignment_errors.rs +++ /dev/null @@ -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 - }) - ); -} diff --git a/dust-lang/tests/basic.rs b/dust-lang/tests/basic.rs deleted file mode 100644 index ec728e6..0000000 --- a/dust-lang/tests/basic.rs +++ /dev/null @@ -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)))); -} diff --git a/dust-lang/tests/comparison.rs b/dust-lang/tests/comparison.rs deleted file mode 100644 index 677a646..0000000 --- a/dust-lang/tests/comparison.rs +++ /dev/null @@ -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)))); -} diff --git a/dust-lang/tests/functions.rs b/dust-lang/tests/functions.rs deleted file mode 100644 index 181529d..0000000 --- a/dust-lang/tests/functions.rs +++ /dev/null @@ -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)); -} diff --git a/dust-lang/tests/lists.rs b/dust-lang/tests/lists.rs deleted file mode 100644 index adb7ba4..0000000 --- a/dust-lang/tests/lists.rs +++ /dev/null @@ -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), - ]))) - ); -} diff --git a/dust-lang/tests/logic/and.rs b/dust-lang/tests/logic/and.rs deleted file mode 100644 index 0bce420..0000000 --- a/dust-lang/tests/logic/and.rs +++ /dev/null @@ -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)))); -} diff --git a/dust-lang/tests/logic/and_and.rs b/dust-lang/tests/logic/and_and.rs deleted file mode 100644 index a0807d2..0000000 --- a/dust-lang/tests/logic/and_and.rs +++ /dev/null @@ -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![], - )) - ); -} diff --git a/dust-lang/tests/logic/or.rs b/dust-lang/tests/logic/or.rs deleted file mode 100644 index 87eb26e..0000000 --- a/dust-lang/tests/logic/or.rs +++ /dev/null @@ -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)))); -} diff --git a/dust-lang/tests/loops.rs b/dust-lang/tests/loops.rs deleted file mode 100644 index 5c7d121..0000000 --- a/dust-lang/tests/loops.rs +++ /dev/null @@ -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)))); -} diff --git a/dust-lang/tests/math/add.rs b/dust-lang/tests/math/add.rs deleted file mode 100644 index 59c77cf..0000000 --- a/dust-lang/tests/math/add.rs +++ /dev/null @@ -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")))); -} diff --git a/dust-lang/tests/math/add_assign.rs b/dust-lang/tests/math/add_assign.rs deleted file mode 100644 index a434bb7..0000000 --- a/dust-lang/tests/math/add_assign.rs +++ /dev/null @@ -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)))); -} diff --git a/dust-lang/tests/math/add_errors.rs b/dust-lang/tests/math/add_errors.rs deleted file mode 100644 index 6268790..0000000 --- a/dust-lang/tests/math/add_errors.rs +++ /dev/null @@ -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, - }) - ); -} diff --git a/dust-lang/tests/math/divide.rs b/dust-lang/tests/math/divide.rs deleted file mode 100644 index 9f40492..0000000 --- a/dust-lang/tests/math/divide.rs +++ /dev/null @@ -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)))); -} diff --git a/dust-lang/tests/math/divide_assign.rs b/dust-lang/tests/math/divide_assign.rs deleted file mode 100644 index 7e44d83..0000000 --- a/dust-lang/tests/math/divide_assign.rs +++ /dev/null @@ -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)))); -} diff --git a/dust-lang/tests/math/divide_errors.rs b/dust-lang/tests/math/divide_errors.rs deleted file mode 100644 index a3118cc..0000000 --- a/dust-lang/tests/math/divide_errors.rs +++ /dev/null @@ -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, - }) - ); -} diff --git a/dust-lang/tests/math/modulo.rs b/dust-lang/tests/math/modulo.rs deleted file mode 100644 index d803338..0000000 --- a/dust-lang/tests/math/modulo.rs +++ /dev/null @@ -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)))); -} diff --git a/dust-lang/tests/math/modulo_assign.rs b/dust-lang/tests/math/modulo_assign.rs deleted file mode 100644 index e69de29..0000000 diff --git a/dust-lang/tests/math/modulo_errors.rs b/dust-lang/tests/math/modulo_errors.rs deleted file mode 100644 index d283ec4..0000000 --- a/dust-lang/tests/math/modulo_errors.rs +++ /dev/null @@ -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, - }) - ); -} diff --git a/dust-lang/tests/math/multiply.rs b/dust-lang/tests/math/multiply.rs deleted file mode 100644 index f54f044..0000000 --- a/dust-lang/tests/math/multiply.rs +++ /dev/null @@ -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)))); -} diff --git a/dust-lang/tests/math/multiply_assign.rs b/dust-lang/tests/math/multiply_assign.rs deleted file mode 100644 index 065bd24..0000000 --- a/dust-lang/tests/math/multiply_assign.rs +++ /dev/null @@ -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)))); -} diff --git a/dust-lang/tests/math/multiply_errors.rs b/dust-lang/tests/math/multiply_errors.rs deleted file mode 100644 index 5c03033..0000000 --- a/dust-lang/tests/math/multiply_errors.rs +++ /dev/null @@ -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, - }) - ); -} diff --git a/dust-lang/tests/math/subtract.rs b/dust-lang/tests/math/subtract.rs deleted file mode 100644 index 44f7b2d..0000000 --- a/dust-lang/tests/math/subtract.rs +++ /dev/null @@ -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)))); -} diff --git a/dust-lang/tests/math/subtract_assign.rs b/dust-lang/tests/math/subtract_assign.rs deleted file mode 100644 index 7b20cbf..0000000 --- a/dust-lang/tests/math/subtract_assign.rs +++ /dev/null @@ -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)))); -} diff --git a/dust-lang/tests/math/subtract_errors.rs b/dust-lang/tests/math/subtract_errors.rs deleted file mode 100644 index 1d73bde..0000000 --- a/dust-lang/tests/math/subtract_errors.rs +++ /dev/null @@ -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, - }) - ); -} diff --git a/dust-lang/tests/native_functions.rs b/dust-lang/tests/native_functions.rs deleted file mode 100644 index e6d13db..0000000 --- a/dust-lang/tests/native_functions.rs +++ /dev/null @@ -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")))) -} diff --git a/dust-lang/tests/scopes.rs b/dust-lang/tests/scopes.rs deleted file mode 100644 index d9e14e3..0000000 --- a/dust-lang/tests/scopes.rs +++ /dev/null @@ -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 - }) - ); -} diff --git a/dust-lang/tests/unary_operations.rs b/dust-lang/tests/unary_operations.rs deleted file mode 100644 index 129f441..0000000 --- a/dust-lang/tests/unary_operations.rs +++ /dev/null @@ -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)))); -} diff --git a/dust-lang/tests/values/load_values.rs b/dust-lang/tests/values/load_values.rs new file mode 100644 index 0000000..c65bdfa --- /dev/null +++ b/dust-lang/tests/values/load_values.rs @@ -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()); +} diff --git a/dust-lang/tests/variables.rs b/dust-lang/tests/variables.rs deleted file mode 100644 index b1f67d0..0000000 --- a/dust-lang/tests/variables.rs +++ /dev/null @@ -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)))); -}