brainfuck 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in brainfuck.gemspec
4
+ gemspec
@@ -0,0 +1,33 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ brainfuck (0.0.1)
5
+ highline
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.1.2)
11
+ highline (1.6.1)
12
+ rspec (2.2.0)
13
+ rspec-core (~> 2.2)
14
+ rspec-expectations (~> 2.2)
15
+ rspec-mocks (~> 2.2)
16
+ rspec-core (2.2.1)
17
+ rspec-expectations (2.2.0)
18
+ diff-lcs (~> 1.1.2)
19
+ rspec-mocks (2.2.0)
20
+ simplecov (0.3.7)
21
+ simplecov-html (>= 0.3.7)
22
+ simplecov-html (0.3.9)
23
+
24
+ PLATFORMS
25
+ java
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ brainfuck!
30
+ bundler
31
+ highline
32
+ rspec
33
+ simplecov
@@ -0,0 +1,15 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'simplecov'
5
+ SimpleCov.start do
6
+ add_group "Lib", 'lib'
7
+ end
8
+
9
+ require 'rspec/core'
10
+ require 'rspec/core/rake_task'
11
+ RSpec::Core::RakeTask.new(:spec) do |spec|
12
+ spec.pattern = FileList['spec/**/*_spec.rb']
13
+ end
14
+
15
+ task :default => :spec
@@ -0,0 +1,49 @@
1
+ # brainfuck
2
+
3
+ Just another Brainfuck interpreter in Ruby!
4
+ (If you don't know what Brainfuck is, you definitely
5
+ [should][http://en.wikipedia.org/wiki/Brainfuck]).
6
+
7
+ This interpreter works with MRI 1.8.7, 1.9.2 and JRuby 1.5.5.
8
+
9
+ ## Known caveats (yes, before anything)
10
+
11
+ Ok, I admit it. Nested loops don't work in an extremely reliable manner, so to
12
+ speak. I suggest you NOT TO USE THIS IN PRODUCTION APPS. Yes, forget about
13
+ using this interpreter for that high-security online payment system you wrote in Brainfuck.
14
+
15
+ Oh and why are nested loops tricky with this interpreter? I was tired and Civilization 5
16
+ was installed in my laptop and... You know, forks and pull requests are always welcome! :)
17
+
18
+ ## Installation and usage
19
+
20
+ You just `gem install brainfuck`!
21
+
22
+ And then: `brainfuck my_file.bf`
23
+
24
+ You can also require the gem and use inline brainfuck in your ruby scripts like this:
25
+
26
+ require 'brainfuck'
27
+
28
+ interpreter = Brainfuck.new
29
+ interpreter.compile "+++>+++<---"
30
+
31
+ interpreter.cells
32
+ # => [0, 3]
33
+
34
+ It's very basic, and needs *a lot* of refactoring, but for now... there you go! ;)
35
+
36
+ ## Note on Patches/Pull Requests
37
+
38
+ * Fork the project.
39
+ * Make your feature addition or bug fix.
40
+ * Add specs for it. This is important so I don't break it in a
41
+ future version unintentionally.
42
+ * Commit, do not mess with rakefile, version, or history.
43
+ If you want to have your own version, that is fine but bump version
44
+ in a commit by itself I can ignore when I pull.
45
+ * Send me a pull request. Bonus points for topic branches.
46
+
47
+ ## Copyright
48
+
49
+ Copyright (c) 2010 Josep M. Bach. See LICENSE for details.
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'brainfuck'
3
+ Brainfuck::Interpreter.new.compile File.read(ARGV.first)
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "brainfuck/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "brainfuck"
7
+ s.version = Brainfuck::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Josep M. Bach"]
10
+ s.email = ["josep.m.bach@gmail.com"]
11
+ s.homepage = "http://github.com/txus/brainfuck"
12
+ s.summary = %q{Another Brainfuck interpreter in Ruby}
13
+ s.description = %q{Another Brainfuck interpreter in Ruby}
14
+
15
+ s.rubyforge_project = "brainfuck"
16
+
17
+ s.add_runtime_dependency "highline"
18
+ s.add_development_dependency "rspec"
19
+ s.add_development_dependency "bundler"
20
+ s.add_development_dependency "simplecov"
21
+
22
+ s.files = `git ls-files`.split("\n")
23
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
+ s.require_paths = ["lib"]
26
+ end
@@ -0,0 +1,21 @@
1
+ +++++ +++++ initialize counter (cell #0) to 10
2
+ [ use loop to set the next four cells to 70/100/30/10
3
+ > +++++ ++ add 7 to cell #1
4
+ > +++++ +++++ add 10 to cell #2
5
+ > +++ add 3 to cell #3
6
+ > + add 1 to cell #4
7
+ <<<< - decrement counter (cell #0)
8
+ ]
9
+ > ++ . print 'H'
10
+ > + . print 'e'
11
+ +++++ ++ . print 'l'
12
+ . print 'l'
13
+ +++ . print 'o'
14
+ > ++ . print ' '
15
+ << +++++ +++++ +++++ . print 'W'
16
+ > . print 'o'
17
+ +++ . print 'r'
18
+ ----- - . print 'l'
19
+ ----- --- . print 'd'
20
+ > + . print '!'
21
+ > . print '\n'
@@ -0,0 +1,102 @@
1
+ require 'highline/system_extensions'
2
+
3
+ module Brainfuck
4
+ class Interpreter
5
+ include HighLine::SystemExtensions
6
+
7
+ INSTRUCTIONS = %w{> < + - [ ] . ,}
8
+
9
+ attr_accessor :cells
10
+ attr_reader :pointer
11
+ attr_reader :code
12
+
13
+ def initialize
14
+ @cells = [0]
15
+ @pointer = 0
16
+ @code = nil
17
+ end
18
+
19
+ def current
20
+ @cells[pointer] ||= 0
21
+ end
22
+ def current=(value)
23
+ @cells[pointer] = (value % 255) rescue 0
24
+ end
25
+
26
+ def forward
27
+ @pointer += 1
28
+ initialize_cell_if_nil
29
+ end
30
+ def backward
31
+ @pointer -= 1
32
+ ensure_pointer_is_above_zero
33
+ initialize_cell_if_nil
34
+ end
35
+ def increase
36
+ @cells[pointer] = (@cells[pointer] + 1) % 255
37
+ end
38
+ def decrease
39
+ @cells[pointer] = (@cells[pointer] - 1) % 255
40
+ end
41
+
42
+ def compile(code)
43
+ @code = clean(code)
44
+ run
45
+ end
46
+
47
+ def run(from = nil, to = nil)
48
+ index = 0
49
+ context = 0
50
+
51
+ c = code.dup
52
+
53
+ if from && to
54
+ context = from
55
+ c = c.slice(from...to)
56
+ end
57
+
58
+ c.each_char do |char|
59
+ index += 1
60
+ case char
61
+ when '>'
62
+ forward
63
+ when '<'
64
+ backward
65
+ when '+'
66
+ increase
67
+ when '-'
68
+ decrease
69
+ when '.'
70
+ stdout.print current.chr
71
+ when ','
72
+ self.current = get_character
73
+ when '['
74
+ @start = index
75
+ when ']'
76
+ @end = index unless @end && @start < @end
77
+ run(@start, @end) unless current == 0
78
+ @start = context || nil
79
+ end
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ def clean(code)
86
+ code.chars.select {|c| INSTRUCTIONS.include? c }.join
87
+ end
88
+
89
+ def stdout
90
+ $stdout
91
+ end
92
+
93
+ def initialize_cell_if_nil
94
+ @cells[pointer] ||= 0
95
+ end
96
+
97
+ def ensure_pointer_is_above_zero
98
+ raise "Tried to access cell #{@pointer}." if @pointer < 0
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,3 @@
1
+ module Brainfuck
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,107 @@
1
+ require 'spec_helper'
2
+
3
+ module Brainfuck
4
+ describe Interpreter, "acceptance specs" do
5
+
6
+ describe "without loops nor user input" do
7
+ let(:code) do
8
+ <<-EOS
9
+ ++++>++++---.<--.
10
+ EOS
11
+ end
12
+ it "sets two cells to 2 and 1" do
13
+ subject.should_receive(:code).and_return code
14
+ subject.compile(code)
15
+ subject.cells.should == [2,1]
16
+ end
17
+ it "prints 2 and 1" do
18
+ output = double('output')
19
+ subject.should_receive(:stdout).twice.and_return(output)
20
+ output.should_receive(:print).with(1.chr).ordered
21
+ output.should_receive(:print).with(2.chr).ordered
22
+
23
+ subject.compile(code)
24
+ end
25
+ end
26
+
27
+ describe "with user input" do
28
+ let(:code) do
29
+ <<-EOS
30
+ ,++++
31
+ EOS
32
+ end
33
+ it "sets the first cell to a + 4" do
34
+ input = double('input')
35
+ subject.should_receive(:get_character).once.and_return 97
36
+
37
+ subject.compile(code)
38
+ subject.current.should == 101
39
+ end
40
+ end
41
+
42
+ describe "with loops" do
43
+ let(:code) do
44
+ <<-EOS
45
+ ++++[-]+-+
46
+ EOS
47
+ end
48
+ it "runs the loop 4 times" do
49
+ subject.compile(code)
50
+ subject.current.should == 1
51
+ end
52
+ end
53
+
54
+ describe "cell hopping examples" do
55
+
56
+ it "transfers the content from one cell to another" do
57
+ subject.cells = [10]
58
+ subject.compile("[>+<-]")
59
+ subject.cells.should == [0,10]
60
+ end
61
+
62
+ it "transfers the content from one cell to the third" do
63
+ subject.cells = [10]
64
+ subject.compile("[>+<-]>[>+<-]")
65
+ subject.cells.should == [0,0,10]
66
+ end
67
+
68
+ it "transfers the content from one cell to the third and back to the second" do
69
+ subject.cells = [10]
70
+ subject.compile("[>+<-]>[>+<-]>[<+>-]")
71
+ subject.cells.should == [0,10,0]
72
+ end
73
+
74
+ end
75
+
76
+ describe "hello world" do
77
+
78
+ it "displays hello world" do
79
+ subject.compile <<-EOS
80
+ +++++ +++++
81
+ [
82
+ > +++++ ++
83
+ > +++++ +++++
84
+ > +++
85
+ > +
86
+ <<<< -
87
+ ]
88
+ > ++ .
89
+ > + .
90
+ +++++ ++ .
91
+ .
92
+ +++ .
93
+ > ++ .
94
+ << +++++ +++++ +++++ .
95
+ > .
96
+ +++ .
97
+ ----- - .
98
+ ----- --- .
99
+ > + .
100
+ > .
101
+ EOS
102
+
103
+ end
104
+ end
105
+
106
+ end
107
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ module Brainfuck
4
+ describe Interpreter do
5
+ subject { Interpreter.new }
6
+
7
+ it "initializes with an array of cells with a single 0 element" do
8
+ subject.cells.should == [0]
9
+ end
10
+
11
+ describe "#clean" do
12
+ it "cleans the code from comments and whitespace" do
13
+ subject.send(:clean, " < > h - + ..,hb [lk]f").should == '<>-+..,[]'
14
+ end
15
+ end
16
+
17
+ describe "#compile" do
18
+ it "cleans the code first and runs it second" do
19
+ code = double('code')
20
+ subject.should_receive(:clean).once.with(code).ordered.and_return("")
21
+ subject.should_receive(:run).once
22
+
23
+ subject.compile(code)
24
+ end
25
+ end
26
+
27
+ describe "#run" do
28
+ it "converts > into forward" do
29
+ subject.stub(:code).and_return ">"
30
+ subject.should_receive(:forward).once
31
+ subject.run
32
+ end
33
+ it "converts < into backward" do
34
+ subject.stub(:code).and_return "<"
35
+ subject.should_receive(:backward).once
36
+ subject.run
37
+ end
38
+ it "converts + into increase" do
39
+ subject.stub(:code).and_return "+"
40
+ subject.should_receive(:increase).once
41
+ subject.run
42
+ end
43
+ it "converts - into decrease" do
44
+ subject.stub(:code).and_return "-"
45
+ subject.should_receive(:decrease).once
46
+ subject.run
47
+ end
48
+ it "converts , into get_character" do
49
+ subject.stub(:code).and_return ","
50
+ subject.should_receive(:get_character).once
51
+ subject.run
52
+ end
53
+ it "converts . into stdout.print" do
54
+ subject.stub(:code).and_return "."
55
+ output = double('output')
56
+ subject.should_receive(:stdout).once.and_return(output)
57
+ subject.should_receive(:current).once.and_return(117)
58
+ output.should_receive(:print).once
59
+
60
+ subject.run
61
+ end
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,18 @@
1
+ require 'bundler'
2
+ require 'simplecov'
3
+ SimpleCov.start do
4
+ add_group "Lib", "lib"
5
+ end
6
+
7
+ begin
8
+ Bundler.setup(:default, :development)
9
+ rescue Bundler::BundlerError => e
10
+ $stderr.puts e.message
11
+ $stderr.puts "Run `bundle install` to install missing gems"
12
+ exit e.status_code
13
+ end
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
16
+
17
+ require 'brainfuck'
18
+ require 'rspec'
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: brainfuck
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Josep M. Bach
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-12-02 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: highline
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: rspec
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ type: :development
45
+ version_requirements: *id002
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ prerelease: false
49
+ requirement: &id003 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ segments:
55
+ - 0
56
+ version: "0"
57
+ type: :development
58
+ version_requirements: *id003
59
+ - !ruby/object:Gem::Dependency
60
+ name: simplecov
61
+ prerelease: false
62
+ requirement: &id004 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ type: :development
71
+ version_requirements: *id004
72
+ description: Another Brainfuck interpreter in Ruby
73
+ email:
74
+ - josep.m.bach@gmail.com
75
+ executables:
76
+ - brainfuck
77
+ extensions: []
78
+
79
+ extra_rdoc_files: []
80
+
81
+ files:
82
+ - .gitignore
83
+ - Gemfile
84
+ - Gemfile.lock
85
+ - Rakefile
86
+ - Readme.md
87
+ - bin/brainfuck
88
+ - brainfuck.gemspec
89
+ - examples/hello_world.bf
90
+ - lib/brainfuck.rb
91
+ - lib/brainfuck/version.rb
92
+ - spec/acceptance_spec.rb
93
+ - spec/interpreter_spec.rb
94
+ - spec/spec_helper.rb
95
+ has_rdoc: true
96
+ homepage: http://github.com/txus/brainfuck
97
+ licenses: []
98
+
99
+ post_install_message:
100
+ rdoc_options: []
101
+
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ segments:
110
+ - 0
111
+ version: "0"
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ segments:
118
+ - 0
119
+ version: "0"
120
+ requirements: []
121
+
122
+ rubyforge_project: brainfuck
123
+ rubygems_version: 1.3.7
124
+ signing_key:
125
+ specification_version: 3
126
+ summary: Another Brainfuck interpreter in Ruby
127
+ test_files:
128
+ - spec/acceptance_spec.rb
129
+ - spec/interpreter_spec.rb
130
+ - spec/spec_helper.rb