rbf 0.0.4 → 0.0.5

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.
@@ -0,0 +1,31 @@
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 'stringio'
14
+
15
+ class IO
16
+ begin
17
+ require 'Win32API'
18
+
19
+ def read_char
20
+ Win32API.new('crtdll', '_getch', [], 'L').Call
21
+ end
22
+ rescue LoadError
23
+ def read_char
24
+ system 'stty raw -echo'
25
+
26
+ STDIN.getc
27
+ ensure
28
+ system 'stty -raw echo'
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,73 @@
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; class Interpreter
14
+
15
+ class Storage < Hash
16
+ attr_accessor :position
17
+
18
+ def initialize (data)
19
+ if data.is_a?(Array)
20
+ parent = {}
21
+
22
+ data.each_with_index {|value, index|
23
+ parent[index] = value
24
+ }
25
+
26
+ super(parent)
27
+ else
28
+ super
29
+ end
30
+
31
+ @position = 0
32
+ end
33
+
34
+ def check!
35
+ unless self[@position].is_a?(Integer)
36
+ self[@position] = 0
37
+ end
38
+ end
39
+
40
+ def forward!
41
+ @position += 1
42
+ end
43
+
44
+ def backward!
45
+ @position -= 1
46
+ end
47
+
48
+ def increase!
49
+ check!
50
+
51
+ self[@position] += 1
52
+ end
53
+
54
+ def decrease!
55
+ check!
56
+
57
+ self[@position] -= 1
58
+ end
59
+
60
+ def set (value, position=nil)
61
+ self[position ? position.to_i : @position.to_i] = value.ord
62
+ end
63
+
64
+ def get (position=nil)
65
+ self[position ? position.to_i : @position.to_i].to_i rescue 0
66
+ end
67
+
68
+ def inspect
69
+ "#<Storage(#{position}): #{super}>"
70
+ end
71
+ end
72
+
73
+ end; end
@@ -10,87 +10,12 @@
10
10
  # 0. You just DO WHAT THE FUCK YOU WANT TO.
11
11
  #++
12
12
 
13
- require 'stringio'
14
-
15
- class IO
16
- begin
17
- require 'Win32API'
18
-
19
- def read_char
20
- Win32API.new('crtdll', '_getch', [], 'L').Call
21
- end
22
- rescue LoadError
23
- def read_char
24
- system 'stty raw -echo'
25
-
26
- STDIN.getc
27
- ensure
28
- system 'stty -raw echo'
29
- end
30
- end
31
- end
13
+ require 'rbf/interpreter/extensions'
14
+ require 'rbf/interpreter/storage'
32
15
 
33
16
  module RBF
34
17
 
35
18
  class Interpreter
36
- class Storage < Hash
37
- attr_reader :position
38
-
39
- def initialize (data)
40
- if data.is_a?(Array)
41
- parent = {}
42
-
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
53
- end
54
-
55
- def check!
56
- unless self[@position].is_a?(Integer)
57
- self[@position] = 0
58
- end
59
- end
60
-
61
- def forward!
62
- @position += 1
63
- end
64
-
65
- def backward!
66
- @position -= 1
67
- end
68
-
69
- def increase!
70
- check!
71
-
72
- self[@position] += 1
73
- end
74
-
75
- def decrease!
76
- check!
77
-
78
- self[@position] -= 1
79
- end
80
-
81
- def set (value, position=nil)
82
- self[position || @position] = value.ord
83
- end
84
-
85
- def get (position=nil)
86
- self[position || @position].to_i rescue 0
87
- end
88
-
89
- def inspect
90
- "#<Storage(#{position}): #{super}>"
91
- end
92
- end
93
-
94
19
  attr_reader :options, :storage
95
20
 
96
21
  def initialize (options={})
@@ -103,6 +28,7 @@ class Interpreter
103
28
  @parser = RBF::Parser.syntax(RBF.syntax(options[:syntax])).new
104
29
  @transform = RBF::Transform.new
105
30
  @optimizer = RBF::Optimizer.new(options)
31
+ @jit = RBF::JIT.new(options)
106
32
  end
107
33
 
108
34
  def parse (text)
@@ -116,7 +42,7 @@ class Interpreter
116
42
  end
117
43
 
