brainfuck 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile.lock +8 -23
- data/Rakefile +12 -10
- data/Readme.md +17 -11
- data/bin/brainfuck +1 -1
- data/brainfuck.gemspec +5 -6
- data/lib/brainfuck.rb +5 -18
- data/lib/brainfuck/ast.rb +126 -18
- data/lib/brainfuck/code_loader.rb +31 -0
- data/lib/brainfuck/compiler.rb +81 -0
- data/lib/brainfuck/lexer.rb +32 -0
- data/lib/brainfuck/main.rb +99 -0
- data/lib/brainfuck/parser.rb +9 -24
- data/lib/brainfuck/stages.rb +170 -0
- data/lib/brainfuck/version.rb +1 -1
- data/test/acceptance/acceptance_test.rb +75 -0
- data/test/brainfuck/ast_test.rb +7 -0
- data/test/brainfuck/lexer_test.rb +21 -0
- data/test/brainfuck/parser_test.rb +16 -0
- data/test/test_helper.rb +10 -0
- metadata +32 -53
- data/lib/brainfuck/interpreter.rb +0 -20
- data/lib/brainfuck/stack.rb +0 -51
- data/spec/acceptance/acceptance_spec.rb +0 -105
- data/spec/brainfuck/ast_spec.rb +0 -36
- data/spec/brainfuck/interpreter_spec.rb +0 -25
- data/spec/brainfuck/parser_spec.rb +0 -27
- data/spec/brainfuck/stack_spec.rb +0 -81
- data/spec/brainfuck_spec.rb +0 -23
- data/spec/spec_helper.rb +0 -18
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Brainfuck
|
4
|
+
class ParserTest < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
%w{fwd bwd inc dec puts gets iteration exp}.each do |rule|
|
7
|
+
define_method "test_implements_a_#{rule}_rule" do
|
8
|
+
rules = Parser.rules.map(&:first).map do |pattern|
|
9
|
+
pattern.instance_variable_get(:@pattern)
|
10
|
+
end.map(&:keys).flatten
|
11
|
+
assert_includes rules, rule.to_sym
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brainfuck
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
5
6
|
segments:
|
6
7
|
- 0
|
7
|
-
- 1
|
8
8
|
- 2
|
9
|
-
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Josep M. Bach
|
@@ -14,75 +15,52 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2011-
|
18
|
+
date: 2011-05-16 00:00:00 +02:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
|
-
name:
|
22
|
+
name: parslet
|
22
23
|
prerelease: false
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
25
|
none: false
|
25
26
|
requirements:
|
26
27
|
- - ">="
|
27
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
28
30
|
segments:
|
29
31
|
- 0
|
30
32
|
version: "0"
|
31
33
|
type: :runtime
|
32
34
|
version_requirements: *id001
|
33
35
|
- !ruby/object:Gem::Dependency
|
34
|
-
name:
|
36
|
+
name: minitest
|
35
37
|
prerelease: false
|
36
38
|
requirement: &id002 !ruby/object:Gem::Requirement
|
37
39
|
none: false
|
38
40
|
requirements:
|
39
41
|
- - ">="
|
40
42
|
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
41
44
|
segments:
|
42
45
|
- 0
|
43
46
|
version: "0"
|
44
|
-
type: :
|
47
|
+
type: :development
|
45
48
|
version_requirements: *id002
|
46
49
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
50
|
+
name: mocha
|
48
51
|
prerelease: false
|
49
52
|
requirement: &id003 !ruby/object:Gem::Requirement
|
50
53
|
none: false
|
51
54
|
requirements:
|
52
55
|
- - ">="
|
53
56
|
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
54
58
|
segments:
|
55
59
|
- 0
|
56
60
|
version: "0"
|
57
61
|
type: :development
|
58
62
|
version_requirements: *id003
|
59
|
-
|
60
|
-
name: bundler
|
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
|
-
- !ruby/object:Gem::Dependency
|
73
|
-
name: simplecov
|
74
|
-
prerelease: false
|
75
|
-
requirement: &id005 !ruby/object:Gem::Requirement
|
76
|
-
none: false
|
77
|
-
requirements:
|
78
|
-
- - ">="
|
79
|
-
- !ruby/object:Gem::Version
|
80
|
-
segments:
|
81
|
-
- 0
|
82
|
-
version: "0"
|
83
|
-
type: :development
|
84
|
-
version_requirements: *id005
|
85
|
-
description: Another Brainfuck interpreter in Ruby
|
63
|
+
description: An implementation of Brainfuck on the Rubinius VM.
|
86
64
|
email:
|
87
65
|
- josep.m.bach@gmail.com
|
88
66
|
executables:
|
@@ -104,17 +82,18 @@ files:
|
|
104
82
|
- examples/hello_world.bf
|
105
83
|
- lib/brainfuck.rb
|
106
84
|
- lib/brainfuck/ast.rb
|
107
|
-
- lib/brainfuck/
|
85
|
+
- lib/brainfuck/code_loader.rb
|
86
|
+
- lib/brainfuck/compiler.rb
|
87
|
+
- lib/brainfuck/lexer.rb
|
88
|
+
- lib/brainfuck/main.rb
|
108
89
|
- lib/brainfuck/parser.rb
|
109
|
-
- lib/brainfuck/
|
90
|
+
- lib/brainfuck/stages.rb
|
110
91
|
- lib/brainfuck/version.rb
|
111
|
-
-
|
112
|
-
-
|
113
|
-
-
|
114
|
-
-
|
115
|
-
-
|
116
|
-
- spec/brainfuck_spec.rb
|
117
|
-
- spec/spec_helper.rb
|
92
|
+
- test/acceptance/acceptance_test.rb
|
93
|
+
- test/brainfuck/ast_test.rb
|
94
|
+
- test/brainfuck/lexer_test.rb
|
95
|
+
- test/brainfuck/parser_test.rb
|
96
|
+
- test/test_helper.rb
|
118
97
|
has_rdoc: true
|
119
98
|
homepage: http://github.com/txus/brainfuck
|
120
99
|
licenses: []
|
@@ -129,6 +108,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
129
108
|
requirements:
|
130
109
|
- - ">="
|
131
110
|
- !ruby/object:Gem::Version
|
111
|
+
hash: 3
|
132
112
|
segments:
|
133
113
|
- 0
|
134
114
|
version: "0"
|
@@ -137,21 +117,20 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
137
117
|
requirements:
|
138
118
|
- - ">="
|
139
119
|
- !ruby/object:Gem::Version
|
120
|
+
hash: 3
|
140
121
|
segments:
|
141
122
|
- 0
|
142
123
|
version: "0"
|
143
124
|
requirements: []
|
144
125
|
|
145
126
|
rubyforge_project: brainfuck
|
146
|
-
rubygems_version: 1.
|
127
|
+
rubygems_version: 1.5.2
|
147
128
|
signing_key:
|
148
129
|
specification_version: 3
|
149
|
-
summary:
|
130
|
+
summary: An implementation of Brainfuck on the Rubinius VM.
|
150
131
|
test_files:
|
151
|
-
-
|
152
|
-
-
|
153
|
-
-
|
154
|
-
-
|
155
|
-
-
|
156
|
-
- spec/brainfuck_spec.rb
|
157
|
-
- spec/spec_helper.rb
|
132
|
+
- test/acceptance/acceptance_test.rb
|
133
|
+
- test/brainfuck/ast_test.rb
|
134
|
+
- test/brainfuck/lexer_test.rb
|
135
|
+
- test/brainfuck/parser_test.rb
|
136
|
+
- test/test_helper.rb
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module Brainfuck
|
2
|
-
class Interpreter < Parslet::Transform
|
3
|
-
def self.stack
|
4
|
-
@@stack ||= Stack.new
|
5
|
-
end
|
6
|
-
|
7
|
-
rule(:fwd => simple(:fwd)) { AST::FwdNode.new(Interpreter.stack) }
|
8
|
-
rule(:bwd => simple(:bwd)) { AST::BwdNode.new(Interpreter.stack) }
|
9
|
-
|
10
|
-
rule(:inc => simple(:inc)) { AST::IncNode.new(Interpreter.stack) }
|
11
|
-
rule(:dec => simple(:dec)) { AST::DecNode.new(Interpreter.stack) }
|
12
|
-
|
13
|
-
rule(:puts => simple(:puts)) { AST::PutsNode.new(Interpreter.stack) }
|
14
|
-
rule(:gets => simple(:gets)) { AST::GetsNode.new(Interpreter.stack) }
|
15
|
-
|
16
|
-
rule(:iteration => subtree(:iteration)) { AST::IterationNode.new(Interpreter.stack, iteration) }
|
17
|
-
|
18
|
-
rule(:exp => subtree(:exp)) { exp }
|
19
|
-
end
|
20
|
-
end
|
data/lib/brainfuck/stack.rb
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
module Brainfuck
|
2
|
-
class Stack
|
3
|
-
include HighLine::SystemExtensions
|
4
|
-
|
5
|
-
attr_reader :current
|
6
|
-
def initialize
|
7
|
-
@pointer = 0
|
8
|
-
@stack = [0]
|
9
|
-
end
|
10
|
-
def current
|
11
|
-
@stack[@pointer]
|
12
|
-
end
|
13
|
-
def fwd
|
14
|
-
@pointer += 1
|
15
|
-
initialize_cell_if_nil
|
16
|
-
end
|
17
|
-
def bwd
|
18
|
-
@pointer -= 1
|
19
|
-
ensure_pointer_is_above_zero
|
20
|
-
initialize_cell_if_nil
|
21
|
-
end
|
22
|
-
def inc
|
23
|
-
@stack[@pointer] = (current + 1) % 255
|
24
|
-
end
|
25
|
-
def dec
|
26
|
-
@stack[@pointer] = (current - 1) % 255
|
27
|
-
end
|
28
|
-
def puts
|
29
|
-
$stdout.print current.chr
|
30
|
-
end
|
31
|
-
def gets
|
32
|
-
@stack[@pointer] = (get_character % 255) rescue 0
|
33
|
-
end
|
34
|
-
|
35
|
-
def to_a
|
36
|
-
@stack
|
37
|
-
end
|
38
|
-
|
39
|
-
def clear
|
40
|
-
initialize
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
def initialize_cell_if_nil
|
45
|
-
@stack[@pointer] ||= 0
|
46
|
-
end
|
47
|
-
def ensure_pointer_is_above_zero
|
48
|
-
raise "Tried to access cell #{@pointer}." if @pointer < 0
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,105 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Brainfuck
|
4
|
-
describe "Acceptance specs" do
|
5
|
-
|
6
|
-
subject { Brainfuck }
|
7
|
-
|
8
|
-
describe "without loops nor user input" do
|
9
|
-
let(:code) do
|
10
|
-
<<-EOS
|
11
|
-
++++>++++---.<--.
|
12
|
-
EOS
|
13
|
-
end
|
14
|
-
it "sets two cells to 2 and 1" do
|
15
|
-
subject.run(code).should == [2,1]
|
16
|
-
end
|
17
|
-
it "prints 2 and 1" do
|
18
|
-
$stdout.should_receive(:print).twice
|
19
|
-
subject.run code
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
describe "with user input" do
|
24
|
-
let(:code) do
|
25
|
-
<<-EOS
|
26
|
-
,++++
|
27
|
-
EOS
|
28
|
-
end
|
29
|
-
it "sets the first cell to a + 4" do
|
30
|
-
stack = Stack.new
|
31
|
-
Interpreter.stub(:stack).and_return stack
|
32
|
-
|
33
|
-
stack.should_receive(:get_character).once.and_return 97
|
34
|
-
|
35
|
-
subject.run(code).should == [101]
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
describe "with loops" do
|
40
|
-
let(:code) do
|
41
|
-
<<-EOS
|
42
|
-
++++[-]+-+
|
43
|
-
EOS
|
44
|
-
end
|
45
|
-
it "runs the loop 4 times" do
|
46
|
-
subject.run(code).should == [1]
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
describe "cell hopping examples" do
|
51
|
-
|
52
|
-
it "transfers the content from one cell to another" do
|
53
|
-
subject.run("++++++++++ [>+<-]").should == [0,10]
|
54
|
-
end
|
55
|
-
|
56
|
-
it "transfers the content from one cell to the third" do
|
57
|
-
subject.run("++++++++++ [>+<-]>[>+<-]").should == [0,0,10]
|
58
|
-
end
|
59
|
-
|
60
|
-
it "transfers the content from one cell to the third and back to the second" do
|
61
|
-
subject.run("++++++++++ [>+<-]>[>+<-]>[<+>-]").should == [0,10,0]
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
|
66
|
-
describe "nested loop examples" do
|
67
|
-
|
68
|
-
it "work flawlessly" do
|
69
|
-
subject.run("[++++++++++[-]+-+-]").should == [0]
|
70
|
-
end
|
71
|
-
|
72
|
-
end
|
73
|
-
|
74
|
-
describe "hello world" do
|
75
|
-
|
76
|
-
it "displays hello world" do
|
77
|
-
subject.run <<-EOS
|
78
|
-
+++++ +++++
|
79
|
-
[
|
80
|
-
> +++++ ++
|
81
|
-
> +++++ +++++
|
82
|
-
> +++
|
83
|
-
> +
|
84
|
-
<<<< -
|
85
|
-
]
|
86
|
-
> ++ .
|
87
|
-
> + .
|
88
|
-
+++++ ++ .
|
89
|
-
.
|
90
|
-
+++ .
|
91
|
-
> ++ .
|
92
|
-
<< +++++ +++++ +++++ .
|
93
|
-
> .
|
94
|
-
+++ .
|
95
|
-
----- - .
|
96
|
-
----- --- .
|
97
|
-
> + .
|
98
|
-
> .
|
99
|
-
EOS
|
100
|
-
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
end
|
105
|
-
end
|
data/spec/brainfuck/ast_spec.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Brainfuck
|
4
|
-
describe AST do
|
5
|
-
let(:stack) { double('stack') }
|
6
|
-
|
7
|
-
%w{fwd bwd inc dec puts gets}.each do |node|
|
8
|
-
describe "AST::#{node.capitalize}Node" do
|
9
|
-
subject { eval("AST::#{node.capitalize}Node").new stack }
|
10
|
-
describe "#eval" do
|
11
|
-
it "calls stack##{node}" do
|
12
|
-
subject.stack.should_receive(node)
|
13
|
-
subject.eval
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
describe AST::IterationNode do
|
20
|
-
let(:nodes) do
|
21
|
-
[ double('node'), double('node2') ]
|
22
|
-
end
|
23
|
-
subject { AST::IterationNode.new stack, nodes }
|
24
|
-
describe "#eval" do
|
25
|
-
it 'evaluates the expression until the stack cell is 0' do
|
26
|
-
subject.stack.stub(:current).and_return 3, 2, 1, 0
|
27
|
-
nodes.each do |node|
|
28
|
-
node.should_receive(:eval).exactly(3).times
|
29
|
-
end
|
30
|
-
subject.eval
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
36
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Brainfuck
|
4
|
-
describe Interpreter do
|
5
|
-
|
6
|
-
describe ".stack" do
|
7
|
-
it 'returns a new or cached Stack' do
|
8
|
-
stack = Interpreter.stack
|
9
|
-
stack.should be_kind_of(Stack)
|
10
|
-
Interpreter.stack.should === stack
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
describe "rules" do
|
15
|
-
%w{fwd bwd inc dec puts gets iteration exp}.each do |rule|
|
16
|
-
it "implements a rule for :#{rule} node" do
|
17
|
-
subject.rules.map(&:first).map do |pattern|
|
18
|
-
pattern.instance_variable_get(:@pattern)
|
19
|
-
end.map(&:keys).flatten.should include(:"#{rule}")
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
25
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Brainfuck
|
4
|
-
describe Parser do
|
5
|
-
|
6
|
-
describe "INSTRUCTIONS constant" do
|
7
|
-
it 'returns valid symbols' do
|
8
|
-
Parser::INSTRUCTIONS.should == %w{> < + - [ ] . ,}
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
describe ".clean" do
|
13
|
-
it 'cleans all non-valid symbols from a string' do
|
14
|
-
Parser.clean(">3< 223+fn - ()()[r23-] .bdn*& ,").should == '><+-[-].,'
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
describe "rules" do
|
19
|
-
%w{lparen rparen space space? fwd bwd inc dec puts gets iteration expression}.each do |rule|
|
20
|
-
it "implements a rule for :#{rule} node" do
|
21
|
-
subject.should respond_to(:"#{rule}")
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
end
|