rbf 0.0.3 → 0.0.4

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/bin/rbf CHANGED
@@ -1,5 +1,23 @@
1
1
  #! /usr/bin/env ruby
2
2
  require 'rubygems'
3
+ require 'optparse'
3
4
  require 'rbf'
4
5
 
5
- RBF.execute(ARGV.first)
6
+ options = {}
7
+
8
+ OptionParser.new do |opts|
9
+ opts.on '-h', '--help', 'Display this screen' do
10
+ puts opts
11
+ exit
12
+ end
13
+
14
+ opts.on '-s', '--syntax [NAME]', ['default', 'nintendo'], 'Choose a brainfuck syntax' do |value|
15
+ options[:syntax] = value
16
+ end
17
+ end.parse!
18
+
19
+ if ARGV.first
20
+ RBF.execute(ARGV.first, options[:syntax])
21
+ else
22
+ RBF.repl(options)
23
+ end
@@ -33,63 +33,98 @@ end
33
33
  module RBF
34
34
 
35
35
  class Interpreter
36
- class Storage < Array
37
- def initialize (*args)
38
- super
36
+ class Storage < Hash
37
+ attr_reader :position
39
38
 
40
- @pointer = 0
39
+ def initialize (data)
40
+ if data.is_a?(Array)
41
+ parent = {}
41
42
 
42
- check!
43
+ data.each_with_index {|value, index|
44
+ parent[index] = value
45
+ }
46
+
47
+ super(parent)
48
+ else
49
+ super
50
+ end
51
+
52
+ @position = 0
43
53
  end
44
54
 
45
55
  def check!
46
- if self[@pointer].nil?
47
- self[@pointer] = 0
56
+ unless self[@position].is_a?(Integer)
57
+ self[@position] = 0
48
58
  end
49
59
  end
50
60
 
51
61
  def forward!
52
- @pointer += 1
53
-
54
- check!
62
+ @position += 1
55
63
  end
56
64
 
57
65
  def backward!
58
- @pointer -= 1
59
-
60
- check!
66
+ @position -= 1
61
67
  end
62
68
 
63
69
  def increase!
64
- self[@pointer] += 1
70
+ check!
71
+
72
+ self[@position] += 1
65
73
  end
66
74
 
67
75
  def decrease!
68
- self[@pointer] -= 1
76
+ check!
77
+
78
+ self[@position] -= 1
69
79
  end
70
80
 
71
- def set (value)
72
- self[@pointer] = value.to_i
81
+ def set (value, position=nil)
82
+ self[position || @position] = value.ord
73
83
  end
74
84
 
75
- def get
76
- self[@pointer].to_i
85
+ def get (position=nil)
86
+ self[position || @position].to_i rescue 0
87
+ end
88
+
89
+ def inspect
90
+ "#<Storage(#{position}): #{super}>"
77
91
  end
78
92
  end
79
93
 
80
- def initialize
81
- @storage = Storage.new
94
+ attr_reader :options, :storage
95
+
96
+ def initialize (options={})
97
+ @options = options
98
+
99
+ @storage = Storage.new(options[:env] || [])
82
100
  @input = STDIN
101
+ @output = STDOUT
102
+
103
+ @parser = RBF::Parser.syntax(RBF.syntax(options[:syntax])).new
104
+ @transform = RBF::Transform.new
105
+ @optimizer = RBF::Optimizer.new(options)
106
+ end
107
+
108
+ def parse (text)
109
+ return text if text.is_a?(Array)
110
+
111
+ parsed = @parser.parse_with_debug(text)
112
+
113
+ raise SyntaxError, 'There is a syntax error' unless parsed
114
+
115
+ @optimizer.optimize(@transform.apply(parsed))
83
116
  end
84
117
 
85
- def evaluate (tree, options={})
118
+ def evaluate (tree, options=nil)
119
+ options ||= {}
120
+
86
121
  if options[:catch]
87
122
  @output = StringIO.new
88
123
  else
89
124
  @output = STDOUT
90
125
  end
91
126
 
92
- cycle(tree)
127
+ cycle(parse(tree))
93
128
 
94
129
  if options[:catch]
95
130
  @output.rewind
@@ -97,6 +132,10 @@ class Interpreter
97
132
  end
98
133
  end
99
134
 
135
+ def execute (path, options=nil)
136
+ evaluate(File.read(path), options)
137
+ end
138
+
100
139
  def cycle (tree)
