1
0

Fix and pass all tests

This commit is contained in:
Jeff 2025-02-07 22:39:07 -05:00
parent ac11ad5674
commit d3addbe183
5 changed files with 85 additions and 33 deletions

View File

@ -44,7 +44,7 @@ use crate::{
/// let source = "40 + 2 == 42"; /// let source = "40 + 2 == 42";
/// let chunk = compile(source).unwrap(); /// let chunk = compile(source).unwrap();
/// ///
/// assert_eq!(chunk.instructions().len(), 3); /// assert_eq!(chunk.instructions.len(), 6);
/// ``` /// ```
pub fn compile(source: &str) -> Result<Chunk, DustError> { pub fn compile(source: &str) -> Result<Chunk, DustError> {
let lexer = Lexer::new(source); let lexer = Lexer::new(source);
@ -796,7 +796,13 @@ impl<'src> Compiler<'src> {
fn handle_binary_argument(&mut self, instruction: &Instruction) -> (Operand, bool) { fn handle_binary_argument(&mut self, instruction: &Instruction) -> (Operand, bool) {
let operand = instruction.as_operand(); let operand = instruction.as_operand();
let push_back = match instruction.operation() { let push_back = match instruction.operation() {
Operation::LOAD_ENCODED | Operation::LOAD_SELF => true, Operation::LOAD_ENCODED
| Operation::LOAD_SELF
| Operation::ADD
| Operation::SUBTRACT
| Operation::MULTIPLY
| Operation::DIVIDE
| Operation::MODULO => true,
_ => !instruction.yields_value(), _ => !instruction.yields_value(),
}; };

View File

@ -8,8 +8,8 @@ pub struct Add {
pub right: Operand, pub right: Operand,
} }
impl From<Instruction> for Add { impl From<&Instruction> for Add {
fn from(instruction: Instruction) -> Self { fn from(instruction: &Instruction) -> Self {
let destination = instruction.a_field(); let destination = instruction.a_field();
let (left, right) = instruction.b_and_c_as_operands(); let (left, right) = instruction.b_and_c_as_operands();

View File

@ -20,40 +20,30 @@
//! you may also need to modify its flags. It is usually best to remove instructions and insert new //! you may also need to modify its flags. It is usually best to remove instructions and insert new
//! ones in their place instead of mutating them. //! ones in their place instead of mutating them.
//! //!
//! # Examples //! # Creating Instructions
//!
//! ## Creating Instructions
//! //!
//! For each operation, there are two ways to create an instruction: //! For each operation, there are two ways to create an instruction:
//! //!
//! - Use the associated function on `Instruction` //! - Use the associated function on `Instruction`
//! - Use the corresponding struct and call `Instruction::from` //! - Use the corresponding struct and call `Instruction::from`
//! //!
//! Both produce the same result, but the first is more concise. The structs are more useful when //! Both produce the same result, but the first is usuall more concise. The structs are more useful
//! reading instructions, as shown below. //! when reading instructions, as shown below.
//!
//! ```
//! # use dust_lang::instruction::{Instruction, Move};
//! let move_1 = Instruction::r#move(42, 4);
//! let move_2 = Instruction::from(Move { from: 42, to: 4 });
//!
//! assert_eq!(move_1, move_2);
//! ```
//! //!
//! Use the [`Operand`][] type when creating instructions. In addition to being easy to read and //! Use the [`Operand`][] type when creating instructions. In addition to being easy to read and
//! write, this ensures that the instruction has the correct flags to represent the operands. //! write, this ensures that the instruction has the correct flags to represent the operands.
//! //!
//! ``` //! ```
//! # use dust_lang::instruction::{Instruction, Add, Operand}; //! # use dust_lang::instruction::{Instruction, Add, Operand, TypeCode};
//! let add_1 = Instruction::add( //! let add_1 = Instruction::add(
//! 0, //! 0,
//! Operand::Register(1), //! Operand::Register(1, TypeCode::INTEGER),
//! Operand::Constant(2) //! Operand::Constant(2, TypeCode::INTEGER)
//! ); //! );
//! let add_2 = Instruction::from(Add { //! let add_2 = Instruction::from(Add {
//! destination: 0, //! destination: 0,
//! left: Operand::Register(1), //! left: Operand::Register(1, TypeCode::INTEGER),
//! right: Operand::Constant(2), //! right: Operand::Constant(2, TypeCode::INTEGER),
//! }); //! });
//! //!
//! assert_eq!(add_1, add_2); //! assert_eq!(add_1, add_2);
@ -67,24 +57,25 @@
//! D fields as `u16`, `bool` or `Operand` values. //! D fields as `u16`, `bool` or `Operand` values.
//! //!
//! ``` //! ```
//! # use dust_lang::instruction::{Instruction, Add, Operand, Operation}; //! # use dust_lang::instruction::{Instruction, Add, Operand, Operation, TypeCode};
//! # let mystery_instruction = Instruction::add( //! # let mystery_instruction = Instruction::add(
//! # 1, //! # 1,
//! # Operand::Register(1), //! # Operand::Register(1, TypeCode::INTEGER),
//! # Operand::Constant(2) //! # Operand::Constant(2, TypeCode::INTEGER)
//! # ); //! # );
//! // Let's read an instruction and see if it performs addition-assignment, //! // Let's read an instruction and see if it performs addition-assignment,
//! // like in one of the following examples: //! // like in one of the following examples:
//! // - `a += 2` //! // - `a += 2`
//! // - `a = a + 2` //! // - `a = a + 2`
//! // - `a = 2 + a`
//! //!
//! let operation = mystery_instruction.operation(); //! let operation = mystery_instruction.operation();
//! let is_add_assign = match operation { //! let is_add_assign = match operation {
//! Operation::Add => { //! Operation::ADD => {
//! let Add { destination, left, right } = Add::from(&mystery_instruction); //! let Add { destination, left, right } = Add::from(&mystery_instruction);
//! //!
//! left == Operand::Register(destination) //! left == Operand::Register(destination, TypeCode::INTEGER)
//! || right == Operand::Register(destination) //! || right == Operand::Register(destination, TypeCode::INTEGER)
//! //!
//! } //! }
//! _ => false, //! _ => false,
@ -329,7 +320,26 @@ impl Instruction {
Operand::Register(destination, TypeCode::FUNCTION) Operand::Register(destination, TypeCode::FUNCTION)
} }
_ => todo!(), Operation::ADD => {
let Add {
destination, left, ..
} = Add::from(self);
let register_type = match left.as_type() {
TypeCode::BOOLEAN => TypeCode::BOOLEAN,
TypeCode::BYTE => TypeCode::BYTE,
TypeCode::CHARACTER => TypeCode::STRING,
TypeCode::INTEGER => TypeCode::INTEGER,
TypeCode::FLOAT => TypeCode::FLOAT,
TypeCode::STRING => TypeCode::STRING,
TypeCode::LIST => TypeCode::LIST,
TypeCode::FUNCTION => TypeCode::FUNCTION,
_ => unreachable!(),
};
Operand::Register(destination, register_type)
}
unsupported => todo!("Support {unsupported}"),
} }
} }
@ -609,7 +619,7 @@ impl Instruction {
Operation::LOAD_FUNCTION => LoadFunction::from(*self).to_string(), Operation::LOAD_FUNCTION => LoadFunction::from(*self).to_string(),
Operation::LOAD_LIST => LoadList::from(*self).to_string(), Operation::LOAD_LIST => LoadList::from(*self).to_string(),
Operation::LOAD_SELF => LoadSelf::from(*self).to_string(), Operation::LOAD_SELF => LoadSelf::from(*self).to_string(),
Operation::ADD => Add::from(*self).to_string(), Operation::ADD => Add::from(self).to_string(),
Operation::SUBTRACT => Subtract::from(*self).to_string(), Operation::SUBTRACT => Subtract::from(*self).to_string(),
Operation::MULTIPLY => Multiply::from(*self).to_string(), Operation::MULTIPLY => Multiply::from(*self).to_string(),
Operation::DIVIDE => Divide::from(*self).to_string(), Operation::DIVIDE => Divide::from(*self).to_string(),

View File

@ -14,10 +14,10 @@
//! ## Examples //! ## Examples
//! //!
//! ```rust //! ```rust
//! # use dust_lang::{run, ConcreteValue}; //! # use dust_lang::{run, Value};
//! let result = run("21 * 2").unwrap(); //! let result = run("21 * 2").unwrap();
//! //!
//! assert_eq!(result, Some(ConcreteValue::Integer(42))); //! assert_eq!(result, Some(Value::integer(42)));
//! ``` //! ```
//! //!
//! ```rust //! ```rust

View File

@ -430,7 +430,43 @@ pub fn add(instruction: InstructionFields, thread: &mut Thread) {
pub fn subtract(instruction: InstructionFields, thread: &mut Thread) {} pub fn subtract(instruction: InstructionFields, thread: &mut Thread) {}
pub fn multiply(instruction: InstructionFields, thread: &mut Thread) {} pub fn multiply(instruction: InstructionFields, thread: &mut Thread) {
let destination = instruction.a_field as usize;
let left = instruction.b_field as usize;
let left_type = instruction.b_type;
let left_is_constant = instruction.b_is_constant;
let right = instruction.c_field as usize;
let right_type = instruction.c_type;
let right_is_constant = instruction.c_is_constant;
match (left_type, right_type) {
(TypeCode::INTEGER, TypeCode::INTEGER) => {
let left_value = if left_is_constant {
if cfg!(debug_assertions) {
thread.get_constant(left).as_integer().unwrap()
} else {
unsafe { thread.get_constant(left).as_integer().unwrap_unchecked() }
}
} else {
thread.get_integer_register(left)
};
let right_value = if right_is_constant {
if cfg!(debug_assertions) {
thread.get_constant(right).as_integer().unwrap()
} else {
unsafe { thread.get_constant(right).as_integer().unwrap_unchecked() }
}
} else {
thread.get_integer_register(right)
};
let result = left_value * right_value;
let register = Register::Value(result);
thread.set_integer_register(destination as usize, register);
}
_ => unimplemented!(),
}
}
pub fn divide(instruction: InstructionFields, thread: &mut Thread) {} pub fn divide(instruction: InstructionFields, thread: &mut Thread) {}