118
44
  def evaluate (tree, options=nil)
119
- options ||= {}
45
+ options = @options.merge(options || {})
120
46
 
121
47
  if options[:catch]
122
48
  @output = StringIO.new
@@ -124,6 +50,12 @@ class Interpreter
124
50
  @output = STDOUT
125
51
  end
126
52
 
53
+ tree = parse(tree)
54
+
55
+ if JIT.supported? && !options[:catch]
56
+ return @jit.compile(tree).execute
57
+ end
58
+
127
59
  cycle(parse(tree))
128
60
 
129
61
  if options[:catch]
@@ -0,0 +1,34 @@
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; class JIT
14
+
15
+ class Code
16
+ attr_reader :options
17
+
18
+ def initialize (tree, options=nil)
19
+ @options = options
20
+
21
+ @module = LLVM::Module.create('brainfuck')
22
+ @module.functions.add('self', [], LLVM::Void) do |func|
23
+ builder = LLVM::Builder.create
24
+ end
25
+
26
+ @module.verify
27
+ end
28
+
29
+ def execute
30
+ LLVM::ExecutionEngine.create_jit_compiler(@module).run_function(@module.functions['self'])
31
+ end
32
+ end
33
+
34
+ end; end
data/lib/rbf/jit.rb ADDED
@@ -0,0 +1,47 @@
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 'memoized'
14
+
15
+ module RBF
16
+
17
+ class JIT
18
+ class << self
19
+ memoize
20
+ def supported?
21
+ raise
22
+
23
+ require 'llvm'
24
+ require 'llvm/core'
25
+ require 'llvm/execution_engine'
26
+ require 'llvm/transforms/scalar'
27
+
28
+ LLVM.init_x86
29
+
30
+ true
31
+ rescue
32
+ false
33
+ end
34
+ end
35
+
36
+ attr_reader :options
37
+
38
+ def initialize (options)
39
+ @options = options
40
+ end
41
+
42
+ def compile (tree)
43
+ Code.new(tree, options)
44
+ end
45
+ end
46
+
47
+ end
data/lib/rbf/optimizer.rb CHANGED
@@ -16,15 +16,20 @@ class Optimizer
16
16
  class Algorithm
17
17
  attr_reader :optimizer
18
18
 
19
- def initialize (optimizer)
19
+ def initialize (optimizer, &block)
20
20
  @optimizer = optimizer
21
+ @block = block
21
22
  end
22
23
 
23
24
  def optimize (tree)
24
- nil
25
+ self.instance_exec(tree, &@block)
25
26
  end
26
27
  end
27
28
 
29
+ def self.optimization (name, &block)
30
+ (@@optimizations ||= []) << [name, block]
31
+ end
32
+
28
33
  attr_reader :options
29
34
 
30
35
  def initialize (options={})
@@ -35,38 +40,66 @@ class Optimizer
35
40
  result = tree.clone
36
41
 
37
42
  algorithms.each {|alg|
38
- alg.new(self).optimize(result)
43
+ alg.optimize(result)
39
44
  }
40
45
 
41
46
  result
42
47
  end
43
48
 
44
49
  def algorithms
45
- Optimizer.constants.map {|const|
46
- Optimizer.const_get(const) unless options[const.to_s.downcase.to_sym] == false
50
+ @@optimizations.map {|(name, block)|
51
+ Algorithm.new(self, &block) unless options[name] == false
47
52
  }.compact
48
53
  end
49
54
 
50
- class UselessOperations < Algorithm
51
- def optimize (tree)
52
- i = 0
55
+ optimization :useless_operations do |tree|
56
+ i = 0
57
+ changed = false
53
58
 
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])
59
+ until i >= tree.length
60
+ if tree[i].is_a?(Array) && tree[i + 1].is_a?(Array)
61
+ optimize(tree[i])
62
+ optimize(tree[i + 1])
58
63
 
59
- i += 2
60
- elsif tree[i].is_a?(Array)
61
- optimize(tree[i])
64
+ i += 2
65
+ elsif tree[i].is_a?(Array)
66
+ optimize(tree[i])
62
67
 
