diff --git a/dust-lang/src/compiler/mod.rs b/dust-lang/src/compiler/mod.rs index 865053a..8310e6e 100644 --- a/dust-lang/src/compiler/mod.rs +++ b/dust-lang/src/compiler/mod.rs @@ -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 { 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(), }; diff --git a/dust-lang/src/instruction/add.rs b/dust-lang/src/instruction/add.rs index f5cf9bb..a2dbd9c 100644 --- a/dust-lang/src/instruction/add.rs +++ b/dust-lang/src/instruction/add.rs @@ -8,8 +8,8 @@ pub struct Add { pub right: Operand, } -impl From 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(); diff --git a/dust-lang/src/instruction/mod.rs b/dust-lang/src/instruction/mod.rs index 1def451..c288de2 100644 --- a/dust-lang/src/instruction/mod.rs +++ b/dust-lang/src/instruction/mod.rs @@ -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(), diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index d8e4aa6..648893f 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -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 diff --git a/dust-lang/src/vm/action.rs b/dust-lang/src/vm/action.rs index b15a615..27d37a4 100644 --- a/dust-lang/src/vm/action.rs +++ b/dust-lang/src/vm/action.rs @@ -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) {}