Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Session 6 functionality #5

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Conversation

maw3193
Copy link
Owner

@maw3193 maw3193 commented Apr 25, 2023

No description provided.

Copy link

@danielsilverstone-ct danielsilverstone-ct left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Over-all I think you've done well. If you say that this passes everything you can think of to throw at it then I'm happy with the functionality.

I think there's work to be done with respect to deciding what things need to be pub vs. not; remember that anything you make public you are making part of your support contract for future development.

If you want to chat about things, please find me.

Comment on lines +100 to +103
fn next_instruction(&self) -> usize {
self.instruction_pointer + 1
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function feels a little "extra" but I don't hate it.

Comment on lines +230 to 232
pub fn current_cell(&mut self) -> &mut T {
&mut self.cells[self.head]
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not clear why you need this function, using this can cause borrow problems in functions in your impl blocks, because to call it, everything inside the instance must be consistent and unborrowed - I imagine you're not having a problem right now, but in general I try and avoid this kind of function unless it's critical to your API. Do you need this to be public? If not, perhaps it need not exist.

If you're not quite sure why I'm saying this is a potential problem; then think more about what it means to be able to call a method on a struct in terms of the borrows. If you're still stuck, poke me IRL and I'll try to explain it another way.

Comment on lines +327 to +333
file.write_all(&buffer)
.and_then(|_| file.flush())
.map_err(|e| VMError::IOError {
instruction: self.current_instruction().instruction(),
source: e,
})
.and(Ok(self.next_instruction()))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a really nice literate handling of the write/flush/map_err process, well done.

Comment on lines +338 to +341
assert!(matches!(
self.current_instruction(),
DecoratedInstruction::OpenLoop { .. }
));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surely this function won't be called unless the current instruction is an openloop?

.prog
.position_to_index(closer.line(), closer.character())
+ 1),
_ => unreachable!(),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assert/matches above is also handled here since unreachable!() will panic if it's ever reached.

closer,
} => Ok(self
.prog
.position_to_index(closer.line(), closer.character())

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a conversion which could have been precomputed and stored in the instruction stream.

While I wouldn't always advocate precomputing things, in this instance the use of this data will be frequent and on the critical path of most BF programs.

Comment on lines +358 to +361
assert!(matches!(
self.current_instruction(),
DecoratedInstruction::CloseLoop { .. }
));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comments as above re: assert/matches and the unreachable below

opener,
} => Ok(self
.prog()
.position_to_index(opener.line(), opener.character())),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And for this computation step

Comment on lines +380 to +399
self.instruction_pointer = self.interpret_current_instruction(input, output)?
}
Ok(())
}

fn interpret_current_instruction(
&mut self,
input: &mut impl Read,
output: &mut impl Write,
) -> Result<usize, VMError> {
match self.current_instruction().instruction().instruction() {
RawInstruction::OpenLoop => self.open_loop(),
RawInstruction::CloseLoop => self.close_loop(),
RawInstruction::DecrementDataPointer => self.seek_left(),
RawInstruction::IncrementDataPointer => self.seek_right(),
RawInstruction::IncrementByte => self.increment_cell(),
RawInstruction::DecrementByte => self.decrement_cell(),
RawInstruction::GetByte => self.read_value(input),
RawInstruction::PutByte => self.write_value(output),
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I'd not have had a separate method for interpreting a single instruction, though this isn't entirely bad.

.then(instruction.character().cmp(&character))
})
.unwrap()
// >:| I can't just search for the DecoratedInstruction because I don't store it

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not store an index -> index map instead (perhaps as a Vec<usize>)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants