brainfucktt 0.1.1 → 0.1.2

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.
data/Rakefile CHANGED
@@ -23,6 +23,7 @@ spec = Gem::Specification.new do |s|
23
23
  s.add_dependency 'treetop', '~> 1.4'
24
24
  s.add_dependency 'polyglot', '~> 0.3'
25
25
  s.add_dependency 'version', '~> 1.0'
26
+ s.add_dependency 'slop', '~> 3.3'
26
27
  s.add_development_dependency 'at', '~> 0.1'
27
28
  s.add_development_dependency 'rake', '~> 10.0'
28
29
  s.add_development_dependency 'guard-rspec', '~> 2.1'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.1.2
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'brainfucktt/repl'
4
+ require 'slop'
5
+
6
+ opts = Slop.parse help: true do
7
+ banner "brainfucktt [options]\n Start the Brainfuck REPL"
8
+ end
9
+
10
+ if opts.help?
11
+ puts
12
+ puts Brainfucktt::REPL.instance.help.lines.collect { |line| " #{line}"}.join
13
+ else
14
+ Brainfucktt::REPL.run
15
+ end
@@ -2,14 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "brainfucktt"
5
- s.version = "0.1.1"
5
+ s.version = "0.1.2"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Ryan Scott Lewis"]
9
9
  s.date = "2012-12-06"
10
10
  s.description = "A Brainfuck interpreter built using Treetop."
11
11
  s.email = "ryan@rynet.us"
12
- s.files = ["Gemfile", "LICENSE", "README.md", "Rakefile", "VERSION", "brainfucktt.gemspec", "examples/hello_world.rb", "examples/hello_world_with_comments.rb", "examples/stringio.rb", "lib/brainfucktt.rb", "lib/brainfucktt/byte.rb", "lib/brainfucktt/conversion_helpers.rb", "lib/brainfucktt/data.rb", "lib/brainfucktt/errors.rb", "lib/brainfucktt/language.rb", "lib/brainfucktt/language/decrement_byte.rb", "lib/brainfucktt/language/decrement_pointer.rb", "lib/brainfucktt/language/increment_byte.rb", "lib/brainfucktt/language/increment_pointer.rb", "lib/brainfucktt/language/input_byte.rb", "lib/brainfucktt/language/loop.rb", "lib/brainfucktt/language/output_byte.rb", "lib/brainfucktt/language/tree.rb", "lib/brainfucktt/language_parser.treetop", "lib/brainfucktt/node.rb", "lib/brainfucktt/parser.rb"]
12
+ s.executables = ["brainfucktt"]
13
+ s.files = ["Gemfile", "LICENSE", "README.md", "Rakefile", "VERSION", "bin/brainfucktt", "brainfucktt.gemspec", "examples/hello_world.rb", "examples/hello_world_with_comments.rb", "examples/rot13.rb", "examples/square_numbers.rb", "examples/stringio.rb", "examples/system_bell.rb", "lib/brainfucktt.rb", "lib/brainfucktt/byte.rb", "lib/brainfucktt/conversion_helpers.rb", "lib/brainfucktt/data.rb", "lib/brainfucktt/errors.rb", "lib/brainfucktt/language.rb", "lib/brainfucktt/language/decrement_byte.rb", "lib/brainfucktt/language/decrement_pointer.rb", "lib/brainfucktt/language/increment_byte.rb", "lib/brainfucktt/language/increment_pointer.rb", "lib/brainfucktt/language/input_byte.rb", "lib/brainfucktt/language/loop.rb", "lib/brainfucktt/language/output_byte.rb", "lib/brainfucktt/language/tree.rb", "lib/brainfucktt/language_parser.treetop", "lib/brainfucktt/node.rb", "lib/brainfucktt/parser.rb", "lib/brainfucktt/repl.rb"]
13
14
  s.homepage = "http://github.com/RyanScottLewis/brainfucktt"
14
15
  s.require_paths = ["lib"]
15
16
  s.rubygems_version = "1.8.24"
@@ -22,6 +23,7 @@ Gem::Specification.new do |s|
22
23
  s.add_runtime_dependency(%q<treetop>, ["~> 1.4"])
23
24
  s.add_runtime_dependency(%q<polyglot>, ["~> 0.3"])
24
25
  s.add_runtime_dependency(%q<version>, ["~> 1.0"])
26
+ s.add_runtime_dependency(%q<slop>, ["~> 3.3"])
25
27
  s.add_development_dependency(%q<at>, ["~> 0.1"])
26
28
  s.add_development_dependency(%q<rake>, ["~> 10.0"])
27
29
  s.add_development_dependency(%q<guard-rspec>, ["~> 2.1"])
@@ -34,6 +36,7 @@ Gem::Specification.new do |s|
34
36
  s.add_dependency(%q<treetop>, ["~> 1.4"])
35
37
  s.add_dependency(%q<polyglot>, ["~> 0.3"])
36
38
  s.add_dependency(%q<version>, ["~> 1.0"])
39
+ s.add_dependency(%q<slop>, ["~> 3.3"])
37
40
  s.add_dependency(%q<at>, ["~> 0.1"])
38
41
  s.add_dependency(%q<rake>, ["~> 10.0"])
39
42
  s.add_dependency(%q<guard-rspec>, ["~> 2.1"])
@@ -47,6 +50,7 @@ Gem::Specification.new do |s|
47
50
  s.add_dependency(%q<treetop>, ["~> 1.4"])
48
51
  s.add_dependency(%q<polyglot>, ["~> 0.3"])
49
52
  s.add_dependency(%q<version>, ["~> 1.0"])
53
+ s.add_dependency(%q<slop>, ["~> 3.3"])
50
54
  s.add_dependency(%q<at>, ["~> 0.1"])
51
55
  s.add_dependency(%q<rake>, ["~> 10.0"])
52
56
  s.add_dependency(%q<guard-rspec>, ["~> 2.1"])
@@ -1,8 +1,6 @@
1
1
  require_relative '../lib/brainfucktt'
2
2
 
3
- code = DATA.read
4
-
5
- Brainfucktt.run(code)
3
+ Brainfucktt.run( DATA.read )
6
4
 
7
5
  __END__
