forked from elm-city-craftworks/turing_tarpit
/
turing_tarpit.rb
150 lines (120 loc) · 2.83 KB
/
turing_tarpit.rb
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
require "io/console"
module TuringTarpit
PointerBoundaryError = Class.new(StandardError)
InvalidValue = Class.new(StandardError)
class Interpreter
def initialize(scanner, tape)
@scanner = scanner
@tape = tape
end
def run
loop do
case @scanner.next(@tape.cell_value)
when "+"
@tape.increment_cell_value
when "-"
@tape.decrement_cell_value
when ">"
@tape.increment_pointer
when "<"
@tape.decrement_pointer
when "."
print("" << @tape.cell_value)
when ","
value = STDIN.getch.bytes.first
next if value.zero?
@tape.cell_value = value
end
end
end
end
class Scanner
def initialize(source_text)
@chars = source_text.chars.to_a
@index = 0
end
def next(cell_value)
validate_index
element = @chars[@index]
case element
when "["
jump_forward if cell_value.zero?
consume
element = @chars[@index]
when "]"
if cell_value.zero?
while element == "]"
consume
element = @chars[@index]
validate_index
end
else
jump_back
consume
element = @chars[@index]
end
end
consume
element
end
private
def validate_index
raise StopIteration if @chars.length == @index
end
def consume
@index += 1
end
def jump_forward
jump("[", "]", 1)
end
def jump_back
jump("]", "[", -1)
end
def jump(from, to, step)
counter = 1
until counter == 0
@index += step
case @chars[@index]
when from
counter += 1
when to
counter -= 1
end
end
end
end
class Tape
CELL_SIZE = 256
def initialize
@pointer_position = 0
@cells = []
end
attr_reader :pointer_position
def cell_value
cells[pointer_position] ||= 0
end
def cell_value=(value)
raise InvalidValue unless valid_cell_value?(value)
cells[pointer_position] = value
end
def increment_cell_value
self.cell_value = (cell_value + 1) % CELL_SIZE
end
def decrement_cell_value
self.cell_value = (cell_value - 1) % CELL_SIZE
end
def increment_pointer
self.pointer_position = pointer_position + 1
end
def decrement_pointer
raise PointerBoundaryError unless pointer_position > 0
self.pointer_position = pointer_position - 1
end
private
attr_reader :cells
attr_writer :pointer_position
def valid_cell_value?(value)
value.kind_of?(Integer) && value.between?(0,CELL_SIZE-1)
end
end
end