-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstack_machine.deed
More file actions
66 lines (56 loc) · 2.11 KB
/
Copy pathstack_machine.deed
File metadata and controls
66 lines (56 loc) · 2.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// A tiny stack machine: push a number, or combine the top two with an
// operator. Four instructions, and the interesting part is `applied`,
// which is one function for all three binary operators because the
// operator itself is the parameter, the same shape `logs.deed` uses to
// take a walk's question as an argument.
module examples/stack_machine
use std/list.{take, drop, last}
choice Instruction {
Push { value: Int },
Add,
Sub,
Mul,
}
fn applied(stack: List<Int>, op: Fn(Int, Int) -> Int) -> List<Int> {
let rest = take(stack, length(stack) - 2)
let top = drop(stack, length(stack) - 2)
match at(top, 0) {
ok(first) => match at(top, 1) {
ok(second) => push(rest, op(first, second)),
err(_) => stack,
},
err(_) => stack,
}
}
fn step(stack: List<Int>, instruction: Instruction) -> List<Int> {
match instruction {
Push { value } => push(stack, value),
Add => applied(stack, |a: Int, b: Int| a + b),
Sub => applied(stack, |a: Int, b: Int| a - b),
Mul => applied(stack, |a: Int, b: Int| a * b),
}
}
fn run(program: List<Instruction>) -> List<Int> {
for instruction in program with stack = [] {
step(stack, instruction)
}
}
fn result_of(program: List<Instruction>) -> Result<Int, String> {
last(run(program))
}
test "push builds the stack in order" {
assert run([Push { value: 1 }, Push { value: 2 }, Push { value: 3 }]) == [1, 2, 3]
}
test "each operator combines the top two and leaves the rest untouched" {
assert result_of([Push { value: 2 }, Push { value: 3 }, Add]) == ok(5)
assert result_of([Push { value: 5 }, Push { value: 3 }, Sub]) == ok(2)
assert result_of([Push { value: 4 }, Push { value: 3 }, Mul]) == ok(12)
assert run([Push { value: 1 }, Push { value: 2 }, Push { value: 3 }, Add]) == [1, 5]
}
test "an operator with nothing to combine leaves the stack alone" {
assert run([Add]) == []
assert run([Push { value: 1 }, Add]) == [1]
}
test "a short program with no instructions has no result" {
assert result_of([]) == err("index -1 is outside a list of 0")
}