rubex 0.1.1 → 0.1.2

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.
Files changed (131) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/CONTRIBUTING.md +73 -9
  4. data/HISTORY.md +19 -0
  5. data/README.md +53 -8
  6. data/REFERENCE.md +112 -44
  7. data/benchmarks/no_gil/no_gil.rb +24 -0
  8. data/benchmarks/no_gil/no_gil.rubex +22 -0
  9. data/bin/rubex +1 -1
  10. data/examples/c_struct_interface/c_struct_interface.rubex +1 -0
  11. data/lib/rubex.rb +1 -0
  12. data/lib/rubex/ast.rb +11 -7
  13. data/lib/rubex/ast/expression.rb +1 -1
  14. data/lib/rubex/ast/expression/actual_arg_list.rb +7 -0
  15. data/lib/rubex/ast/expression/analysed_element_ref/c_var_element_ref.rb +5 -2
  16. data/lib/rubex/ast/expression/analysed_element_ref/ruby_object_element_ref.rb +26 -9
  17. data/lib/rubex/ast/expression/binary/binary_boolean.rb +1 -1
  18. data/lib/rubex/ast/expression/binary/binary_expo.rb +34 -0
  19. data/lib/rubex/ast/expression/binary/colon2.rb +34 -0
  20. data/lib/rubex/ast/expression/binary/empty_classes.rb +0 -3
  21. data/lib/rubex/ast/expression/command_call.rb +24 -0
  22. data/lib/rubex/ast/{statement → expression/command_call}/print.rb +4 -5
  23. data/lib/rubex/ast/{statement → expression/command_call}/raise.rb +29 -24
  24. data/lib/rubex/ast/expression/command_call/require.rb +27 -0
  25. data/lib/rubex/ast/expression/command_call/yield.rb +36 -0
  26. data/lib/rubex/ast/expression/element_ref.rb +10 -5
  27. data/lib/rubex/ast/expression/instance_var.rb +33 -0
  28. data/lib/rubex/ast/expression/method_call.rb +4 -2
  29. data/lib/rubex/ast/expression/method_call/c_function_call.rb +4 -3
  30. data/lib/rubex/ast/expression/method_call/ruby_method_call.rb +7 -5
  31. data/lib/rubex/ast/expression/name.rb +10 -1
  32. data/lib/rubex/ast/expression/ruby_object_element_ref/ruby_array_element_ref.rb +5 -2
  33. data/lib/rubex/ast/expression/ruby_object_element_ref/ruby_hash_element_ref.rb +10 -2
  34. data/lib/rubex/ast/expression/to_ruby_object.rb +1 -0
  35. data/lib/rubex/ast/expression/unary.rb +7 -3
  36. data/lib/rubex/ast/expression/unary_base/ampersand.rb +5 -0
  37. data/lib/rubex/ast/node.rb +213 -185
  38. data/lib/rubex/ast/node/file_node.rb +25 -0
  39. data/lib/rubex/ast/node/main_node.rb +56 -0
  40. data/lib/rubex/ast/statement/begin_block/begin.rb +4 -3
  41. data/lib/rubex/ast/statement/c_array_decl.rb +1 -1
  42. data/lib/rubex/ast/statement/c_ptr_decl.rb +2 -0
  43. data/lib/rubex/ast/statement/no_gil_block.rb +70 -0
  44. data/lib/rubex/ast/statement/return.rb +1 -0
  45. data/lib/rubex/ast/top_statement.rb +1 -1
  46. data/lib/rubex/ast/top_statement/klass.rb +4 -0
  47. data/lib/rubex/ast/top_statement/klass/attached_klass.rb +88 -10
  48. data/lib/rubex/ast/top_statement/method_def.rb +2 -3
  49. data/lib/rubex/ast/top_statement/method_def/c_function_def.rb +10 -4
  50. data/lib/rubex/cli.rb +11 -6
  51. data/lib/rubex/code_supervisor.rb +49 -0
  52. data/lib/rubex/code_writer.rb +22 -1
  53. data/lib/rubex/compiler.rb +109 -30
  54. data/lib/rubex/compiler_config.rb +14 -1
  55. data/lib/rubex/constants.rb +3 -0
  56. data/lib/rubex/data_type.rb +2 -3
  57. data/lib/rubex/data_type/ruby_object/ruby_symbol.rb +0 -1
  58. data/lib/rubex/error.rb +4 -0
  59. data/lib/rubex/helpers/writers.rb +33 -4
  60. data/lib/rubex/lexer.rex +9 -1
  61. data/lib/rubex/lexer.rex.rb +15 -2
  62. data/lib/rubex/parser.racc +125 -49
  63. data/lib/rubex/parser.racc.rb +1526 -1376
  64. data/lib/rubex/rake_task.rb +42 -6
  65. data/lib/rubex/symbol_table/entry.rb +6 -0
  66. data/lib/rubex/symbol_table/scope.rb +28 -3
  67. data/lib/rubex/version.rb +1 -1
  68. data/rubex.gemspec +1 -0
  69. data/spec/basic_ruby_method_spec.rb +2 -2
  70. data/spec/blocks_spec.rb +2 -2
  71. data/spec/box_op_multi_args_spec.rb +34 -0
  72. data/spec/c_function_ptrs_spec.rb +2 -2
  73. data/spec/c_functions_spec.rb +2 -0
  74. data/spec/c_struct_interface_spec.rb +8 -3
  75. data/spec/default_args_spec.rb +2 -2
  76. data/spec/external_c_struct_spec.rb +33 -0
  77. data/spec/fixtures/api/consumer.rubex +0 -0
  78. data/spec/fixtures/api/implementation.rubex +0 -0
  79. data/spec/fixtures/api/implementation.rubexd +0 -0
  80. data/spec/fixtures/box_op_multi_args/box_op_multi_args.rubex +3 -0
  81. data/spec/fixtures/c_functions/c_functions.rubex +13 -0
  82. data/spec/fixtures/c_struct_interface/c_struct_interface.rubex +28 -0
  83. data/spec/fixtures/class_methods/class_methods.rubex +1 -1
  84. data/spec/fixtures/error_handling/error_handling.rubex +2 -2
  85. data/spec/fixtures/external_c_struct/external_c_struct.rubex +16 -0
  86. data/spec/fixtures/if_else/if_else.rubex +1 -1
  87. data/spec/fixtures/init_ruby_objects_with_literal_syntax/init_ruby_objects_with_literal_syntax.rubex +1 -1
  88. data/spec/fixtures/instance_variables/instance_variables.rubex +25 -0
  89. data/spec/fixtures/loops/loops.rubex +2 -2
  90. data/spec/fixtures/module/module.rubex +28 -0
  91. data/spec/fixtures/multi_file_programs/Rakefile +8 -0
  92. data/spec/fixtures/multi_file_programs/a.rubex +5 -0
  93. data/spec/fixtures/multi_file_programs/b.rubex +5 -0
  94. data/spec/fixtures/multi_file_programs/multi_file_programs.rubex +14 -0
  95. data/spec/fixtures/no_gil/no_gil.rubex +24 -0
  96. data/spec/fixtures/no_gil_attach_class/no_gil_attach_class.rubex +23 -0
  97. data/spec/fixtures/no_gil_compile_check/no_gil_compile_check.rubex +4 -0
  98. data/spec/fixtures/outside_stmts/outside_stmts.rubex +6 -0
  99. data/spec/fixtures/pow/pow.rubex +4 -0
  100. data/spec/fixtures/rake_task/single_file/test.rubex +3 -0
  101. data/spec/fixtures/recursion/recursion.rubex +1 -1
  102. data/spec/fixtures/ruby_constant_scoping/ruby_constant_scoping.rubex +7 -0
  103. data/spec/fixtures/ruby_operators/ruby_operators.rubex +1 -1
  104. data/spec/fixtures/ruby_raise/ruby_raise.rubex +2 -2
  105. data/spec/fixtures/ruby_types/ruby_types.rubex +4 -4
  106. data/spec/fixtures/statement_expression/statement_expression.rubex +2 -2
  107. data/spec/fixtures/static_array/static_array.rubex +3 -3
  108. data/spec/fixtures/string_literals/string_literals.rubex +12 -2
  109. data/spec/fixtures/struct/struct.rubex +1 -1
  110. data/spec/fixtures/var_declarations/var_declarations.rubex +1 -1
  111. data/spec/implicit_lib_include_spec.rb +2 -2
  112. data/spec/init_ruby_objects_with_literal_syntax_spec.rb +2 -2
  113. data/spec/instance_variables_spec.rb +33 -0
  114. data/spec/loops_spec.rb +2 -2
  115. data/spec/module_spec.rb +39 -0
  116. data/spec/multi_file_programs_spec.rb +41 -0
  117. data/spec/no_gil_attach_class_spec.rb +33 -0
  118. data/spec/no_gil_compile_check_spec.rb +25 -0
  119. data/spec/no_gil_spec.rb +36 -0
  120. data/spec/outside_stmts_spec.rb +34 -0
  121. data/spec/pow_spec.rb +33 -0
  122. data/spec/rake_task_spec.rb +142 -0
  123. data/spec/recursion_spec.rb +4 -4
  124. data/spec/ruby_constant_scoping_spec.rb +42 -0
  125. data/spec/ruby_raise_spec.rb +2 -2
  126. data/spec/ruby_symbols_spec.rb +2 -2
  127. data/spec/ruby_types_spec.rb +2 -2
  128. data/spec/spec_helper.rb +17 -3
  129. data/spec/string_literals_spec.rb +1 -0
  130. metadata +90 -6
  131. data/lib/rubex/ast/statement/yield.rb +0 -41
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubex do
4
+ test_case = "module"
5
+
6
+ context "Case: #{test_case}" do
7
+ before do
8
+ @path = path_str test_case
9
+ end
10
+
11
+ context ".ast" do
12
+ skip "generates the AST" do
13
+ t = Rubex::Compiler.ast(@path + '.rubex')
14
+ end
15
+ end
16
+
17
+ context ".compile" do
18
+ skip "compiles to valid C file" do
19
+ t,c,e = Rubex::Compiler.compile(@path + '.rubex', test: true)
20
+ end
21
+ end
22
+
23
+ context "Black Box testing" do
24
+ skip "compiles and checks for valid output" do
25
+ setup_and_teardown_compiled_files(test_case) do |dir|
26
+ require_relative "#{dir}/#{test_case}.#{os_extension}"
27
+
28
+ expect(Foo::Bar.new.baz).to eq("hello world")
29
+
30
+ include Bar
31
+ expect(b).to eq("b")
32
+
33
+ include Outer::Inner
34
+ expect(abc).to eq("abc")
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubex do
4
+ test_case = "multi_file_programs"
5
+
6
+ context "Case: #{test_case}" do
7
+ before do
8
+ @dir = dir_str test_case
9
+ @t_dir = @dir + "/#{test_case}"
10
+ @main_file = path_str test_case
11
+ @file_names = ["a.rubex", "b.rubex", "multi_file_programs.rubex"]
12
+ end
13
+
14
+ context ".ast" do
15
+ it "generates the AST" do
16
+ t = Rubex::Compiler.ast(@main_file + '.rubex', source_dir: @dir)
17
+ end
18
+ end
19
+
20
+ context ".compile" do
21
+ it "compiles to valid C file" do
22
+ t,c,e = Rubex::Compiler.compile(@main_file + '.rubex', files: @file_names,
23
+ source_dir: @dir, test: true, multi_file: true,
24
+ target_dir: @t_dir)
25
+ end
26
+ end
27
+
28
+ context "black box testing" do
29
+ it "compiles and checks for valid output" do
30
+ setup_and_teardown_multiple_compiled_files(
31
+ @main_file + '.rubex', @dir, @t_dir, @file_names) do |dir|
32
+
33
+ require_relative "#{dir}/#{test_case}.#{os_extension}"
34
+ expect(C.new("hello ruby").bar).to eq("hello ruby")
35
+ expect(D.new("ruby ").foo).to eq("ruby hello world")
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubex do
4
+ test_case = "no_gil_attach_class"
5
+
6
+ context "Case: #{test_case}" do
7
+ before do
8
+ @path = path_str test_case
9
+ end
10
+
11
+ context ".ast" do
12
+ it "generates the AST" do
13
+ t = Rubex::Compiler.ast(@path + '.rubex')
14
+ end
15
+ end
16
+
17
+ context ".compile" do
18
+ skip "compiles to valid C file" do
19
+ t,c,e = Rubex::Compiler.compile(@path + '.rubex', test: true)
20
+ end
21
+ end
22
+
23
+ context "Black Box testing" do
24
+ skip "compiles and checks for valid output" do
25
+ setup_and_teardown_compiled_files(test_case) do |dir|
26
+ require_relative "#{dir}/#{test_case}.#{os_extension}"
27
+
28
+ expect(A.new.foo)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubex do
4
+ test_case = "no_gil_compile_check"
5
+
6
+ context "Case: #{test_case}" do
7
+ before do
8
+ @path = path_str test_case
9
+ end
10
+
11
+ context ".ast" do
12
+ it "generates the AST" do
13
+ t = Rubex::Compiler.ast(@path + '.rubex')
14
+ end
15
+ end
16
+
17
+ context ".compile" do
18
+ it "raises compile error" do
19
+ expect {
20
+ Rubex::Compiler.compile(@path + '.rubex', test: true)
21
+ }.to raise_error(Rubex::CompileCheckError)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubex do
4
+ test_case = "no_gil"
5
+
6
+ context "Case: #{test_case}" do
7
+ before do
8
+ @path = path_str test_case
9
+ end
10
+
11
+ context ".ast" do
12
+ it "generates the AST" do
13
+ t = Rubex::Compiler.ast(@path + '.rubex')
14
+ end
15
+ end
16
+
17
+ context ".compile" do
18
+ it "compiles to valid C file" do
19
+ t,c,e = Rubex::Compiler.compile(@path + '.rubex', test: true)
20
+ end
21
+ end
22
+
23
+ context "Black Box testing" do
24
+ it "compiles and checks for valid output" do
25
+ setup_and_teardown_compiled_files(test_case) do |dir|
26
+ require_relative "#{dir}/#{test_case}.#{os_extension}"
27
+ N = 999
28
+
29
+ n = Thread.new { work_without_gil(N) }
30
+ m = Thread.new { work_without_gil(N) }
31
+ n.join; m.join
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+ include Rubex::AST
3
+
4
+ describe Rubex do
5
+ test_case = 'outside_stmts'
6
+
7
+ context "Case : #{test_case}" do
8
+ before do
9
+ @path = path_str test_case
10
+ end
11
+
12
+ context ".ast" do
13
+ it "returns a valid Abstract Syntax Tree" do
14
+ t = Rubex::Compiler.ast @path + ".rubex"
15
+ end
16
+ end
17
+
18
+ context ".compile" do
19
+ it "generates valid C code" do
20
+ t, c, e = Rubex::Compiler.compile @path + ".rubex", test: true
21
+ end
22
+ end
23
+
24
+ context "Black Box testing" do
25
+ it "compiles and checks for valid output" do
26
+ setup_and_teardown_compiled_files(test_case) do |dir|
27
+ require_relative "#{dir}/#{test_case}.#{os_extension}"
28
+
29
+ expect(use_narray).to eq(3.0)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rubex do
4
+ test_case = "pow"
5
+
6
+ context "Case: #{test_case}" do
7
+ before do
8
+ @path = path_str test_case
9
+ end
10
+
11
+ context ".ast" do
12
+ it "generates the AST" do
13
+ t = Rubex::Compiler.ast(@path + '.rubex')
14
+ end
15
+ end
16
+
17
+ context ".compile" do
18
+ it "compiles to valid C file" do
19
+ t,c,e = Rubex::Compiler.compile(@path + '.rubex', test: true)
20
+ end
21
+ end
22
+
23
+ context "Black Box testing" do
24
+ it "compiles and checks for valid output" do
25
+ setup_and_teardown_compiled_files(test_case) do |dir|
26
+ require_relative "#{dir}/#{test_case}.#{os_extension}"
27
+
28
+ expect(test_pow(4, 2)).to eq(20)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,142 @@
1
+ require 'spec_helper'
2
+ require 'rubex/rake_task'
3
+
4
+ describe Rubex::RakeTask do
5
+ context "#files" do
6
+ it "specifies rubex files for a multi-file compile" do
7
+ files = ["foo.rubex", "bar.rubex", "bar.rubex"]
8
+ task = Rubex::RakeTask.new("test") do
9
+ files files
10
+ end
11
+
12
+ expect(task.rubex_files).to eq(files)
13
+ end
14
+ end
15
+
16
+ context "#ext" do
17
+ before do
18
+ @task_name = "test"
19
+ end
20
+
21
+ it "assumes default dir for ext in a gem" do
22
+ task = Rubex::RakeTask.new(@task_name)
23
+ expect(task.ext_dir).to eq("#{Dir.pwd}/ext/#{@task_name}")
24
+ end
25
+
26
+ it "allows user to set the ext directory" do
27
+ task = Rubex::RakeTask.new(@task_name) do
28
+ ext Dir.pwd
29
+ end
30
+ expect(task.ext_dir).to eq(Dir.pwd)
31
+ end
32
+ end
33
+
34
+ context "#debug" do
35
+ before do
36
+ @task_name = "test"
37
+ end
38
+
39
+ it "sets debug flag -g during compilation" do
40
+ task = Rubex::RakeTask.new(@task_name) do
41
+ debug = true
42
+ end
43
+
44
+ expect(task.debug).to eq(true)
45
+ end
46
+ end
47
+ end
48
+
49
+ describe "rake" do
50
+ context "rubex:compile" do
51
+ before do
52
+ Rake::Task.clear
53
+ end
54
+
55
+ it "compiles a single file program" do
56
+ ext_path = "#{Dir.pwd}/spec/fixtures/rake_task/single_file"
57
+ name = "test"
58
+ Rubex::RakeTask.new(name) do
59
+ ext ext_path
60
+ end
61
+ Rake::Task["rubex:compile"].invoke
62
+
63
+ build_path = "#{ext_path}/#{name}"
64
+ expect(File.exist?("#{build_path}/#{name}.c")).to eq(true)
65
+ expect(File.exist?("#{build_path}/extconf.rb")).to eq(true)
66
+
67
+ # delete generated files
68
+ Dir.chdir(build_path) do
69
+ FileUtils.rm(
70
+ Dir.glob(
71
+ "#{build_path}/*.{c,h,so,o,bundle,dll}") + ["Makefile", "extconf.rb"], force: true
72
+ )
73
+ end
74
+ FileUtils.rmdir(build_path)
75
+ end
76
+
77
+ it "compiles a multiple file program" do
78
+ Rubex::RakeTask.new("test") do
79
+ ext "#{Dir.pwd}/fixtures/rake_task/multi_file"
80
+ files ["a.rubex", "test.rubex"]
81
+ end
82
+ Rake::Task["rubex:compile"].invoke
83
+ end
84
+ end
85
+
86
+ context "rake:clobber" do
87
+ before do
88
+ Rake::Task.clear
89
+ end
90
+
91
+ it "clobbers generated files." do
92
+ ext_path = "#{Dir.pwd}/spec/fixtures/rake_task/single_file"
93
+ name = "test"
94
+ Rubex::RakeTask.new(name) do
95
+ ext ext_path
96
+ end
97
+ Rake::Task["rubex:compile"].invoke
98
+ Rake::Task["rubex:clobber"].invoke
99
+
100
+ expect(!File.exist?("#{ext_path}/#{name}/#{name}.c")).to eq(true)
101
+ expect(!File.exist?("#{ext_path}/#{name}/extconf.rb")).to eq(true)
102
+ end
103
+ end
104
+
105
+ context "rake:compile:install" do
106
+ before do
107
+ Rake::Task.clear
108
+ end
109
+
110
+ context "for single file" do
111
+ it "generates the shared object file after compilation" do
112
+ ext_path = "#{Dir.pwd}/spec/fixtures/rake_task/single_file"
113
+ name = "test"
114
+ Rubex::RakeTask.new(name) do
115
+ ext ext_path
116
+ end
117
+ Rake::Task["rubex:compile:install"].invoke
118
+
119
+ expect(File.exist?("#{ext_path}/#{name}/#{name}.c")).to eq(true)
120
+ expect(File.exist?("#{ext_path}/#{name}/extconf.rb")).to eq(true)
121
+ expect(File.exist?("#{ext_path}/#{name}/#{name}.so")).to eq(true)
122
+
123
+ # delete generated files
124
+ dir = "#{ext_path}/#{name}"
125
+ Dir.chdir(dir) do
126
+ FileUtils.rm(
127
+ Dir.glob(
128
+ "#{dir}/#{name}.{c,h,so,o,bundle,dll}") + ["Makefile", "extconf.rb"],
129
+ force: true
130
+ )
131
+ end
132
+ FileUtils.rmdir(dir)
133
+ end
134
+ end
135
+
136
+ context "for multi file" do
137
+ skip "generates .so file after compilation" do
138
+ # TODO
139
+ end
140
+ end
141
+ end
142
+ end
@@ -9,22 +9,22 @@ describe Rubex do
9
9
  end
