yarbf 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ ++++++++++.