yarbf 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +29 -0
  3. data/.gitignore +1 -1
  4. data/.rubocop.yml +1168 -0
  5. data/bin/yarbf +2 -2
  6. data/lib/yarbf.rb +147 -73
  7. data/lib/yarbf/version.rb +1 -1
  8. data/test/bf/hello-world.bf +15 -0
  9. data/test/bf/pi.bf +229 -0
  10. data/test/bf/show-bf.bf +17 -0
  11. data/test/bf/square.bf +79 -0
  12. data/test/helper.rb +40 -0
  13. data/test/input/cell_size/pi-10 +0 -0
  14. data/test/input/cell_size/pi-11 +0 -0
  15. data/test/input/cell_size/pi-12 +0 -0
  16. data/test/input/cell_size/pi-16 +0 -0
  17. data/test/input/cell_size/pi-8 +0 -0
  18. data/test/input/cell_size/pi-9 +0 -0
  19. data/test/input/debug/hello-world +0 -0
  20. data/test/input/debug/pi +0 -0
  21. data/test/input/debug/show-bf +1 -0
  22. data/test/input/debug/square +0 -0
  23. data/test/input/hello-world +0 -0
  24. data/test/input/input_mode/show-bf-buffered +1 -0
  25. data/test/input/input_mode/show-bf-raw +1 -0
  26. data/test/input/pi +0 -0
  27. data/test/input/show-bf +1 -0
  28. data/test/input/square +0 -0
  29. data/test/input/wrap_around/pi +0 -0
  30. data/test/output/cell_size/pi-10-1 +1 -0
  31. data/test/output/cell_size/pi-10-2 +1 -0
  32. data/test/output/cell_size/pi-11-1 +1 -0
  33. data/test/output/cell_size/pi-11-2 +0 -0
  34. data/test/output/cell_size/pi-12-1 +1 -0
  35. data/test/output/cell_size/pi-12-2 +0 -0
  36. data/test/output/cell_size/pi-16-1 +1 -0
  37. data/test/output/cell_size/pi-16-2 +0 -0
  38. data/test/output/cell_size/pi-32-1 +1 -0
  39. data/test/output/cell_size/pi-32-2 +0 -0
  40. data/test/output/cell_size/pi-8-1 +0 -0
  41. data/test/output/cell_size/pi-8-2 +1 -0
  42. data/test/output/cell_size/pi-9-1 +1 -0
  43. data/test/output/cell_size/pi-9-2 +1 -0
  44. data/test/output/construct_program_units/hello-world-1 +106 -0
  45. data/test/output/construct_program_units/pi-1 +648 -0
  46. data/test/output/construct_program_units/show-bf-1 +49 -0
  47. data/test/output/construct_program_units/square-1 +191 -0
  48. data/test/output/debug/hello-world-1 +1 -0
  49. data/test/output/debug/hello-world-2 +1 -0
  50. data/test/output/debug/pi-1 +0 -0
  51. data/test/output/debug/pi-2 +1 -0
  52. data/test/output/debug/show-bf-1 +1 -0
  53. data/test/output/debug/show-bf-2 +1 -0
  54. data/test/output/debug/square-1 +101 -0
  55. data/test/output/debug/square-2 +1 -0
  56. data/test/output/hello-world-1 +1 -0
  57. data/test/output/hello-world-2 +0 -0
  58. data/test/output/input_mode/show-bf-buffered-1 +1 -0
  59. data/test/output/input_mode/show-bf-buffered-2 +0 -0
  60. data/test/output/input_mode/show-bf-raw-1 +0 -0
  61. data/test/output/input_mode/show-bf-raw-2 +1 -0
  62. data/test/output/match_brackets/hello-world-1 +106 -0
  63. data/test/output/match_brackets/pi-1 +648 -0
  64. data/test/output/match_brackets/show-bf-1 +49 -0
  65. data/test/output/match_brackets/square-1 +191 -0
  66. data/test/output/pi-1 +0 -0
  67. data/test/output/pi-2 +1 -0
  68. data/test/output/show-bf-1 +1 -0
  69. data/test/output/show-bf-2 +0 -0
  70. data/test/output/square-1 +101 -0
  71. data/test/output/square-2 +0 -0
  72. data/test/output/wrap_around/pi-1 +1 -0
  73. data/test/output/wrap_around/pi-2 +0 -0
  74. data/test/test_bf_interpreter.rb +116 -0
  75. data/test/test_cell_size.rb +29 -0
  76. data/test/test_debug.rb +25 -0
  77. data/test/test_default.rb +19 -0
  78. data/test/test_input_mode.rb +29 -0
  79. data/test/test_wrap_around.rb +25 -0
  80. data/yarbf.gemspec +1 -1
  81. metadata +76 -2