10
10
 
11
11
  context '.ast' do
12
- skip 'generates a valid AST' do
12
+ it 'generates a valid AST' do
13
13
  t = Rubex::Compiler.ast(@path + '.rubex')
14
14
  end
15
15
  end
16
16
 
17
17
  context '.compile' do
18
- skip 'compiles to valid C code' do
18
+ it 'compiles to valid C code' do
19
19
  t, c, e = Rubex::Compiler.compile(@path + '.rubex', test: true)
20
20
  end
21
21
  end
22
22
 
23
23
  context 'Black Box testing' do
24
- skip 'compiles and checks for valid output' do
24
+ it 'compiles and checks for valid output' do
25
25
  setup_and_teardown_compiled_files(test_case) do |dir|
26
26
  require_relative "#{dir}/#{test_case}.#{os_extension}"
27
- expect(Fibonnaci.new.compute(5)).to eq(5)
27
+ expect(Fibonnaci.new.compute(10)).to eq(55)
28
28
  end
29
29
  end
30
30
  end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ include Rubex::AST
3
+
4
+ describe Rubex do
5
+ test_case = 'ruby_constant_scoping'
6
+
7
+ context "Case : #{test_case}" do
8
+ before do
9
+ @path = path_str test_case
10
+ end
11
+
12
+ context ".ast" do
13
+ it "returns a valid Abstract Syntax Tree" do
14
+ t = Rubex::Compiler.ast @path + ".rubex"
15
+ end
16
+ end
17
+
18
+ context ".compile" do
19
+ it "generates valid C code" do
20
+ t, c, e = Rubex::Compiler.compile @path + ".rubex", test: true
21
+ end
22
+ end
23
+
24
+ context "Black Box testing" do
25
+ it "compiles and checks for valid output" do
26
+ setup_and_teardown_compiled_files(test_case) do |dir|
27
+ class Foo
28
+ class Bar
29
+ class Baz
30
+ NUMBER = 10
31
+ end
32
+ end
33
+ end
34
+ require_relative "#{dir}/#{test_case}.#{os_extension}"
35
+
36
+ expect(get_eid.is_a?(Fixnum)).to eq(true)
37
+ expect(user_chained_const).to eq(10)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end