rubex 0.1.1 → 0.1.2

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