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 chunk = compile(source).unwrap();
///
/// assert_eq!(chunk.instructions().len(), 3);
/// assert_eq!(chunk.instructions.len(), 6);
/// ```
pub fn compile(source: &str) -> Result<Chunk, DustError> {
let lexer = Lexer::new(source);
@ -796,7 +796,13 @@ impl<'src> Compiler<'src> {
fn handle_binary_argument(&mut self, instruction: &Instruction) -> (Operand, bool) {
let operand = instruction.as_operand();
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(),
};

View File

@ -8,8 +8,8 @@ pub struct Add {
pub right: Operand,
}
impl From<Instruction> for Add {
fn from(instruction: Instruction) -> Self {
impl From<&Instruction> for Add {
fn from(instruction: &Instruction) -> Self {
let destination = instruction.a_field();
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
//! ones in their place instead of mutating them.
//!
//! # Examples
//!
//! ## Creating Instructions
//! # Creating Instructions
//!
//! For each operation, there are two ways to create an instruction:
//!
//! - Use the associated function on `Instruction`
//! - 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
//! 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);
//! ```
//! Both produce the same result, but the first is usuall more concise. The structs are more useful
//! when reading instructions, as shown below.
//!
//! 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.
//!
//! ```
//! # use dust_lang::instruction::{Instruction, Add, Operand};
//! # use dust_lang::instruction::{Instruction, Add, Operand, TypeCode};
//! let add_1 = Instruction::add(
//! 0,
//! Operand::Register(1),
//! Operand::Constant(2)
//! Operand::Register(1, TypeCode::INTEGER),
//! Operand::Constant(2, TypeCode::INTEGER)
//! );
//! let add_2 = Instruction::from(Add {
//! destination: 0,
//! left: Operand::Register(1),
//! right: Operand::Constant(2),
//! left: Operand::Register(1, TypeCode::INTEGER),
//! right: Operand::Constant(2, TypeCode::INTEGER),
//! });
//!
//! assert_eq!(add_1, add_2);
@ -67,24 +57,25 @@
//! 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(
//! # 1,
//! # Operand::Register(1),
//! # Operand::Constant(2)
//! # Operand::Register(1, TypeCode::INTEGER),
//! # Operand::Constant(2, TypeCode::INTEGER)
//! # );
//! // Let's read an instruction and see if it performs addition-assignment,
//! // like in one of the following examples:
//! // - `a += 2`
//! // - `a = a + 2`
//! // - `a = 2 + a`
//!
//! let operation = mystery_instruction.operation();
//! let is_add_assign = match operation {
//! Operation::Add => {
//! Operation::ADD => {
//! let Add { destination, left, right } = Add::from(&mystery_instruction);
//!
//! left == Operand::Register(destination)
//! || right == Operand::Register(destination)
//! left == Operand::Register(destination, TypeCode::INTEGER)
//! || right == Operand::Register(destination, TypeCode::INTEGER)
//!
//! }
//! _ => false,
@ -329,7 +320,26 @@ impl Instruction {
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_LIST => LoadList::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::MULTIPLY => Multiply::from(*self).to_string(),
Operation::DIVIDE => Divide::from(*self).to_string(),

View File

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