Fix and pass all tests
This commit is contained in:
parent
ac11ad5674
commit
d3addbe183
@ -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(),
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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
|
||||
|
@ -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) {}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user