8
6
  +++++ +++++ initialize counter (cell #0) to 10
@@ -0,0 +1,37 @@
1
+ require_relative '../lib/brainfucktt'
2
+
3
+ Brainfucktt.run( DATA.read )
4
+
5
+ __END__
6
+ WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
7
+ THIS IS SLOW THIS IS SLOW THIS IS SLOW THIS IS SLOW THIS IS SLOW THIS IS SLOW
8
+ WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
9
+
10
+ -,+[ Read first character and start outer character reading loop
11
+ -[ Skip forward if character is 0
12
+ >>++++[>++++++++<-] Set up divisor (32) for division loop
13
+ (MEMORY LAYOUT: dividend copy remainder divisor quotient zero zero)
14
+ <+<-[ Set up dividend (x minus 1) and enter division loop
15
+ >+>+>-[>>>] Increase copy and remainder / reduce divisor / Normal case: skip forward
16
+ <[[>+<-]>>+>] Special case: move remainder back to divisor and increase quotient
17
+ <<<<<- Decrement dividend
18
+ ] End division loop
19
+ ]>>>[-]+ End skip loop; zero former divisor and reuse space for a flag
20
+ >--[-[<->+++[-]]]<[ Zero that flag unless quotient was 2 or 3; zero quotient; check flag
21
+ ++++++++++++<[ If flag then set up divisor (13) for second division loop
22
+ (MEMORY LAYOUT: zero copy dividend divisor remainder quotient zero zero)
23
+ >-[>+>>] Reduce divisor; Normal case: increase remainder
24
+ >[+[<+>-]>+>>] Special case: increase remainder / move it back to divisor / increase quotient
25
+ <<<<<- Decrease dividend
26
+ ] End division loop
27
+ >>[<+>-] Add remainder back to divisor to get a useful 13
28
+ >[ Skip forward if quotient was 0
29
+ -[ Decrement quotient and skip forward if quotient was 1
30
+ -<<[-]>> Zero quotient and divisor if quotient was 2
31
+ ]<<[<<->>-]>> Zero divisor and subtract 13 from copy if quotient was 1
32
+ ]<<[<<+>>-] Zero divisor and add 13 to copy if quotient was 0
33
+ ] End outer skip loop (jump to here if ((character minus 1)/32) was not 2 or 3)
34
+ <[-] Clear remainder from first division if second division was skipped
35
+ <.[-] Output ROT13ed character from copy and clear it
36
+ <-,+ Read next character
37
+ ] End character reading loop
@@ -0,0 +1,37 @@
1
+ # require 'brainfucktt'
2
+ $:.unshift(File.expand_path(File.join(__FILE__, '..', '..', 'lib-compiled')))
3
+ Rubinius::CodeLoader.require_compiled 'brainfucktt'
4
+
5
+ Brainfucktt.run( DATA.read )
6
+
7
+ =begin Benchmarks
8
+
9
+ ruby 1.9.3p327 (2012-11-10 revision 37606) [x86_64-darwin12.2.0]
10
+
11
+ real 0m9.986s
12
+ user 0m9.564s
13
+ sys 0m0.274s
14
+
15
+ rubinius 2.0.0rc1 (1.8.7 release 2012-11-02 JI) [x86_64-apple-darwin12.2.0]
16
+
17
+ uncompiled
18
+
19
+ real 0m5.828s
20
+ user 0m6.330s
21
+ sys 0m0.233s
22
+
23
+ jruby 1.7.0 (1.9.3p203) 2012-10-22 ff1ebbe on Java HotSpot(TM) 64-Bit Server VM 1.6.0_37-b06-434-11M3909 [darwin-x86_64]
24
+
25
+ real 0m17.404s
26
+ user 0m26.151s
27
+ sys 0m1.402s
28
+
29
+
30
+ =end
31
+
32
+
33
+ __END__
34
+ ++++[>+++++<-]>[<+++++>-]+<+[>[>+>+<<-]++>>[<<+>>-]>>>[-]++>[-]+>>>+[[-]++++++>
35
+ >>]<<<[[<++++++++<++>>-]+<.<[>----<-]<]<<[>>>>>[>>>[-]+++++++++<[>-<-]+++++++++
36
+ >[-[<->-]+[<<<]]<[>+<-]>]<<-]<<-]
37
+
@@ -0,0 +1,3 @@
1
+ require_relative '../lib/brainfucktt'
2
+
3
+ Brainfucktt.run('+++++++.')
@@ -1,17 +1,30 @@
1
- require 'pathname'
2
- require 'forwardable'
3
-
4
- __LIB__ ||= Pathname.new(__FILE__).join('..').expand_path
5
- $:.unshift(__LIB__.to_s) unless $:.include?(__LIB__)
1
+ # require 'pathname'
2
+ #
3
+ # __LIB__ ||= Pathname.new(__FILE__).join('..').expand_path
4
+ # $:.unshift(__LIB__.to_s) unless $:.include?(__LIB__)
6
5
 
7
6
  require 'brainfucktt/parser'
8
7
 
9
8
  # A Brainfuck interpreter built in Ruby using Treetop.
10
9
  module Brainfucktt
11
10
  class << self
12
- extend Forwardable
13
11
 
14
- delegate [:parse, :run] => Parser
12
+ # Parse the given Brainfuck code.
13
+ #
14
+ # @param [String, #to_s] code
15
+ # @raise [Brainfucktt::ParserError]
16
+ # @return [Brainfucktt::Parser]
17
+ def parse(code)
18
+ Parser.parse(code)
19
+ end
20
+
21
+ # Parse and run the given Brainfuck code.
22
+ #
23
+ # @param [String, #to_s] code
24
+ # @param [Hash, #to_hash, #to_h] options
25
+ def run(code=nil, options={})
26
+ Parser.run(code, options)
27
+ end
15
28
 
16
29
  end
17
30
  end
@@ -44,7 +44,7 @@ module Brainfucktt
44
44
  #
45
45
  # @return [true, false]
46
46
  def ==(other)
47
- self == other
47
+ self.object_id == other.object_id
48
48
  end
49
49
 
50
50
  # Check to see if the given object instance as an Integer is the same as the value of
@@ -74,7 +74,7 @@ module Brainfucktt
74
74
  #
75
75
  # @return [String]
76
76
  def to_binary
77
- @value.to_s(2)
77
+ "%08b" % @value
78
78
  end
79
79
 
80
80
  # Return the Byte as an ASCII character.
@@ -89,7 +89,7 @@ module Brainfucktt
89
89
  #
90
90
  # @return [String]
91
91
  def to_hex
92
- @value.to_s(16)
92
+ '%02x' % @value
93
93
  end
94
94
 
95
95
  # Return the Byte as a binary string.
@@ -39,11 +39,6 @@ module Brainfucktt
39
39
 
40
40
  # Raised when the code being parsed has a syntax error.
41
41
  class ParserError < Error
42
- extend Forwardable
43
-
44
- def_delegator :@language_parser, :failure_reason, :reason
45
- def_delegator :@language_parser, :failure_line, :line
46
- def_delegator :@language_parser, :failure_column, :column
47
42
 
48
43
  # @param [Brainfucktt::LanguageParser] language_parser
49
44
  def initialize(language_parser)
@@ -57,6 +52,21 @@ module Brainfucktt
57
52
  "Error at column #{column}, line #{line} - '#{reason}'"
58
53
  end
59
54
 
55
+ # @return [String]
56
+ def reason
57
+ @language_parser.failure_reason
58
+ end
59
+
60
+ # @return [String]
61
+ def line
62
+ @language_parser.failure_line
63
+ end
64
+
65
+ # @return [String]
66
+ def column
67
+ @language_parser.failure_column
68
+ end
69
+
60
70
  end
61
71
 
62
72
  end
@@ -8,7 +8,7 @@ module Brainfucktt
8
8
 
9
9
  # Input an ASCII character and store it in the byte at the pointer.
10
10
  def run(parser)
11
- parser.byte = get_character(parser.stdin)
11
+ parser.byte = get_character(parser.input)
12
12
  end
13
13
 
14
14
  protected
@@ -8,7 +8,7 @@ module Brainfucktt
8
8
 
9
9
  # Run the loop
10
10
  def run(parser)
11
- elements.first.run(parser) until parser.byte.empty?
11
+ elements[0].run(parser) until parser.byte.empty?
12
12
  end
13
13
 
14
14
  end
@@ -5,13 +5,11 @@ module Brainfucktt
5
5
  # The base class for Brainfucktt syntax nodes in the AST
6
6
  class Node < Treetop::Runtime::SyntaxNode
7
7
 
8
- alias_method :elements_with_treetop, :elements
9
-
10
8
  # The children of this Node instance.
11
9
  #
12
10
  # @return [<Brainfucktt::Node>]
13
11
  def elements
14
- elements_with_treetop.find_all { |node| node.is_a?(Brainfucktt::Node) } rescue []
12
+ super.find_all { |node| node.is_a?(Brainfucktt::Node) } rescue []
15
13
  end
16
14
 
17
15
  # Return the text value of this Node instance.
@@ -16,9 +16,16 @@ module Brainfucktt
16
16
 
17
17
  # Get a new or the cached instance of this class.
18
18
  #
19
- # @return [Brainfucktt::LanguageParser]
19
+ # @return [Brainfucktt::Parser]
20
20
  def instance
21
- @instance ||= LanguageParser.new
21
+ @instance ||= new
22
+ end
23
+
24
+ # Get a new or the cached instance of this class.
25
+ #
26
+ # @return [Brainfucktt::Parser]
27
+ def language_parser
28
+ @language_parser ||= LanguageParser.new
22
29
  end
23
30
 
24
31
  # Parse the given Brainfuck code.
@@ -27,38 +34,55 @@ module Brainfucktt
27
34
  # @raise [Brainfucktt::ParserError]
28
35
  # @return [Brainfucktt::Parser]
29
36
  def parse(code)
30
- tree = instance.parse(code)
31
- raise ParserError, instance unless tree
32
-
33
- new(tree)
37
+ instance.parse(code)
34
38
  end
35
39
 
36
40
  # Parse and run the given Brainfuck code.
37
41
  #
38
42
  # @param [String, #to_s] code
39
- def run(code, options={})
40
- parse(code).run(options)
43
+ # @param [Hash, #to_hash, #to_h] options
44
+ def run(code=nil, options={})
45
+ instance.run(code, options)
41
46
  end
47
+
42
48
  end
43
49
 
44
50
  attr_reader :data, :tree, :input, :output
45
51
  attr_accessor :pointer
46
52
 
47
- def initialize(tree)
48
- @data, @tree, @pointer = Data.new, tree, 0
49
- end
53
+ def initialize(options={})
54
+ options = { :input => STDIN, :output => STDOUT }.merge( convert_to_options(options) )
50
55
 
56
+ @input, @output = options.values_at(:input, :output)
57
+ @data, @pointer, @tree = Data.new, 0, nil
58
+ end
59
+
51
60
  # Run the parsed Brainfuck code.
52
61
  #
53
- # @raise [Brainfucktt::InvalidOptionsError] When the given offset cannot be converted into an Integer.
62
+ # @param [String, #to_s] code The code to parse before running.
54
63
  # @param [Hash, #to_hash, #to_h] options
55
- def run(options={})
56
- options = { input: STDIN, output: STDOUT }.merge( convert_to_options(options) )
57
-
64
+ # @raise [Brainfucktt::InvalidOptionsError] When the given offset cannot be converted into an Integer.
65
+ def run(code=nil, options={})
66
+ options = { :input => @input, :output => @output }.merge( convert_to_options(options) )
58
67
  @input, @output = options.values_at(:input, :output)
68
+
69
+ parse(code) unless code.nil?
70
+
59
71
  @tree.run(self)
60
72
  end
61
73
 
74
+ # Parse the given Brainfuck code.
75
+ #
76
+ # @param [String, #to_s] code
77
+ # @raise [Brainfucktt::ParserError]
78
+ # @return [Brainfucktt::Parser]
79
+ def parse(code)
80
+ @tree = self.class.language_parser.parse(code)
81
+ raise ParserError, self unless @tree
82
+
83
+ self
84
+ end
85
+
62
86
  # Returns the Byte instance within the @data collection at pointer.
63
87
  #
64
88
  # @return [Brainfucktt::Byte]
@@ -0,0 +1,103 @@
1
+ require 'brainfucktt/parser'
2
+
3
+ module Brainfucktt
4
+
5
+ class REPL
6
+
7
+ class << self
8
+
9
+ def instance
10
+ @instance ||= new
11
+ end
12
+
13
+ def run
14
+ puts instance.help
15
+ instance.loop
16
+ end
17
+
18
+ end
19
+
20
+ def initialize
21
+ trap('INT') { self.exit }
22
+ @input, @output = nil
23
+ @parser = Brainfucktt::Parser.new
24
+ end
25
+
26
+ def read
27
+ Kernel.print '> '
28
+ @input = gets
29
+ end
30
+
31
+ def eval
32
+ case @input.strip
33
+ when 'help' then puts help
34
+ when '?' then puts help
35
+ when 'quit' then self.exit
36
+ when 'exit' then self.exit
37
+ when 'hex' then puts hex
38
+ when 'ascii' then puts ascii
39
+ when 'binary' then puts binary
40
+ when 'decimal' then puts decimal
41
+ else; @parser.run(@input)
42
+ end
43
+ end
44
+
45
+ def print
46
+ puts @parser.data.bytes.collect { |byte|
47
+ byte_str = ''
48
+ byte_str << (@parser.byte == byte ? '>' : '|')
49
+ byte_str << byte.to_hex
50
+ byte_str << (@parser.byte == byte ? '<' : '|')
51
+
52
+ byte_str
53
+ }.join(' ')
54
+
55
+ @input = nil
56
+ end
57
+
58
+ def loop
59
+ Kernel.loop do
60
+ # begin
61
+ read
62
+ eval
63
+ print
64
+ # rescue
65
+ # # Do squat
66
+ # end
67
+ end
68
+ end
69
+
70
+ def help
71
+ result = ''
72
+ result << "Type 'help' or '?' for help.\n"
73
+ result << "Type 'hex' to output the data buffer in hexadecimal.\n"
74
+ result << "Type 'ascii' to output the data buffer in ASCII.\n"
75
+ result << "Type 'binary' to output the data buffer in binary.\n"
76
+ result << "Type 'decimal' to output the data buffer in decimal.\n"
77
+ result << "Type 'exit' or 'quit' or press CTRL-C to exit.\n\n"
78
+ end
79
+
80
+ def exit
81
+ puts
82
+ Kernel.exit
83
+ end
84
+
85
+ def hex
86
+ @parser.data.bytes.collect(&:to_hex).join(' ')
87
+ end
88
+
89
+ def ascii
90
+ @parser.data.bytes.collect(&:to_ascii).join
91
+ end
92
+
93
+ def binary
94
+ @parser.data.bytes.collect(&:to_binary).join(' ')
95
+ end
96
+
97
+ def decimal
98
+ @parser.data.bytes.collect(&:to_i).join(' ')
99
+ end
100
+
101
+ end
102
+
103
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brainfucktt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -59,6 +59,22 @@ dependencies:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
61
  version: '1.0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: slop
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '3.3'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '3.3'
62
78
  - !ruby/object:Gem::Dependency
63
79
  name: at
64
80
  requirement: !ruby/object:Gem::Requirement
@@ -189,7 +205,8 @@ dependencies:
189
205
  version: '0.7'
190
206
  description: A Brainfuck interpreter built using Treetop.
191
207
  email: ryan@rynet.us
192
- executables: []
208
+ executables:
209
+ - brainfucktt
193
210
  extensions: []
194
211
  extra_rdoc_files: []
195
212
  files:
@@ -198,10 +215,14 @@ files:
198
215
  - README.md
199
216
  - Rakefile
200
217
  - VERSION
218
+ - bin/brainfucktt
201
219
  - brainfucktt.gemspec
202
220
  - examples/hello_world.rb
203
221
  - examples/hello_world_with_comments.rb
222
+ - examples/rot13.rb
223
+ - examples/square_numbers.rb
204
224
  - examples/stringio.rb
225
+ - examples/system_bell.rb
205
226
  - lib/brainfucktt.rb
206
227
  - lib/brainfucktt/byte.rb
207
228
  - lib/brainfucktt/conversion_helpers.rb
@@ -219,6 +240,7 @@ files:
219
240
  - lib/brainfucktt/language_parser.treetop
220
241
  - lib/brainfucktt/node.rb
221
242
  - lib/brainfucktt/parser.rb
243
+ - lib/brainfucktt/repl.rb
222
244
  homepage: http://github.com/RyanScottLewis/brainfucktt
223
245
  licenses: []
224
246
  post_install_message:
@@ -233,7 +255,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
233
255
  version: '0'
234
256
  segments:
235
257
  - 0
236
- hash: -107453280338519890
258
+ hash: -1731370008399117762
237
259
  required_rubygems_version: !ruby/object:Gem::Requirement
238
260
  none: false
239
261
  requirements: