rbf 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/rbf/interpreter/extensions.rb +31 -0
- data/lib/rbf/interpreter/storage.rb +73 -0
- data/lib/rbf/interpreter.rb +10 -78
- data/lib/rbf/jit/code.rb +34 -0
- data/lib/rbf/jit.rb +47 -0
- data/lib/rbf/optimizer.rb +52 -19
- data/lib/rbf/parser.rb +1 -0
- data/lib/rbf.rb +10 -7
- metadata +16 -1
@@ -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
|
data/lib/rbf/interpreter.rb
CHANGED
@@ -10,87 +10,12 @@
|
|
10
10
|
# 0. You just DO WHAT THE FUCK YOU WANT TO.
|
11
11
|
#++
|
12
12
|
|
13
|
-
require '
|
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]
|
data/lib/rbf/jit/code.rb
ADDED
@@ -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
|
-
|
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.
|
43
|
+
alg.optimize(result)
|
39
44
|
}
|
40
45
|
|
41
46
|
result
|
42
47
|
end
|
43
48
|
|
44
49
|
def algorithms
|
45
|
-
|
46
|
-
|
50
|
+
@@optimizations.map {|(name, block)|
|
51
|
+
Algorithm.new(self, &block) unless options[name] == false
|
47
52
|
}.compact
|
48
53
|
end
|
49
54
|
|
50
|
-
|
51
|
-
|
52
|
-
|
55
|
+
optimization :useless_operations do |tree|
|
56
|
+
i = 0
|
57
|
+
changed = false
|
53
58
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
60
|
-
|
61
|
-
|
64
|
+
i += 2
|
65
|
+
elsif tree[i].is_a?(Array)
|
66
|
+
optimize(tree[i])
|
62
67
|
|
63
|
-
|
64
|
-
|
65
|
-
|
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
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
|
78
|
-
|
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
|
81
|
-
STDOUT.puts "#{($1 || interpreter.storage.position).to_s.bold}: #{interpreter.storage.get($1
|
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.
|
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
|