This commit is contained in:
lilymonade 2025-03-13 22:24:34 +01:00
parent 2ddc195b73
commit d8ea42b795
Signed by: lilymonade
GPG Key ID: F8967EC454DBDCB6
5 changed files with 92 additions and 3 deletions

View File

@ -59,3 +59,7 @@ exercises:
- "compute_division_by_zero_push"
- "compute_division_by_zero_operation"
- "compute_all_ops"
- "compute_add"
- "compute_sub"
- "compute_mul"
- "compute_div"

View File

@ -56,3 +56,23 @@ pub fn compute_all_ops() {
Ok(3.0),
);
}
#[test]
pub fn compute_add() {
assert_eq!(compute(&[Operation::Push(1.0), Operation::Push(2.0), Operation::Binary(Binary::Add)]), Ok(3.0));
}
#[test]
pub fn compute_sub() {
assert_eq!(compute(&[Operation::Push(1.0), Operation::Push(2.0), Operation::Binary(Binary::Sub)]), Ok(-1.0));
}
#[test]
pub fn compute_mul() {
assert_eq!(compute(&[Operation::Push(3.0), Operation::Push(2.0), Operation::Binary(Binary::Mul)]), Ok(6.0));
}
#[test]
pub fn compute_div() {
assert_eq!(compute(&[Operation::Push(42.0), Operation::Push(7.0), Operation::Binary(Binary::Div)]), Ok(6.0));
}

View File

@ -6,6 +6,7 @@
   │   └── result.rs
   ├── errors.rs
   ├── vec
   │   └── access.rs
   │   ├── access.rs
   │   └── compute.rs
   ├── vec.rs
   └── lib.rs

View File

@ -0,0 +1,64 @@
---
name = "Compute simple Forth expressions"
file = "src/vec/compute.rs"
---
[Forth](https://en.wikipedia.org/wiki/Forth_(programming_language)) is a stack based programming language based on the [Reverse Polish Notation](https://en.wikipedia.org/wiki/Reverse_Polish_notation). In this language, a program is expressed as a stream of words, each word representing an instruction. For example, this expression:
```
1.0 2.0 +
```
represent a program made of 3 words: `1.0` meaning "push the number 1.0" on the stack, `2.0` meaning push 2.0 on the stack, and `+` meaning "pop the two highest numbers off the stack, and push their sum". We will first define some types to represent such program, and then implement the `compute` function, taking a `slice` of operations and giving the result of computing these operations.
```rust
/// Possible operations
pub enum Operation {
Push(f32),
Binary(Binary),
}
/// Different binary operators
pub enum Binary {
/// +
Add,
/// -
Sub,
/// *
Mul,
/// /
Div,
}
/// What could go wrong when computing a Forth expression
#[derive(PartialEq, Debug)]
pub enum ComputeError {
NotEnoughData,
DivisionByZero,
}
```
```prototype
pub fn compute(operations: &[Operation]) -> Result<f32, ComputeError> {
unimplemented!()
}
```
```example
fn main() {
// 1 2 3 * +
// gives the result 7 because it's computed as 1 + 2 * 3
assert_eq!(
compute(&[
Operation::Push(1.0),
Operation::Push(2.0),
Operation::Push(3.0),
Operation::Binary(Binary::Mul),
Operation::Binary(Binary::Add),
]),
Ok(7.0)
);
assert_eq!(compute(&[Operation::Binary(Binary::Add)), Err(ComputeError::NotEnoughData));
}
```

View File

@ -1,7 +1,7 @@
---
name = "Vecs and slices"
difficulty = 2
exercises = ["access.md"]
difficulty = 5
exercises = ["access.md", "compute.md"]
---
Let's now look at some functions on [`slice`](https://doc.rust-lang.org/std/primitive.slice.html)s and [`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html)s. Instead of manualy checking things we will follow the type system using `Option`s and `Result`s we saw earlier.