This commit is contained in:
Jeff 2024-09-17 21:10:44 -04:00
parent f02c3d1fb5
commit 37dc2e05c5
3 changed files with 79 additions and 170 deletions

View File

@ -224,6 +224,21 @@ impl Instruction {
} }
pub fn disassembly_info(&self, chunk: Option<&Chunk>) -> Option<String> { pub fn disassembly_info(&self, chunk: Option<&Chunk>) -> Option<String> {
let format_arguments = || {
let first_argument = if self.first_argument_is_constant() {
format!("C({})", self.first_argument())
} else {
format!("R({})", self.first_argument())
};
let second_argument = if self.second_argument_is_constant() {
format!("C({})", self.second_argument())
} else {
format!("R({})", self.second_argument())
};
(first_argument, second_argument)
};
let info = match self.operation() { let info = match self.operation() {
Operation::Move => { Operation::Move => {
format!("R({}) = R({})", self.destination(), self.first_argument()) format!("R({}) = R({})", self.destination(), self.first_argument())
@ -306,106 +321,43 @@ impl Instruction {
} }
Operation::Add => { Operation::Add => {
let destination = self.destination(); let destination = self.destination();
let first_argument = if self.first_argument_is_constant() { let (first_argument, second_argument) = format_arguments();
format!("C({})", self.first_argument())
} else {
format!("R({})", self.first_argument())
};
let second_argument = if self.second_argument_is_constant() {
format!("C({})", self.second_argument())
} else {
format!("R({})", self.second_argument())
};
format!("R({destination}) = {first_argument} + {second_argument}",) format!("R({destination}) = {first_argument} + {second_argument}",)
} }
Operation::Subtract => { Operation::Subtract => {
let destination = self.destination(); let destination = self.destination();
let first_argument = if self.first_argument_is_constant() { let (first_argument, second_argument) = format_arguments();
format!("C({})", self.first_argument())
} else {
format!("R({})", self.first_argument())
};
let second_argument = if self.second_argument_is_constant() {
format!("C({})", self.second_argument())
} else {
format!("R({})", self.second_argument())
};
format!("R({destination}) = {first_argument} - {second_argument}",) format!("R({destination}) = {first_argument} - {second_argument}",)
} }
Operation::Multiply => { Operation::Multiply => {
let destination = self.destination(); let destination = self.destination();
let first_argument = if self.first_argument_is_constant() { let (first_argument, second_argument) = format_arguments();
format!("C({})", self.first_argument())
} else {
format!("R({})", self.first_argument())
};
let second_argument = if self.second_argument_is_constant() {
format!("C({})", self.second_argument())
} else {
format!("R({})", self.second_argument())
};
format!("R({destination}) = {first_argument} * {second_argument}",) format!("R({destination}) = {first_argument} * {second_argument}",)
} }
Operation::Divide => { Operation::Divide => {
let destination = self.destination(); let destination = self.destination();
let first_argument = if self.first_argument_is_constant() { let (first_argument, second_argument) = format_arguments();
format!("C({})", self.first_argument())
} else {
format!("R({})", self.first_argument())
};
let second_argument = if self.second_argument_is_constant() {
format!("C({})", self.second_argument())
} else {
format!("R({})", self.second_argument())
};
format!("R({destination}) = {first_argument} / {second_argument}",) format!("R({destination}) = {first_argument} / {second_argument}",)
} }
Operation::Modulo => { Operation::Modulo => {
let destination = self.destination(); let destination = self.destination();
let first_argument = if self.first_argument_is_constant() { let (first_argument, second_argument) = format_arguments();
format!("C({})", self.first_argument())
} else {
format!("R({})", self.first_argument())
};
let second_argument = if self.second_argument_is_constant() {
format!("C({})", self.second_argument())
} else {
format!("R({})", self.second_argument())
};
format!("R({destination}) = {first_argument} % {second_argument}",) format!("R({destination}) = {first_argument} % {second_argument}",)
} }
Operation::And => { Operation::And => {
let destination = self.destination(); let destination = self.destination();
let first_argument = if self.first_argument_is_constant() { let (first_argument, second_argument) = format_arguments();
format!("C({})", self.first_argument())
} else {
format!("R({})", self.first_argument())
};
let second_argument = if self.second_argument_is_constant() {
format!("C({})", self.second_argument())
} else {
format!("R({})", self.second_argument())
};
format!("R({destination}) = {first_argument} && {second_argument}",) format!("R({destination}) = {first_argument} && {second_argument}",)
} }
Operation::Or => { Operation::Or => {
let destination = self.destination(); let destination = self.destination();
let first_argument = if self.first_argument_is_constant() { let (first_argument, second_argument) = format_arguments();
format!("C({})", self.first_argument())
} else {
format!("R({})", self.first_argument())
};
let second_argument = if self.second_argument_is_constant() {
format!("C({})", self.second_argument())
} else {
format!("R({})", self.second_argument())
};
format!("R({destination}) = {first_argument} || {second_argument}",) format!("R({destination}) = {first_argument} || {second_argument}",)
} }

View File

@ -96,7 +96,7 @@ impl<'src> Parser<'src> {
let (new_token, position) = self.lexer.next_token()?; let (new_token, position) = self.lexer.next_token()?;
log::trace!("Parsing token \"{new_token}\" at {position}"); log::trace!("Parsing \"{new_token}\" at {position}");
self.previous_token = replace(&mut self.current_token, new_token); self.previous_token = replace(&mut self.current_token, new_token);
self.previous_position = replace(&mut self.current_position, position); self.previous_position = replace(&mut self.current_position, position);
@ -271,7 +271,7 @@ impl<'src> Parser<'src> {
TokenKind::Minus => Instruction::negate(destination, from_register), TokenKind::Minus => Instruction::negate(destination, from_register),
_ => { _ => {
return Err(ParseError::ExpectedTokenMultiple { return Err(ParseError::ExpectedTokenMultiple {
expected: &[TokenKind::Minus], expected: &[TokenKind::Bang, TokenKind::Minus],
found: operator.to_owned(), found: operator.to_owned(),
position: operator_position, position: operator_position,
}) })
@ -356,6 +356,9 @@ impl<'src> Parser<'src> {
TokenKind::Minus, TokenKind::Minus,
TokenKind::Star, TokenKind::Star,
TokenKind::Slash, TokenKind::Slash,
TokenKind::Percent,
TokenKind::DoubleAmpersand,
TokenKind::DoublePipe,
], ],
found: operator.to_owned(), found: operator.to_owned(),
position: operator_position, position: operator_position,
@ -475,13 +478,14 @@ impl<'src> Parser<'src> {
} }
fn parse_list(&mut self, _allow_assignment: bool) -> Result<(), ParseError> { fn parse_list(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
let start = self.current_position.0;
self.advance()?; self.advance()?;
let start = self.current_position.0;
let mut length = 0; let mut length = 0;
while !self.allow(TokenKind::RightSquareBrace)? && !self.is_eof() { while !self.allow(TokenKind::RightSquareBrace)? && !self.is_eof() {
self.parse_expression()?; self.parse(Precedence::Assignment)?; // Do not allow assignment
length += 1; length += 1;
@ -535,7 +539,14 @@ impl<'src> Parser<'src> {
Ok(()) Ok(())
} }
fn parse_let_statement(&mut self, _allow_assignment: bool) -> Result<(), ParseError> { fn parse_let_statement(&mut self, allow_assignment: bool) -> Result<(), ParseError> {
if !allow_assignment {
return Err(ParseError::ExpectedExpression {
found: self.current_token.to_owned(),
position: self.current_position,
});
}
self.advance()?; self.advance()?;
let position = self.current_position; let position = self.current_position;
@ -587,7 +598,7 @@ impl<'src> Parser<'src> {
if let Some(prefix_parser) = ParseRule::from(&self.current_token.kind()).prefix { if let Some(prefix_parser) = ParseRule::from(&self.current_token.kind()).prefix {
log::trace!( log::trace!(
"Parsing {} as prefix with precedence {precedence}", "Parsing \"{}\" with prefix parser at precedence {precedence}",
self.current_token, self.current_token,
); );
@ -599,7 +610,7 @@ impl<'src> Parser<'src> {
while precedence <= infix_rule.precedence { while precedence <= infix_rule.precedence {
if let Some(infix_parser) = infix_rule.infix { if let Some(infix_parser) = infix_rule.infix {
log::trace!( log::trace!(
"Parsing {} as infix with precedence {precedence}", "Parsing \"{}\" with infix parser at precedence {precedence}",
self.current_token, self.current_token,
); );

View File

@ -35,6 +35,26 @@ impl Vm {
} }
pub fn run(&mut self) -> Result<Option<Value>, VmError> { pub fn run(&mut self) -> Result<Option<Value>, VmError> {
let take_constants_or_clone = |vm: &mut Vm,
instruction: Instruction,
position: Span|
-> Result<(Value, Value), VmError> {
let left = if instruction.first_argument_is_constant() {
vm.chunk
.take_constant(instruction.first_argument(), position)?
} else {
vm.clone(instruction.first_argument(), position)?
};
let right = if instruction.second_argument_is_constant() {
vm.chunk
.take_constant(instruction.second_argument(), position)?
} else {
vm.clone(instruction.second_argument(), position)?
};
Ok((left, right))
};
while let Ok((instruction, position)) = self.read(Span(0, 0)).copied() { while let Ok((instruction, position)) = self.read(Span(0, 0)).copied() {
log::trace!("Running instruction {instruction} at {position}"); log::trace!("Running instruction {instruction} at {position}");
@ -98,16 +118,7 @@ impl Vm {
self.chunk.define_local(to_local, from_register, position)?; self.chunk.define_local(to_local, from_register, position)?;
} }
Operation::Add => { Operation::Add => {
let left = self.take_constant_or_clone_register( let (left, right) = take_constants_or_clone(self, instruction, position)?;
instruction.first_argument(),
instruction.first_argument_is_constant(),
position,
)?;
let right = self.take_constant_or_clone_register(
instruction.second_argument(),
instruction.second_argument_is_constant(),
position,
)?;
let sum = left let sum = left
.add(&right) .add(&right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -115,16 +126,7 @@ impl Vm {
self.insert(sum, instruction.destination(), position)?; self.insert(sum, instruction.destination(), position)?;
} }
Operation::Subtract => { Operation::Subtract => {
let left = self.take_constant_or_clone_register( let (left, right) = take_constants_or_clone(self, instruction, position)?;
instruction.first_argument(),
instruction.first_argument_is_constant(),
position,
)?;
let right = self.take_constant_or_clone_register(
instruction.second_argument(),
instruction.second_argument_is_constant(),
position,
)?;
let difference = left let difference = left
.subtract(&right) .subtract(&right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -132,16 +134,7 @@ impl Vm {
self.insert(difference, instruction.destination(), position)?; self.insert(difference, instruction.destination(), position)?;
} }
Operation::Multiply => { Operation::Multiply => {
let left = self.take_constant_or_clone_register( let (left, right) = take_constants_or_clone(self, instruction, position)?;
instruction.first_argument(),
instruction.first_argument_is_constant(),
position,
)?;
let right = self.take_constant_or_clone_register(
instruction.second_argument(),
instruction.second_argument_is_constant(),
position,
)?;
let product = left let product = left
.multiply(&right) .multiply(&right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -149,16 +142,7 @@ impl Vm {
self.insert(product, instruction.destination(), position)?; self.insert(product, instruction.destination(), position)?;
} }
Operation::Divide => { Operation::Divide => {
let left = self.take_constant_or_clone_register( let (left, right) = take_constants_or_clone(self, instruction, position)?;
instruction.first_argument(),
instruction.first_argument_is_constant(),
position,
)?;
let right = self.take_constant_or_clone_register(
instruction.second_argument(),
instruction.second_argument_is_constant(),
position,
)?;
let quotient = left let quotient = left
.divide(&right) .divide(&right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -166,16 +150,7 @@ impl Vm {
self.insert(quotient, instruction.destination(), position)?; self.insert(quotient, instruction.destination(), position)?;
} }
Operation::Modulo => { Operation::Modulo => {
let left = self.take_constant_or_clone_register( let (left, right) = take_constants_or_clone(self, instruction, position)?;
instruction.first_argument(),
instruction.first_argument_is_constant(),
position,
)?;
let right = self.take_constant_or_clone_register(
instruction.second_argument(),
instruction.second_argument_is_constant(),
position,
)?;
let remainder = left let remainder = left
.modulo(&right) .modulo(&right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -183,16 +158,7 @@ impl Vm {
self.insert(remainder, instruction.destination(), position)?; self.insert(remainder, instruction.destination(), position)?;
} }
Operation::And => { Operation::And => {
let left = self.take_constant_or_clone_register( let (left, right) = take_constants_or_clone(self, instruction, position)?;
instruction.first_argument(),
instruction.first_argument_is_constant(),
position,
)?;
let right = self.take_constant_or_clone_register(
instruction.second_argument(),
instruction.second_argument_is_constant(),
position,
)?;
let result = left let result = left
.and(&right) .and(&right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -200,16 +166,7 @@ impl Vm {
self.insert(result, instruction.destination(), position)?; self.insert(result, instruction.destination(), position)?;
} }
Operation::Or => { Operation::Or => {
let left = self.take_constant_or_clone_register( let (left, right) = take_constants_or_clone(self, instruction, position)?;
instruction.first_argument(),
instruction.first_argument_is_constant(),
position,
)?;
let right = self.take_constant_or_clone_register(
instruction.second_argument(),
instruction.second_argument_is_constant(),
position,
)?;
let result = left let result = left
.or(&right) .or(&right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -217,11 +174,12 @@ impl Vm {
self.insert(result, instruction.destination(), position)?; self.insert(result, instruction.destination(), position)?;
} }
Operation::Negate => { Operation::Negate => {
let value = self.take_constant_or_clone_register( let value = if instruction.first_argument_is_constant() {
instruction.first_argument(), self.chunk
instruction.first_argument_is_constant(), .take_constant(instruction.first_argument(), position)?
position, } else {
)?; self.clone(instruction.first_argument(), position)?
};
let negated = value let negated = value
.negate() .negate()
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -229,11 +187,12 @@ impl Vm {
self.insert(negated, instruction.destination(), position)?; self.insert(negated, instruction.destination(), position)?;
} }
Operation::Not => { Operation::Not => {
let value = self.take_constant_or_clone_register( let value = if instruction.first_argument_is_constant() {
instruction.first_argument(), self.chunk
instruction.first_argument_is_constant(), .take_constant(instruction.first_argument(), position)?
position, } else {
)?; self.clone(instruction.first_argument(), position)?
};
let result = value let result = value
.not() .not()
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
@ -289,19 +248,6 @@ impl Vm {
} }
} }
fn take_constant_or_clone_register(
&mut self,
index: u8,
is_constant: bool,
position: Span,
) -> Result<Value, VmError> {
if is_constant {
Ok(self.chunk.take_constant(index, position)?)
} else {
self.clone(index, position)
}
}
fn pop(&mut self, position: Span) -> Result<Value, VmError> { fn pop(&mut self, position: Span) -> Result<Value, VmError> {
if let Some(register) = self.register_stack.pop() { if let Some(register) = self.register_stack.pop() {
let value = register.ok_or(VmError::EmptyRegister { let value = register.ok_or(VmError::EmptyRegister {