rbf 0.0.3 → 0.0.4

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