63
- i += 1
64
- elsif [[?+, ?-], [?-, ?+], [?>, ?<], [?<, ?>]].member?(tree[i ... i + 2])
65
- tree.slice!(i ... i + 2)
68
+ i += 1
69
+ elsif [[?+, ?-], [?-, ?+], [?>, ?<], [?<, ?>]].member?(tree[i ... i + 2])
70
+ tree.slice!(i ... i + 2)
71
+
72
+ changed = true
73
+ else
74
+ i += 1
75
+ end
76
+ end
77
+
78
+ optimize(tree) if changed
79
+ end
80
+
81
+ optimization :clear_empty_loops do |tree|
82
+ i = 0
83
+
84
+ until i >= tree.length
85
+ if !tree[i].is_a?(Array)
86
+ i += 1
87
+
88
+ next
89
+ else
90
+ optimize(tree[i])
91
+
92
+ if tree[i].empty?
93
+ unless @warned
94
+ @warned = true
95
+ warn 'Optimizing out one or more potentially dangerous empty loops'
96
+ end
97
+
98
+ tree.delete_at(i)
66
99
  else
67
100
  i += 1
68
101
  end
69
- end
102
+ end
70
103
  end
71
104
  end
72
105
  end
data/lib/rbf/parser.rb CHANGED
@@ -11,6 +11,7 @@
11
11
  #++
12
12
 
13
13
  require 'parslet'
14
+ require 'parslet/convenience'
14
15
 
15
16
  module RBF
16
17
 
data/lib/rbf.rb CHANGED
@@ -13,10 +13,9 @@
13
13
  require 'rbf/syntax'
14
14
  require 'rbf/parser'
15
15
  require 'rbf/optimizer'
16
+ require 'rbf/jit'
16
17
  require 'rbf/interpreter'
17
18
 
18
- require 'parslet/convenience'
19
-
20
19
  module RBF
21
20
  def self.syntax (name)
22
21
  name.is_a?(Hash) ? name :
@@ -74,17 +73,21 @@ module RBF
74
73
  when 'storage'
75
74
  STDOUT.puts interpreter.storage.inspect
76
75
 
77
- when 'position'
78
- STDOUT.puts interpreter.storage.position.to_s.bold
76
+ when /^position(?:\s+(\d+))?$/
77
+ if $1
78
+ interpreter.storage.position = $1
79
+ else
80
+ STDOUT.puts interpreter.storage.position.to_s.bold
81
+ end
79
82
 
80
- when /^get(?:\s*(\d+))?$/
81
- STDOUT.puts "#{($1 || interpreter.storage.position).to_s.bold}: #{interpreter.storage.get($1.to_i)}"
83
+ when /^get(?:\s+(\d+))?$/
84
+ STDOUT.puts "#{($1 || interpreter.storage.position).to_s.bold}: #{interpreter.storage.get($1)}"
82
85
 
83
86
  when /^set(?:\s+(\d+)\s+(\d+))/
84
87
  interpreter.storage.set($2.to_i, $1.to_i)
85
88
 
86
89
  else
87
- STDOUT.puts 'Command not found'.red
90
+ STDOUT.puts 'Command not found or used improperly'.red
88
91
  end
89
92
  else
90
93
  output = interpreter.evaluate(line, interpreter.options.merge(:catch => true))
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: rbf
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.4
5
+ version: 0.0.5
6
6
  platform: ruby
7
7
  authors:
8
8
  - meh.
@@ -34,6 +34,17 @@ dependencies:
34
34
  version: "0"
35
35
  type: :runtime
36
36
  version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: memoized
39
+ prerelease: false
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ type: :runtime
47
+ version_requirements: *id003
37
48
  description:
38
49
  email: meh@paranoici.org
39
50
  executables:
@@ -43,10 +54,14 @@ extensions: []
43
54
  extra_rdoc_files: []
44
55
 
45
56
  files:
57
+ - lib/rbf/jit.rb
46
58
  - lib/rbf/interpreter.rb
59
+ - lib/rbf/interpreter/extensions.rb
60
+ - lib/rbf/interpreter/storage.rb
47
61
  - lib/rbf/syntax.rb
48
62
  - lib/rbf/parser.rb
49
63
  - lib/rbf/optimizer.rb
64
+ - lib/rbf/jit/code.rb
50
65
  - lib/rbf.rb
51
66
  - bin/rbf
52
67
  homepage: http://github.com/meh/rbf