101
140
  tree.each {|token|
102
141
  if token.is_a?(Array)
@@ -130,7 +169,7 @@ class Interpreter
130
169
  end
131
170
 
132
171
  define_method ?. do
133
- @output.print @storage.get.chr
172
+ @output.print @storage.get.chr rescue nil
134
173
  @output.flush
135
174
  end
136
175
 
@@ -0,0 +1,74 @@
1
+ #--
2
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
+ # Version 2, December 2004
4
+ #
5
+ # Copyleft meh. [http://meh.paranoid.pk | meh@paranoici.org]
6
+ #
7
+ # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
8
+ # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
9
+ #
10
+ # 0. You just DO WHAT THE FUCK YOU WANT TO.
11
+ #++
12
+
13
+ module RBF
14
+
15
+ class Optimizer
16
+ class Algorithm
17
+ attr_reader :optimizer
18
+
19
+ def initialize (optimizer)
20
+ @optimizer = optimizer
21
+ end
22
+
23
+ def optimize (tree)
24
+ nil
25
+ end
26
+ end
27
+
28
+ attr_reader :options
29
+
30
+ def initialize (options={})
31
+ @options = options
32
+ end
33
+
34
+ def optimize (tree)
35
+ result = tree.clone
36
+
37
+ algorithms.each {|alg|
38
+ alg.new(self).optimize(result)
39
+ }
40
+
41
+ result
42
+ end
43
+
44
+ def algorithms
45
+ Optimizer.constants.map {|const|
46
+ Optimizer.const_get(const) unless options[const.to_s.downcase.to_sym] == false
47
+ }.compact
48
+ end
49
+
50
+ class UselessOperations < Algorithm
51
+ def optimize (tree)
52
+ i = 0
53
+
54
+ until i >= tree.length
55
+ if tree[i].is_a?(Array) && tree[i + 1].is_a?(Array)
56
+ optimize(tree[i])
57
+ optimize(tree[i + 1])
58
+
59
+ i += 2
60
+ elsif tree[i].is_a?(Array)
61
+ optimize(tree[i])
62
+
63
+ i += 1
64
+ elsif [[?+, ?-], [?-, ?+], [?>, ?<], [?<, ?>]].member?(tree[i ... i + 2])
65
+ tree.slice!(i ... i + 2)
66
+ else
67
+ i += 1
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ end
data/lib/rbf/parser.rb CHANGED
@@ -15,7 +15,7 @@ require 'parslet'
15
15
  module RBF
16
16
 
17
17
  class Parser < Parslet::Parser
18
- def self.apply (keys)
18
+ def self.syntax (keys)
19
19
  klass = self.clone
20
20
 
21
21
  klass.class_eval {
@@ -69,4 +69,17 @@ class Parser < Parslet::Parser
69
69
  root :code
70
70
  end
71
71
 
72
+ class Transform < Parslet::Transform
73
+ rule(?> => simple(:x)) { ?> }
74
+ rule(?< => simple(:x)) { ?< }
75
+
76
+ rule(?+ => simple(:x)) { ?+ }
77
+ rule(?- => simple(:x)) { ?- }
78
+
79
+ rule(?. => simple(:x)) { ?. }
80
+ rule(?, => simple(:x)) { ?, }
81
+
82
+ rule(:loop => subtree(:x)) { x }
83
+ end
84
+
72
85
  end
data/lib/rbf.rb CHANGED
@@ -12,28 +12,89 @@
12
12
 
13
13
  require 'rbf/syntax'
14
14
  require 'rbf/parser'
15
- require 'rbf/transform'
15
+ require 'rbf/optimizer'
16
16
  require 'rbf/interpreter'
17
17
 
18
18
  require 'parslet/convenience'
19
19
 
20
20
  module RBF
21
- def self.parse (text, syntax=nil)
22
- Transform.new.apply(Parser.apply(syntax || Syntax::Default).new.parse_with_debug(text)) or
21
+ def self.syntax (name)
22
+ name.is_a?(Hash) ? name :
23
+ (RBF::Syntax.const_get(name.to_s.capitalize) rescue nil) || Syntax::Default
24
+ end
25
+
26
+ def self.parse (text, syn=nil)
27
+ Transform.new.apply(Parser.syntax(syntax(syn)).new.parse_with_debug(text)) or
23
28
  raise SyntaxError, 'There is a syntax error'
24
29
  end
25
30
 
26
- def self.evaluate (text, options={})
27
- tree = text.is_a?(Array) ? text : parse(text.to_s, options[:syntax])
31
+ def self.optimize (text, options=nil)
32
+ options ||= {}
33
+
34
+ Optimizer.new(options).optimize(text.is_a?(Array) ? text : parse(text.to_s, options[:syntax]))
35
+ end
36
+
37
+ def self.evaluate (text, options=nil)
38
+ options ||= {}
28
39
 
29
- Interpreter.new.evaluate(tree, options)
40
+ Interpreter.new(options).evaluate(text)
30
41
  end
31
42
 
32
43
  def self.execute (file, options={})
33
44
  evaluate(File.read(file), options)
34
45
  end
35
46
 
36
- def self.[] (text, syntax=nil)
37
- evaluate(text, :catch => true, :syntax => syntax)
47
+ def self.[] (text, syn=nil)
48
+ evaluate(text, :catch => true, :syntax => syn)
49
+ end
50
+
51
+ def self.repl (options=nil)
52
+ require 'colorb'
53
+
54
+ interpreter = Interpreter.new(options || {})
55
+
56
+ loop do
57
+ STDOUT.print '>> '.bold
58
+ STDOUT.flush
59
+
60
+ begin
61
+ line = STDIN.gets.chomp rescue nil or raise SystemExit
62
+ rescue Interrupt, SystemExit
63
+ puts "\nExiting REPL."
64
+
65
+ return false
66
+ end
67
+
68
+ begin
69
+ if line.start_with?('!')
70
+ case line[1 .. -1]
71
+ when 'exit', 'quit'
72
+ return true
73
+
74
+ when 'storage'
75
+ STDOUT.puts interpreter.storage.inspect
76
+
77
+ when 'position'
78
+ STDOUT.puts interpreter.storage.position.to_s.bold
79
+
80
+ when /^get(?:\s*(\d+))?$/
81
+ STDOUT.puts "#{($1 || interpreter.storage.position).to_s.bold}: #{interpreter.storage.get($1.to_i)}"
82
+
83
+ when /^set(?:\s+(\d+)\s+(\d+))/
84
+ interpreter.storage.set($2.to_i, $1.to_i)
85
+
86
+ else
87
+ STDOUT.puts 'Command not found'.red
88
+ end
89
+ else
90
+ output = interpreter.evaluate(line, interpreter.options.merge(:catch => true))
91
+
92
+ print output
93
+ print "\n" unless output.empty? || output.end_with?("\n")
94
+ end
95
+ rescue
96
+ STDOUT.puts $!.inspect.red, $@.join("\n")
97
+ end
98
+ end
38
99
  end
39
100
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: rbf
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.3
5
+ version: 0.0.4
6
6
  platform: ruby
7
7
  authors:
8
8
  - meh.
@@ -23,6 +23,17 @@ dependencies:
23
23
  version: "0"
24
24
  type: :runtime
25
25
  version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: colorb
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ type: :runtime
36
+ version_requirements: *id002
26
37
  description:
27
38
  email: meh@paranoici.org
28
39
  executables:
@@ -32,10 +43,10 @@ extensions: []
32
43
  extra_rdoc_files: []
33
44
 
34
45
  files:
35
- - lib/rbf/transform.rb
36
46
  - lib/rbf/interpreter.rb
37
47
  - lib/rbf/syntax.rb
38
48
  - lib/rbf/parser.rb
49
+ - lib/rbf/optimizer.rb
39
50
  - lib/rbf.rb
40
51
  - bin/rbf
41
52
  homepage: http://github.com/meh/rbf
data/lib/rbf/transform.rb DELETED
@@ -1,30 +0,0 @@
1
- #--
2
- # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
3
- # Version 2, December 2004
4
- #
5
- # Copyleft meh. [http://meh.paranoid.pk | meh@paranoici.org]
6
- #
7
- # DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
8
- # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
9
- #
10
- # 0. You just DO WHAT THE FUCK YOU WANT TO.
11
- #++
12
-
13
- require 'parslet'
14
-
15
- module RBF
16
-
17
- class Transform < Parslet::Transform
18
- rule(?> => simple(:x)) { ?> }
19
- rule(?< => simple(:x)) { ?< }
20
-
21
- rule(?+ => simple(:x)) { ?+ }
22
- rule(?- => simple(:x)) { ?- }
23
-
24
- rule(?. => simple(:x)) { ?. }
25
- rule(?, => simple(:x)) { ?, }
26
-
27
- rule(:loop => subtree(:x)) { x }
28
- end
29
-
30
- end