data/bin/yarbf CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
1
+ #!/usr/bin/env ruby -w
2
2
 
3
3
  lib = File.expand_path('../../lib', __FILE__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
@@ -8,7 +8,7 @@ require 'yarbf'
8
8
 
9
9
  # overrides the default #Kernel.fail.
10
10
  def fail(reason)
11
- STDERR.puts File.basename($0) + ': ' + reason.to_s
11
+ $stderr.puts File.basename($0) + ': ' + reason.to_s
12
12
  exit false
13
13
  end
14
14
 
@@ -9,10 +9,36 @@ module Yarbf
9
9
  # available options for input mode
10
10
  INPUT_MODE_OPTIONS = [:buffered, :raw] # :nodoc:
11
11
 
12
+ module BooleanJudge
13
+ ##
14
+ # Determines and returns whether an object is a boolean value.
15
+ #
16
+ # +obj+:: An #Object.
17
+ # +&block+:: A block to call when true.
18
+ #
19
+ def is_boolean?(obj, &block)
20
+ result = [true, false].include?(obj)
21
+ yield if result && !block.nil?
22
+ result
23
+ end
24
+
25
+ ##
26
+ # Determines and returns whether an object is not a boolean value.
27
+ #
28
+ # +obj+:: An #Object.
29
+ # +&block+:: A block to call when true.
30
+ #
31
+ def not_boolean?(obj, &block)
32
+ result = [true, false].include?(obj)
33
+ yield unless result || block.nil?
34
+ result
35
+ end
36
+ end
37
+
12
38
  ##
13
39
  # == BfInterpreter
14
40
  #
15
- # BfInterpreter is the main class of module #YARBF.
41
+ # BfInterpreter is the main class of module #Yarbf.
16
42
  #
17
43
  # === Options
18
44
  #
@@ -42,27 +68,37 @@ module Yarbf
42
68
  # :cell_size => 16,
43
69
  # :input_mode => :buffered
44
70
  # }
45
- # interpreter = YARBF::BfInterpreter.new(options)
71
+ # interpreter = Yarbf::BfInterpreter.new(options)
46
72
  # interpreter.run('/path/to/Brainfuck/source')
47
73
  #
48
74
  class BfInterpreter
75
+ include BooleanJudge
76
+
49
77
  ##
50
78
  # Initialize the instance.
51
79
  #
52
80
  # +options+:: A Hash containing options to the interpreter.
53
81
  #
54
82
  def initialize(options)
55
- unless options.is_a? Hash and OPTIONS.all? { |s| options.has_key? s }
56
- fail 'Invalid options given!'
83
+ unless options.is_a?(Hash) && OPTIONS.all? { |s| options.has_key? s }
84
+ fail 'Missing required options!'
57
85
  end
58
- @option = options.dup
86
+ @options = options.select { |k| OPTIONS.include? k }
87
+ end
88
+
89
+ ##
90
+ # Returns a human-readable string describing the interpreter.
91
+ #
92
+ def inspect
93
+ @options.inspect
59
94
  end
95
+ alias_method :to_s, :inspect
60
96
 
61
97
  ##
62
98
  # Returns whether the interpreter is in debug mode.
63
99
  #
64
100
  def debug?
65
- @option[:debug]
101
+ @options[:debug]
66
102
  end
67
103
 
68
104
  ##
@@ -71,17 +107,17 @@ module Yarbf
71
107
  # +debug+:: A boolean value.
72
108
  #
73
109
  def debug=(debug)
74
- unless debug.is_a?(TrueClass) or debug.is_a?(FalseClass)
110
+ not_boolean?(debug) do
75
111
  fail "'debug' switch should be a boolean but is a #{debug.class}!"
76
112
  end
77
- @option[:debug] = debug
113
+ @options[:debug] = debug
78
114
  end
79
115
 
80
116
  ##
81
117
  # Returns whether the interpreter accepts wrap around.
82
118
  #
83
119
  def wrap_around?
84
- @option[:wrap_around]
120
+ @options[:wrap_around]
85
121
  end
86
122
 
87
123
  ##
@@ -90,17 +126,17 @@ module Yarbf
90
126
  # +wrap_around+:: A boolean value.
91
127
  #
92
128
  def wrap_around=(wrap_around)
93
- unless wrap_around.is_a?(TrueClass) or wrap_around.is_a?(FalseClass)
129
+ not_boolean?(wrap_around) do
94
130
  fail "'wrap_around' should be a boolean but is a #{wrap_around.class}!"
95
131
  end
96
- @option[:wrap_around] = wrap_around
132
+ @options[:wrap_around] = wrap_around
97
133
  end
98
134
 
99
135
  ##
100
136
  # Returns the size of each tape cell.
101
137
  #
102
138
  def cell_size?
103
- @option[:cell_size]
139
+ @options[:cell_size]
104
140
  end
105
141
 
106
142
  ##
@@ -112,14 +148,14 @@ module Yarbf
112
148
  unless cell_size.is_a? Integer
113
149
  fail "'cell_size' should be an integer but is a #{cell_size.class}!"
114
150
  end
115
- @option[:cell_size] = cell_size
151
+ @options[:cell_size] = cell_size
116
152
  end
117
153
 
118
154
  ##
119
155
  # Returns the current input mode.
120
156
  #
121
157
  def input_mode?
122
- @option[:input_mode]
158
+ @options[:input_mode]
123
159
  end
124
160
 
125
161
  ##
@@ -131,7 +167,7 @@ module Yarbf
131
167
  unless INPUT_MODE_OPTIONS.include? input_mode
132
168
  fail 'Invalid value of input mode!'
133
169
  end
134
- @option[:input_mode] = input_mode
170
+ @options[:input_mode] = input_mode
135
171
  end
136
172
 
137
173
  ##
@@ -146,8 +182,7 @@ module Yarbf
146
182
  begin
147
183
  File.open(src) { |file| units = construct_program_units(file) }
148
184
  rescue SystemCallError => e
149
- STDERR.puts $0 + ': ' + e.to_s
150
- return
185
+ fail e.to_s
151
186
  end
152
187
 
153
188
  # match brackets
@@ -158,47 +193,9 @@ module Yarbf
158
193
  position = 0
159
194
  unit = units[0]
160
195
  until unit.nil?
161
- tape[position] = BfCell.new(cell_size?) if tape[position].nil?
162
-
163
- STDERR.printf('%s', unit.instruction) if debug?
164
-
165
- case unit.instruction
166
- when '+' then
167
- tape[position].increase(1, wrap_around?)
168
- when '-' then
169
- tape[position].decrease(1, wrap_around?)
170
- when '<' then
171
- position -= 1
172
- fail 'Cell position out of bound!' if position < 0
173
- when '>' then
174
- position += 1
175
- when ',' then
176
- ch = nil
177
- begin
178
- ch = STDIN.getc if input_mode? == :buffered
179
- ch = STDIN.getch if input_mode? == :raw
180
- rescue SystemCallError => e
181
- fail e.to_s
182
- end
183
- return if ch.nil?
184
- tape[position].value = ch.ord
185
- when '.' then
186
- STDOUT.putc tape[position].value
187
- when '[' then
188
- if tape[position].value == 0
189
- unit = unit.match
190
- next
191
- end
192
- when ']' then
193
- if tape[position].value != 0
194
- unit = unit.match
195
- next
196
- end
197
- else
198
- fail "Invalid instruction '#{unit.instruction}'!"
199
- end
200
-
201
- unit = unit.next
196
+ tape[position] = BfCell.new(position, cell_size?) if tape[position].nil?
197
+ $stderr.printf('%s', unit.instruction) if debug?
198
+ unit, position = deal_unit(unit, tape, position)
202
199
  end
203
200
  end
204
201
 
@@ -213,13 +210,13 @@ module Yarbf
213
210
 
214
211
  file.each_byte do |c|
215
212
  case c.chr
216
- when '+', '-', '<', '>', '[', ']', '.', ',' then
217
- unit = BfProgramUnit.new(c.chr)
218
- units[position - 1].next = unit if position > 0
219
- units[position] = unit
220
- position += 1
221
- else
222
- # other characters are considered as comments, do nothing
213
+ when '+', '-', '<', '>', '[', ']', '.', ',' then
214
+ unit = BfProgramUnit.new(c.chr, position)
215
+ units[position - 1].next = unit if position > 0
216
+ units[position] = unit
217
+ position += 1
218
+ else
219
+ # other characters are considered as comments, do nothing
223
220
  end
224
221
  end
225
222
 
@@ -229,7 +226,7 @@ module Yarbf
229
226
  ##
230
227
  # Matches each bracket '[' and ']' in the source.
231
228
  #
232
- # +units+:: An #Array of program units.
229
+ # +units+:: An #Array of #BfProgramUnit.
233
230
  #
234
231
  def match_brackets(units)
235
232
  units.each_index do |i|
@@ -254,19 +251,89 @@ module Yarbf
254
251
  end
255
252
  end
256
253
 
257
- private :construct_program_units, :match_brackets
254
+ ##
255
+ # Reads and returns the next character from stdin.
256
+ #
257
+ def get_char
258
+ ch = nil
259
+ begin
260
+ ch = $stdin.getc if input_mode? == :buffered
261
+ ch = $stdin.getch if input_mode? == :raw
262
+ rescue SystemCallError => e
263
+ fail e.to_s
264
+ end
265
+ ch
266
+ end
267
+
268
+ ##
269
+ # Deals with the current program unit, and returns the next program unit
270
+ # and tape position.
271
+ #
272
+ # +unit+:: The current program unit.
273
+ # +tape+:: An #Array of #BfCell.
274
+ # +position+:: The current position on the #tape.
275
+ #
276
+ def deal_unit(unit, tape, position)
277
+ case unit.instruction
278
+ when '+' then
279
+ tape[position].increase(1, wrap_around?)
280
+ unit = unit.next
281
+ when '-' then
282
+ tape[position].decrease(1, wrap_around?)
283
+ unit = unit.next
284
+ when '<' then
285
+ position -= 1
286
+ fail 'Cell position out of bound!' if position < 0
287
+ unit = unit.next
288
+ when '>' then
289
+ position += 1
290
+ unit = unit.next
291
+ when ',' then
292
+ ch = get_char
293
+ return nil, nil if ch.nil?
294
+ tape[position].value = ch.ord
295
+ unit = unit.next
296
+ when '.' then
297
+ $stdout.putc tape[position].value
298
+ unit = unit.next
299
+ when '[' then
300
+ if tape[position].value == 0
301
+ unit = unit.match
302
+ else
303
+ unit = unit.next
304
+ end
305
+ when ']' then
306
+ if tape[position].value != 0
307
+ unit = unit.match
308
+ else
309
+ unit = unit.next
310
+ end
311
+ else
312
+ fail "Invalid instruction '#{unit.instruction}'!"
313
+ end
314
+ return unit, position
315
+ end
316
+
317
+ private :construct_program_units, :match_brackets, :get_char, :deal_unit
258
318
 
259
319
  ##
260
320
  # Cell of the Brainfuck tape.
261
321
  #
262
322
  class BfCell
323
+ attr_reader :position
263
324
  attr_accessor :cell_size, :value
264
325
 
265
- def initialize(cell_size = 8, value = 0)
326
+ def initialize(position, cell_size = 8, value = 0)
327
+ @position = position
266
328
  @cell_size = cell_size
267
329
  @value = value
268
330
  end
269
331
 
332
+ def inspect
333
+ "{ pos: #{@position}, value: #{@value} }"
334
+ end
335
+ alias_method :to_s, :inspect
336
+
270
337
  ##
271
338
  # Increase the value of a cell.
272
339
  #
@@ -297,16 +364,23 @@ module Yarbf
297
364
  # Program unit of Brainfuck.
298
365
  #
299
366
  class BfProgramUnit
300
- attr_reader :instruction
367
+ attr_reader :instruction, :position
368
+ attr_accessor :match, :next
301
369
 
302
- attr_accessor :match
303
- attr_accessor :next
304
-
305
- def initialize(instruction)
370
+ def initialize(instruction, position)
306
371
  @instruction = instruction
372
+ @position = position
307
373
  @match = nil
308
374
  @next = nil
309
375
  end
376
+
377
+ def inspect
378
+ s = "{ ins: '#{@instruction}', pos: #{@position}"
379
+ s += ", next: #{@next.position}" unless @next.nil?
380
+ s += ", match: #{@match.position}" unless @match.nil?
381
+ s + ' }'
382
+ end
383
+ alias_method :to_s, :inspect
310
384
  end
311
385
  end
312
386
  end
@@ -1,4 +1,4 @@
1
1
  module Yarbf
2
2
  # gem version
3
- VERSION = '0.1.0'
3
+ VERSION = '0.1.1'
4
4
  end
@@ -0,0 +1,15 @@
1
+ print "Hello World!" with a line feed
2
+
3
+ ++++++++
4
+ [
5
+ >++++
6
+ [
7
+ >++>+++>+++>+<<<<-
8
+ ]
9
+ >+>+>->>+
10
+ [
11
+ <
12
+ ]
13
+ <-
14
+ ]
15
+ >>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.
@@ -0,0 +1,229 @@
1
+ calculate and print value of Pi
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
+ -
151
+ [
152
+ -
153
+ [
154
+ -
155
+ [
156
+ -<->
157
+ [
158
+ -<+<->>
159
+ ]
160
+ ]
161
+ ]
162
+ ]
163
+ ]
164
+ ]
165
+ ]
166
+ ]
167
+ ]
168
+ ]
169
+ <
170
+ [
171
+ +++++
172
+ [
173
+ <<<++++++++<++++++++>>>>-
174
+ ]
175
+ <<<<+<->>>>
176
+ [
177
+ >+<<<+++++++++<->>>-
178
+ ]
179
+ <<<<<
180
+ [
181
+ >>+<<-
182
+ ]
183
+ +<
184
+ [
185
+ ->-<
186
+ ]
187
+ >
188
+ [
189
+ >>.<<<<
190
+ [
191
+ +.
192
+ [
193
+ -
194
+ ]
195
+ ]
196
+ >>-
197
+ ]
198
+ >
199
+ [
200
+ >>.<<-
201
+ ]
202
+ >
203
+ [
204
+ -
205
+ ]
206
+ >
207
+ [
208
+ -
209
+ ]
210
+ >>>
211
+ [
212
+ >>
213
+ [
214
+ <<<<<<<<+>>>>>>>>-
215
+ ]
216
+ <<-
217
+ ]
218
+ ]
219
+ >>
220
+ [
221
+ -
222
+ ]
223
+ <<<
224
+ [
225
+ -
226
+ ]
227
+ <<<<<<<<
228
+ ]
229
+ ++++++++++.