rusby 0.1.0

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,54 @@
1
+ module Rusby
2
+ module Generators
3
+ module Loops
4
+ def generate_loop(ast)
5
+ statements = ast.children[1..-1].map { |node| generate(node) }.compact
6
+ "loop {\n#{statements.join("\n")}\n}"
7
+ end
8
+
9
+ def generate_each_loop(ast)
10
+ if ast.children[0].children[0].type == :lvar
11
+ generate_each_loop_plain(ast)
12
+ else
13
+ generate_each_loop_range(ast)
14
+ end
15
+ end
16
+
17
+ def generate_each_loop_plain(ast)
18
+ collection = ast.children[0].children[0].children[0]
19
+ variable = ast.children[1].children[0].children[0]
20
+ body = ast.children[2..-1].map { |node| generate(node) }.join("\n")
21
+ "for #{variable} in #{collection}.iter() {
22
+ #{body}
23
+ }"
24
+ end
25
+
26
+ def generate_each_with_index_loop(ast)
27
+ collection = ast.children[0].children[0].children[0]
28
+ variable = ast.children[1].children[0].children[0]
29
+ index = ast.children[1].children[1].children[0]
30
+ body = ast.children[2..-1].map { |node| generate(node) }.join("\n")
31
+ "for (#{index}, #{variable}) in #{collection}.iter().enumerate() {
32
+ #{body}
33
+ }"
34
+ end
35
+
36
+ def generate_each_loop_range(ast)
37
+ range = ast.children[0].children[0].children[0]
38
+ range_start = range.children[0].children[0]
39
+ range_end = "(#{range.children[1].children[0]} + 1)" # rust range is inclusive
40
+ range_variable = ast.children[1].children[0].children[0]
41
+ statements = ast.children[1..-1].map { |node| generate(node) }.compact
42
+ "for #{range_variable} in #{range_start}..#{range_end} {\n#{statements.join("\n")}\n}"
43
+ end
44
+
45
+ def generate_while(ast)
46
+ "while #{generate(ast.children[0])} {\n#{generate(ast.children[1])}\n}"
47
+ end
48
+
49
+ def generate_while_post(ast)
50
+ "while {\n#{generate(ast.children[1])};\n#{generate(ast.children[0])}\n}{}"
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,26 @@
1
+ module Rusby
2
+ module Generators
3
+ module Misc
4
+ def generate_begin(ast)
5
+ ast.children.map { |node| generate(node) }.join("\n")
6
+ end
7
+
8
+ def generate_args(_ast)
9
+ end
10
+
11
+ def generate_and(ast)
12
+ "#{generate(ast.children[0])} && #{generate(ast.children[1])}"
13
+ end
14
+
15
+ def generate_return(ast)
16
+ statements = ast.children.map { |node| generate(node) }
17
+ "return #{statements.any? ? statements.join(',') : '&-ptr'} as #{@return_type};"
18
+ end
19
+
20
+ def generate_kwbegin(ast)
21
+ statements = ast.children.map { |node| generate(node) }
22
+ statements.join(';')
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,10 @@
1
+ module Rusby
2
+ module Generators
3
+ module Strings
4
+ # string interpolation
5
+ def generate_dstr(ast)
6
+ ast.children.map { |node| "(#{generate(node)}).to_string()" }.join(' + &')
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,33 @@
1
+ module Rusby
2
+ module Generators
3
+ module Types
4
+ def generate_int(ast)
5
+ ast.children[0]
6
+ end
7
+
8
+ def generate_float(ast)
9
+ ast.children[0]
10
+ end
11
+
12
+ def generate_str(ast)
13
+ "\"#{ast.children[0]}\""
14
+ end
15
+
16
+ def generate_true(_ast)
17
+ 'true'
18
+ end
19
+
20
+ def generate_false(_ast)
21
+ 'false'
22
+ end
23
+
24
+ def generate_array(_ast)
25
+ 'Vec::new()'
26
+ end
27
+
28
+ def generate_const(ast)
29
+ '<array>' if ast.children[1] == :Array
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ module Rusby
2
+ module Postrocessor
3
+ extend self
4
+
5
+ def apply(code, meta)
6
+ # fold the array syntax
7
+ meta[:args].each_with_index do |el, idx|
8
+ if el == 'String'
9
+ code.gsub!(/#{meta[:names][idx]}\[(.+?)\]/, "#{meta[:names][idx]}.chars().nth(\\1)")
10
+ code.gsub!(/;+/, ';')
11
+ end
12
+ end
13
+ # process array :<< and :>> operator
14
+ code.gsub!(/(?:<<|>>)(\S+)/, '.push(\1);')
15
+
16
+ code
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ module Rusby
2
+ module Preprocessor
3
+ extend self
4
+
5
+ def apply(code)
6
+ code = code.gsub(
7
+ /(\w+)\s?=\s?Array\.new\((.*)\)\s?{\s?Array\.new\((.*)\)\s?}/,
8
+ 'rust_variable :\1' \
9
+ "\n" \
10
+ 'rust "let mut \1 = vec![vec![0; \3]; \2];"'
11
+ )
12
+ code
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,32 @@
1
+ module Rusby
2
+ module Profiler
3
+ extend self
4
+
5
+ SQRT_ITERATIONS = Math.sqrt(1000).to_i
6
+
7
+ def timeit(target_method, *args)
8
+ Benchmark.realtime { SQRT_ITERATIONS.times { target_method.call(*args) } }
9
+ end
10
+
11
+ def benchit(obj, original_method, modified_method, args)
12
+ original_method = original_method.bind(obj)
13
+
14
+ m1 = 0
15
+ m2 = 0
16
+
17
+ SQRT_ITERATIONS.times do |i|
18
+ m1 += timeit(original_method, *args)
19
+ m2 += timeit(modified_method, *args)
20
+
21
+ percent = ((i + 1).to_f / SQRT_ITERATIONS * 100).to_i
22
+ print "\r|#{'=' * percent}#{'-' * (100 - percent)}|"
23
+ end
24
+
25
+ boost = m1 > m2 ? m1 / m2 : - m2 / m1
26
+
27
+ printf "\r=> got #{'%.2fx boost'.colorize(boost > 0 ? :green : :red)} (%.2fs original vs %.2fs rust) %s\n\n", boost, m1, m2, ' ' * 80
28
+
29
+ boost
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,14 @@
1
+ module Rusby
2
+ module Proxy
3
+ extend ::FFI::Library
4
+
5
+ def self.libext
6
+ return 'dylib' if `uname` =~ /Darwin/
7
+ return 'so' if `uname` =~ /Linux/
8
+ end
9
+
10
+ def self.rusby_load(fullpath)
11
+ ffi_lib "#{fullpath}.#{libext}"
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,69 @@
1
+ module Rusby
2
+ class Rust
3
+ include ::Rusby::Generators::Base
4
+
5
+ include ::Rusby::Generators::Assignments
6
+ include ::Rusby::Generators::Conditionals
7
+ include ::Rusby::Generators::Loops
8
+ include ::Rusby::Generators::Misc
9
+ include ::Rusby::Generators::Strings
10
+ include ::Rusby::Generators::Types
11
+
12
+ def initialize(return_type)
13
+ @known_methods = []
14
+ @known_variables = []
15
+ @return_type = return_type
16
+ end
17
+
18
+ def known_method?(name)
19
+ @known_methods.include?(name.to_sym)
20
+ end
21
+
22
+ def remember_method(name)
23
+ @known_methods << name.to_sym
24
+ end
25
+
26
+ def known_variable?(name)
27
+ @known_variables.include?(name.to_sym)
28
+ end
29
+
30
+ def remember_variable(name)
31
+ @known_variables << name.to_sym
32
+ end
33
+
34
+ def fold_arrays(nodes)
35
+ result = []
36
+ index_op = false
37
+ index_assignment_op = false
38
+
39
+ nodes.each do |node|
40
+ case node
41
+ when :[]
42
+ index_op = true
43
+ when :[]=
44
+ index_assignment_op = true
45
+ else
46
+ code = generate(node)
47
+ if index_op
48
+ code = "[#{code.to_s =~ /[+-]/ ? "(#{code})" : code} as usize]"
49
+ index_op = false
50
+ end
51
+ if index_assignment_op
52
+ code = "[#{code.to_s =~ /[+-]/ ? "(#{code})" : code} as usize]="
53
+ index_assignment_op = false
54
+ end
55
+ result << code
56
+ end
57
+ end
58
+
59
+ result
60
+ end
61
+
62
+ def method_missing(method_name, *args)
63
+ puts "No method for '#{method_name.to_s.sub('generate_', '')}' AST node.".colorize(:red)
64
+ puts "Please implement #{method_name} in Rusby::Rust.".colorize(:yellow)
65
+ puts "Arguments: #{args.inspect}".colorize(:yellow)
66
+ raise RuntimeError
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,3 @@
1
+ module Rusby
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rusby'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rusby"
8
+ spec.version = Rusby::VERSION
9
+ spec.authors = ["Alexander Krasnoschekov"]
10
+ spec.email = ["akrasnoschekov@gmail.com"]
11
+
12
+ spec.summary = %q{Ruby to Rust transpiler for simple performance-oriented methods.}
13
+ spec.homepage = "https://github.com/rambler-digital-solutions/rusby"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.12"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec", "~> 3.0"
24
+ spec.add_development_dependency "byebug"
25
+
26
+ spec.add_runtime_dependency 'method_source'
27
+ spec.add_runtime_dependency 'ffi'
28
+ spec.add_runtime_dependency 'hashie'
29
+ spec.add_runtime_dependency 'colorize'
30
+ spec.add_runtime_dependency 'parser'
31
+ spec.add_runtime_dependency 'ruby-prof'
32
+ end
@@ -0,0 +1,38 @@
1
+ ffi_to_rust:
2
+ String: 'let <name> = unsafe { CStr::from_ptr(<name>_pointer).to_string_lossy().into_owned() };'
3
+ Array[Fixnum]: 'let <name> = unsafe { std::slice::from_raw_parts_mut(<name>_pointer, <name>_size) };'
4
+ Array[Float]: 'let <name> = unsafe { std::slice::from_raw_parts_mut(<name>_pointer, <name>_size) };'
5
+ ffi_to_rust_types:
6
+ String: '<name>_pointer: *const c_char'
7
+ Array[Fixnum]: '<name>_pointer: *mut i32, <name>_size: usize'
8
+ Array[Float]: '<name>_pointer: *mut f64, <name>_size: usize'
9
+ rust_to_ffi:
10
+ String: 'CString::new(result).unwrap().as_ptr()'
11
+ Array[Fixnum]: 'result.as_ptr()'
12
+ Array[Float]: 'result.as_ptr()'
13
+ rust_to_ffi_types:
14
+ Array[Fixnum]: '*const i32'
15
+ Array[Float]: '*const f64'
16
+ String: '*const c_char'
17
+ rust_types:
18
+ Fixnum: 'i32'
19
+ Array[Fixnum]: '&mut [i32]'
20
+ Array[Float]: '&mut [f64]'
21
+ NilClass: '()'
22
+ String: 'String'
23
+ Float: 'f64'
24
+ ffi_types:
25
+ Fixnum: 'int'
26
+ Array[Fixnum]: 'pointer'
27
+ Array[Float]: 'pointer'
28
+ NilClass: 'void'
29
+ String: 'string'
30
+ Float: 'double'
31
+ file_header: |
32
+ use std::io::{self, Write};
33
+ use std::ffi::{CStr,CString};
34
+ use std::os::raw::c_char;
35
+ method_prefix: "\n#[allow(unused_mut)]"
36
+ exposed_method_prefix: |
37
+ #[no_mangle]
38
+ pub extern "C"
metadata ADDED
@@ -0,0 +1,223 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rusby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Alexander Krasnoschekov
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-08-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: method_source
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: ffi
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: hashie
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: colorize
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: parser
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: ruby-prof
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description:
154
+ email:
155
+ - akrasnoschekov@gmail.com
156
+ executables: []
157
+ extensions: []
158
+ extra_rdoc_files: []
159
+ files:
160
+ - ".gitignore"
161
+ - ".travis.yml"
162
+ - CODE_OF_CONDUCT.md
163
+ - Gemfile
164
+ - Gemfile.lock
165
+ - LICENSE.txt
166
+ - README.md
167
+ - Rakefile
168
+ - bin/console
169
+ - bin/setup
170
+ - doc/img1.png
171
+ - doc/slides.key
172
+ - examples/Gemfile
173
+ - examples/Gemfile.lock
174
+ - examples/fanatic_greeter.rb
175
+ - examples/fanatic_pluser.rb
176
+ - examples/levenshtein_distance.rb
177
+ - examples/quicksort.rb
178
+ - examples/run_examples.rb
179
+ - examples/weighted_random.rb
180
+ - lib/rusby.rb
181
+ - lib/rusby/builder.rb
182
+ - lib/rusby/core.rb
183
+ - lib/rusby/ffi/bridge.rb
184
+ - lib/rusby/generators/assignments.rb
185
+ - lib/rusby/generators/base.rb
186
+ - lib/rusby/generators/conditionals.rb
187
+ - lib/rusby/generators/loops.rb
188
+ - lib/rusby/generators/misc.rb
189
+ - lib/rusby/generators/strings.rb
190
+ - lib/rusby/generators/types.rb
191
+ - lib/rusby/postprocessor.rb
192
+ - lib/rusby/preprocessor.rb
193
+ - lib/rusby/profiler.rb
194
+ - lib/rusby/proxy.rb
195
+ - lib/rusby/rust.rb
196
+ - lib/rusby/version.rb
197
+ - rusby.gemspec
198
+ - rust.yaml
199
+ homepage: https://github.com/rambler-digital-solutions/rusby
200
+ licenses:
201
+ - MIT
202
+ metadata: {}
203
+ post_install_message:
204
+ rdoc_options: []
205
+ require_paths:
206
+ - lib
207
+ required_ruby_version: !ruby/object:Gem::Requirement
208
+ requirements:
209
+ - - ">="
210
+ - !ruby/object:Gem::Version
211
+ version: '0'
212
+ required_rubygems_version: !ruby/object:Gem::Requirement
213
+ requirements:
214
+ - - ">="
215
+ - !ruby/object:Gem::Version
216
+ version: '0'
217
+ requirements: []
218
+ rubyforge_project:
219
+ rubygems_version: 2.4.5
220
+ signing_key:
221
+ specification_version: 4
222
+ summary: Ruby to Rust transpiler for simple performance-oriented methods.
223
+ test_files: []