rbf 0.0.4 → 0.0.5

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