rubex 0.1 → 0.1.1

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 (197) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -2
  3. data/.travis.yml +9 -1
  4. data/CONTRIBUTING.md +2 -2
  5. data/README.md +4 -1
  6. data/Rakefile +2 -2
  7. data/bin/rubex +4 -5
  8. data/lib/rubex.rb +4 -4
  9. data/lib/rubex/ast.rb +4 -1
  10. data/lib/rubex/ast/expression.rb +22 -1191
  11. data/lib/rubex/ast/expression/actual_arg_list.rb +40 -0
  12. data/lib/rubex/ast/expression/analysed_element_ref.rb +26 -0
  13. data/lib/rubex/ast/expression/analysed_element_ref/c_var_element_ref.rb +30 -0
  14. data/lib/rubex/ast/expression/analysed_element_ref/ruby_object_element_ref.rb +42 -0
  15. data/lib/rubex/ast/expression/arg_declaration.rb +43 -0
  16. data/lib/rubex/ast/expression/binary.rb +57 -0
  17. data/lib/rubex/ast/expression/binary/binary_boolean.rb +23 -0
  18. data/lib/rubex/ast/expression/binary/binary_boolean_special_op.rb +20 -0
  19. data/lib/rubex/ast/expression/binary/empty_classes.rb +62 -0
  20. data/lib/rubex/ast/expression/block_given.rb +15 -0
  21. data/lib/rubex/ast/expression/coerce_object.rb +15 -0
  22. data/lib/rubex/ast/expression/command_call.rb +74 -0
  23. data/lib/rubex/ast/expression/command_call/struct_or_union_member_call.rb +38 -0
  24. data/lib/rubex/ast/expression/element_ref.rb +64 -0
  25. data/lib/rubex/ast/expression/empty.rb +13 -0
  26. data/lib/rubex/ast/expression/from_ruby_object.rb +20 -0
  27. data/lib/rubex/ast/expression/func_ptr_arg_declaration.rb +21 -0
  28. data/lib/rubex/ast/expression/func_ptr_internal_arg_declaration.rb +13 -0
  29. data/lib/rubex/ast/expression/literal.rb +30 -0
  30. data/lib/rubex/ast/expression/literal/array_lit.rb +51 -0
  31. data/lib/rubex/ast/expression/literal/c_null.rb +15 -0
  32. data/lib/rubex/ast/expression/literal/char.rb +36 -0
  33. data/lib/rubex/ast/expression/literal/double.rb +14 -0
  34. data/lib/rubex/ast/expression/literal/false.rb +33 -0
  35. data/lib/rubex/ast/expression/literal/hash_lit.rb +45 -0
  36. data/lib/rubex/ast/expression/literal/int.rb +14 -0
  37. data/lib/rubex/ast/expression/literal/nil.rb +14 -0
  38. data/lib/rubex/ast/expression/literal/ruby_symbol.rb +22 -0
  39. data/lib/rubex/ast/expression/literal/string_lit.rb +45 -0
  40. data/lib/rubex/ast/expression/literal/true.rb +29 -0
  41. data/lib/rubex/ast/expression/method_call.rb +52 -0
  42. data/lib/rubex/ast/expression/method_call/c_function_call.rb +40 -0
  43. data/lib/rubex/ast/expression/method_call/ruby_method_call.rb +83 -0
  44. data/lib/rubex/ast/expression/name.rb +127 -0
  45. data/lib/rubex/ast/expression/ruby_constant.rb +25 -0
  46. data/lib/rubex/ast/expression/ruby_object_element_ref/ruby_array_element_ref.rb +20 -0
  47. data/lib/rubex/ast/expression/ruby_object_element_ref/ruby_hash_element_ref.rb +22 -0
  48. data/lib/rubex/ast/expression/self.rb +15 -0
  49. data/lib/rubex/ast/expression/size_of.rb +22 -0
  50. data/lib/rubex/ast/expression/struct_or_union_member_call/element_ref_member_call.rb +23 -0
  51. data/lib/rubex/ast/expression/to_ruby_object.rb +21 -0
  52. data/lib/rubex/ast/expression/typecast.rb +20 -0
  53. data/lib/rubex/ast/expression/typecast_to.rb +10 -0
  54. data/lib/rubex/ast/expression/unary.rb +37 -0
  55. data/lib/rubex/ast/expression/unary_base.rb +24 -0
  56. data/lib/rubex/ast/expression/unary_base/ampersand.rb +16 -0
  57. data/lib/rubex/ast/expression/unary_base/unary_bit_not.rb +18 -0
  58. data/lib/rubex/ast/expression/unary_base/unary_not.rb +18 -0
  59. data/lib/rubex/ast/expression/unary_base/unary_sub.rb +18 -0
  60. data/lib/rubex/ast/node.rb +111 -111
  61. data/lib/rubex/ast/statement.rb +9 -1160
  62. data/lib/rubex/ast/statement/alias.rb +43 -0
  63. data/lib/rubex/ast/statement/argument_list.rb +59 -0
  64. data/lib/rubex/ast/statement/assign.rb +35 -0
  65. data/lib/rubex/ast/statement/begin_block.rb +14 -0
  66. data/lib/rubex/ast/statement/begin_block/begin.rb +202 -0
  67. data/lib/rubex/ast/statement/begin_block/else.rb +21 -0
  68. data/lib/rubex/ast/statement/begin_block/ensure.rb +21 -0
  69. data/lib/rubex/ast/statement/begin_block/rescue.rb +34 -0
  70. data/lib/rubex/ast/statement/break.rb +18 -0
  71. data/lib/rubex/ast/statement/c_array_decl.rb +49 -0
  72. data/lib/rubex/ast/statement/c_base_type.rb +26 -0
  73. data/lib/rubex/ast/statement/c_function_decl.rb +30 -0
  74. data/lib/rubex/ast/statement/c_ptr_decl.rb +52 -0
  75. data/lib/rubex/ast/statement/c_ptr_decl/c_ptr_func_decl.rb +25 -0
  76. data/lib/rubex/ast/statement/c_struct_or_union_def.rb +49 -0
  77. data/lib/rubex/ast/statement/expression.rb +26 -0
  78. data/lib/rubex/ast/statement/for.rb +73 -0
  79. data/lib/rubex/ast/statement/forward_decl.rb +31 -0
  80. data/lib/rubex/ast/statement/if_block.rb +64 -0
  81. data/lib/rubex/ast/statement/if_block/else.rb +30 -0
  82. data/lib/rubex/ast/statement/if_block/elsif.rb +22 -0
  83. data/lib/rubex/ast/statement/if_block/helper.rb +38 -0
  84. data/lib/rubex/ast/statement/print.rb +49 -0
  85. data/lib/rubex/ast/statement/raise.rb +66 -0
  86. data/lib/rubex/ast/statement/return.rb +45 -0
  87. data/lib/rubex/ast/statement/var_decl.rb +49 -0
  88. data/lib/rubex/ast/statement/while.rb +34 -0
  89. data/lib/rubex/ast/statement/yield.rb +41 -0
  90. data/lib/rubex/ast/top_statement.rb +1 -815
  91. data/lib/rubex/ast/top_statement/c_bindings.rb +145 -0
  92. data/lib/rubex/ast/top_statement/klass.rb +125 -0
  93. data/lib/rubex/ast/top_statement/klass/attached_klass.rb +417 -0
  94. data/lib/rubex/ast/top_statement/method_def.rb +110 -0
  95. data/lib/rubex/ast/top_statement/method_def/c_function_def.rb +26 -0
  96. data/lib/rubex/ast/top_statement/method_def/ruby_method_def.rb +33 -0
  97. data/lib/rubex/cli.rb +26 -0
  98. data/lib/rubex/code_writer.rb +1 -1
  99. data/lib/rubex/compiler.rb +49 -28
  100. data/lib/rubex/compiler_config.rb +4 -2
  101. data/lib/rubex/constants.rb +71 -71
  102. data/lib/rubex/data_type.rb +9 -675
  103. data/lib/rubex/data_type/c_array.rb +33 -0
  104. data/lib/rubex/data_type/c_function.rb +23 -0
  105. data/lib/rubex/data_type/c_ptr.rb +71 -0
  106. data/lib/rubex/data_type/c_str.rb +23 -0
  107. data/lib/rubex/data_type/c_struct_or_union.rb +23 -0
  108. data/lib/rubex/data_type/char.rb +30 -0
  109. data/lib/rubex/data_type/f_32.rb +38 -0
  110. data/lib/rubex/data_type/f_64.rb +38 -0
  111. data/lib/rubex/data_type/int.rb +32 -0
  112. data/lib/rubex/data_type/int/c_boolean.rb +13 -0
  113. data/lib/rubex/data_type/int_16.rb +32 -0
  114. data/lib/rubex/data_type/int_32.rb +32 -0
  115. data/lib/rubex/data_type/int_64.rb +36 -0
  116. data/lib/rubex/data_type/int_8.rb +33 -0
  117. data/lib/rubex/data_type/l_int.rb +38 -0
  118. data/lib/rubex/data_type/l_l_int.rb +26 -0
  119. data/lib/rubex/data_type/ruby_method.rb +22 -0
  120. data/lib/rubex/data_type/ruby_object.rb +19 -0
  121. data/lib/rubex/data_type/ruby_object/boolean.rb +11 -0
  122. data/lib/rubex/data_type/ruby_object/boolean/false_type.rb +5 -0
  123. data/lib/rubex/data_type/ruby_object/boolean/true_type.rb +5 -0
  124. data/lib/rubex/data_type/ruby_object/nil_type.rb +9 -0
  125. data/lib/rubex/data_type/ruby_object/ruby_array.rb +10 -0
  126. data/lib/rubex/data_type/ruby_object/ruby_constant.rb +18 -0
  127. data/lib/rubex/data_type/ruby_object/ruby_constant/ruby_class.rb +18 -0
  128. data/lib/rubex/data_type/ruby_object/ruby_hash.rb +9 -0
  129. data/lib/rubex/data_type/ruby_object/ruby_string.rb +10 -0
  130. data/lib/rubex/data_type/ruby_object/ruby_symbol.rb +10 -0
  131. data/lib/rubex/data_type/type_def.rb +34 -0
  132. data/lib/rubex/data_type/u_char.rb +27 -0
  133. data/lib/rubex/data_type/u_int.rb +32 -0
  134. data/lib/rubex/data_type/u_int_16.rb +22 -0
  135. data/lib/rubex/data_type/u_int_32.rb +22 -0
  136. data/lib/rubex/data_type/u_int_64.rb +26 -0
  137. data/lib/rubex/data_type/u_int_8.rb +22 -0
  138. data/lib/rubex/data_type/u_l_int.rb +36 -0
  139. data/lib/rubex/data_type/u_l_int/size_t.rb +10 -0
  140. data/lib/rubex/data_type/u_l_l_int.rb +26 -0
  141. data/lib/rubex/data_type/void.rb +15 -0
  142. data/lib/rubex/data_type_helpers/float_helpers.rb +8 -0
  143. data/lib/rubex/data_type_helpers/helpers.rb +48 -0
  144. data/lib/rubex/data_type_helpers/int_helpers.rb +10 -0
  145. data/lib/rubex/data_type_helpers/u_int_helpers.rb +11 -0
  146. data/lib/rubex/helpers.rb +35 -118
  147. data/lib/rubex/helpers/node_type_methods.rb +9 -0
  148. data/lib/rubex/helpers/writers.rb +79 -0
  149. data/lib/rubex/parser.racc +83 -34
  150. data/lib/rubex/parser.racc.rb +233 -184
  151. data/lib/rubex/version.rb +2 -2
  152. data/rubex.gemspec +2 -0
  153. data/spec/basic_ruby_method_spec.rb +1 -1
  154. data/spec/binding_ptr_args_spec.rb +2 -2
  155. data/spec/bitwise_operators_spec.rb +1 -1
  156. data/spec/blocks_spec.rb +2 -2
  157. data/spec/c_bindings_spec.rb +1 -1
  158. data/spec/c_constants_spec.rb +1 -1
  159. data/spec/c_function_ptrs_spec.rb +1 -1
  160. data/spec/c_functions_spec.rb +2 -2
  161. data/spec/c_struct_interface_spec.rb +1 -1
  162. data/spec/call_by_reference_spec.rb +2 -2
  163. data/spec/class_methods_spec.rb +2 -2
  164. data/spec/class_spec.rb +4 -4
  165. data/spec/cli_spec.rb +43 -0
  166. data/spec/comments_spec.rb +2 -2
  167. data/spec/default_args_spec.rb +21 -23
  168. data/spec/error_handling_spec.rb +1 -1
  169. data/spec/examples_spec.rb +4 -4
  170. data/spec/expressions_spec.rb +1 -1
  171. data/spec/fixtures/cli/cli.rubex +3 -0
  172. data/spec/fixtures/examples/array_to_hash.rubex +1 -1
  173. data/spec/fixtures/examples/rcsv.rubex +10 -6
  174. data/spec/fixtures/loops/loops.rubex +1 -1
  175. data/spec/fixtures/ruby_strings/string_blank_bm.rb +7 -5
  176. data/spec/fixtures/struct/struct.rubex +7 -2
  177. data/spec/fixtures/temp_allocation/temp_allocation.rubex +8 -0
  178. data/spec/if_else_spec.rb +3 -7
  179. data/spec/implicit_lib_include_spec.rb +1 -1
  180. data/spec/init_ruby_objects_with_literal_syntax_spec.rb +1 -1
  181. data/spec/loops_spec.rb +1 -1
  182. data/spec/recursion_spec.rb +18 -21
  183. data/spec/ruby_constant_method_calls_spec.rb +4 -4
  184. data/spec/ruby_operators_spec.rb +1 -1
  185. data/spec/ruby_raise_spec.rb +1 -1
  186. data/spec/ruby_strings_spec.rb +3 -3
  187. data/spec/ruby_symbols_spec.rb +1 -1
  188. data/spec/ruby_types_spec.rb +2 -2
  189. data/spec/spec_helper.rb +42 -10
  190. data/spec/statement_expression_spec.rb +3 -3
  191. data/spec/static_array_spec.rb +3 -3
  192. data/spec/string_literals_spec.rb +2 -2
  193. data/spec/struct_spec.rb +4 -4
  194. data/spec/temp_allocation_spec.rb +35 -0
  195. data/spec/typecasting_spec.rb +2 -2
  196. data/spec/var_declarions_spec.rb +2 -2
  197. metadata +168 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 23e2d866a0c76bc981182646dbb7c459eddc15c5
4
- data.tar.gz: f648dcf434fb3f57deba0f2950a47b15cef095e7
2
+ SHA256:
3
+ metadata.gz: 742568f609bbfd393f0262b1f8b79089a3e22007053e72714bbb8cc256fd5066
4
+ data.tar.gz: 7bd08df3a97cdf480bdb4fa5b34ef37553678f97cbd19f53027296148724c66a
5
5
  SHA512:
6
- metadata.gz: 05ae4e8cadf51c767c005cb03f2e0bf3b164903ad39d371560b5388f99ca9036cf2aaf21d15e10d3f732ed43bc2b951ec87c0283917a3404704225304a7b52ef
7
- data.tar.gz: 34236b528e312e5b0617cc0d5a6b3d76a29215fb244b11294850baa0c65189c090640bdbeeaa5491102ee050a689ef98fe73e873539d4493c1fdb254605296a1
6
+ metadata.gz: 32b17fb06897cf4ca018dd61ba27ee58b6f21d885b715c7ab13effd726175465379912c168c21ba0a7ba48ee69f244996fbb680ae5a33a78021cd07745b6473f
7
+ data.tar.gz: febfc14a8dabb0ab050d592f9d50cfeaaf068007cb0635104876cfa679710fd311e4e71d38f4f8cf3019a6ef78e231fa4638381803899e3f4ee499f19312d41c
data/.gitignore CHANGED
@@ -43,8 +43,8 @@ build-iPhoneSimulator/
43
43
  # for a library or gem, you might want to ignore these files since the code is
44
44
  # intended to run in multiple environments; otherwise, check them in:
45
45
  Gemfile.lock
46
- # .ruby-version
47
- # .ruby-gemset
46
+ .ruby-version
47
+ .ruby-gemset
48
48
 
49
49
  # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
50
  .rvmrc
@@ -52,3 +52,4 @@ Gemfile.lock
52
52
  lib/rubex/parser.output
53
53
  lib/rubex/parser.tab.rb
54
54
  /.idea/
55
+ TAGS
@@ -2,13 +2,21 @@ language:
2
2
  ruby
3
3
 
4
4
  rvm:
5
- - '2.2'
6
5
  - '2.3.0'
7
6
  - '2.4.0'
7
+ - '2.5.0'
8
8
 
9
9
  script:
10
10
  - bundle exec rake spec
11
11
 
12
+ before_install:
13
+ - sudo apt-get -qq update
14
+ - sudo apt-get install -y libcsv3
15
+
12
16
  install:
13
17
  - gem install bundler
14
18
  - bundle install
19
+
20
+ os:
21
+ - linux
22
+
@@ -46,7 +46,7 @@ When writing the `<=>` operator under Rubex::DataType classes, I have been force
46
46
 
47
47
  This consists of a hash that looks like this:
48
48
  ```
49
- {
49
+ {
50
50
  dtype: ,
51
51
  variables: [{}]
52
52
  }
@@ -67,7 +67,7 @@ The `:variables` key maps to a value that is an Array of Hashes that contains a
67
67
 
68
68
  If Hash, it will look like this:
69
69
  ```
70
- {
70
+ {
71
71
  name:,
72
72
  return_ptr_level:,
73
73
  arg_list:
data/README.md CHANGED
@@ -9,6 +9,8 @@ Rubex keeps you happy even when writing C extensions.
9
9
  # Status
10
10
 
11
11
  [![Gem Version](https://badge.fury.io/rb/rubex.svg)](https://badge.fury.io/rb/rubex)
12
+ [![Open Source Helpers](https://www.codetriage.com/v0dro/rubex/badges/users.svg)](https://www.codetriage.com/v0dro/rubex)
13
+ [![Build Status](https://travis-ci.org/SciRuby/rubex.svg?branch=master)](https://travis-ci.org/SciRuby/rubex)
12
14
 
13
15
  # Table of Contents
14
16
 
@@ -116,6 +118,7 @@ Notice the only difference between the above Rubex code and Ruby is the specific
116
118
  Rubex also takes care of the initial setup and compilation of the C files, so all you need to do is execute a bunch of commands and your extension is up and running!
117
119
 
118
120
  # Installation
121
+ To build, requires Ruby version >= 2.3.0
119
122
 
120
123
  The gem as of now has not reached v0.1. However, you can try it out with:
121
124
  ```
@@ -155,4 +158,4 @@ See the [CONTRIBUTING](CONTRIBUTING.md) and the GitHub issue tracker for future
155
158
 
156
159
  * The Ruby Association (Japan) for providing the initial funding for this project through the Ruby Association Grant 2016.
157
160
  * Koichi Sasada (@ko1) and Kenta Murata (@mrkn) for their support and mentorship throughout this project.
158
- * Fukuoka Ruby Award 2017.
161
+ * Fukuoka Ruby Award 2017.
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'rspec/core/rake_task'
2
2
  require 'bundler/gem_tasks'
3
+ require 'oedipus_lex'
3
4
 
4
5
  $:.unshift File.expand_path("../lib", __FILE__)
5
6
 
@@ -15,7 +16,6 @@ end
15
16
 
16
17
  # -v -> verbose
17
18
  # -t -> with debugging output
18
-
19
+ task :default => :spec
19
20
  RSpec::Core::RakeTask.new(:spec)
20
-
21
21
  task :spec => :parser
data/bin/rubex CHANGED
@@ -1,10 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'rubex'
4
-
5
- file_name = ARGV[0]
6
- if File.exists? file_name
7
- file_name = Dir.pwd + "/#{file_name}"
4
+ if Rubex::Cli.all_tasks.keys.include?(ARGV[0]) || ARGV.empty?
5
+ Rubex::Cli.start
6
+ else
7
+ Rubex::Cli.start(["generate"] + ARGV)
8
8
  end
9
9
 
10
- Rubex::Compiler.compile file_name
@@ -1,12 +1,12 @@
1
1
  require 'forwardable'
2
-
3
- require 'rubex/error'
4
- require 'rubex/helpers'
5
- require 'rubex/code_writer'
6
2
  require 'rubex/data_type'
7
3
  require 'rubex/constants'
4
+ require 'rubex/error'
8
5
  require 'rubex/ast'
6
+ require 'rubex/helpers'
7
+ require 'rubex/code_writer'
9
8
  require 'rubex/symbol_table'
10
9
  require 'rubex/parser.racc.rb'
11
10
  require 'rubex/compiler_config'
12
11
  require 'rubex/compiler'
12
+ require 'rubex/cli'
@@ -1,4 +1,7 @@
1
- require 'rubex/ast/node'
1
+ require 'rubex/helpers'
2
2
  require 'rubex/ast/statement'
3
+ Dir['./lib/rubex/ast/statement/**/*.rb'].sort.each { |f| require f }
3
4
  require 'rubex/ast/expression'
5
+ Dir['./lib/rubex/ast/expression/**/*.rb'].sort.each { |f| require f }
4
6
  require 'rubex/ast/top_statement'
7
+ require 'rubex/ast/node'
@@ -2,26 +2,31 @@ module Rubex
2
2
  module AST
3
3
  module Expression
4
4
  class Base
5
+ attr_reader :type, :entry
5
6
  attr_accessor :typecast
6
7
 
7
8
  # In case an expr has to be of a certain type, like a string literal
8
9
  # assigned to a char*, this method will analyse the literal in context
9
10
  # to the target dtype.
10
11
  def analyse_for_target_type target_type, local_scope
11
- analyse_statement local_scope
12
+ analyse_types local_scope
12
13
  end
13
14
 
14
15
  # If the typecast exists, the typecast is made the overall type of
15
16
  # the expression.
16
- def analyse_statement local_scope
17
+ def analyse_types local_scope
17
18
  if @typecast
18
- @typecast.analyse_statement(local_scope)
19
+ @typecast.analyse_types(local_scope)
19
20
  @type = @typecast.type
20
21
  end
21
22
  end
22
23
 
23
24
  def expression?; true; end
24
25
 
26
+ def has_temp
27
+ @has_temp
28
+ end
29
+
25
30
  def c_code local_scope
26
31
  @typecast ? @typecast.c_code(local_scope) : ""
27
32
  end
@@ -50,1213 +55,39 @@ module Rubex
50
55
 
51
56
  def allocate_temps local_scope
52
57
  if @subexprs
53
- @subexprs.each { |expr| expr.allocate_temp(local_scope, expr.type) }
58
+ @subexprs.each { |expr| expr.allocate_temps(local_scope) }
54
59
  end
60
+ allocate_temp local_scope, @type
55
61
  end
56
62
 
57
63
  def release_temps local_scope
58
64
  if @subexprs
59
- @subexprs.each { |expr| expr.release_temp(local_scope) }
60
- end
61
- end
62
-
63
- def generate_evaluation_code code, local_scope
64
-
65
- end
66
-
67
- def generate_disposal_code code
68
-
69
- end
70
-
71
- def generate_assignment_code rhs, code, local_scope
72
-
73
- end
74
- end
75
-
76
- class Typecast < Base
77
- attr_reader :type
78
-
79
- def initialize dtype, ptr_level
80
- @dtype, @ptr_level = dtype, ptr_level
81
- end
82
-
83
- def analyse_statement local_scope
84
- @type = Rubex::Helpers.determine_dtype @dtype, @ptr_level
85
- end
86
-
87
- def c_code local_scope
88
- "(#{@type.to_s})"
89
- end
90
- end # class Typecast
91
-
92
- class SizeOf < Base
93
- attr_reader :type
94
-
95
- def initialize type, ptr_level
96
- @size_of_type = Helpers.determine_dtype type, ptr_level
97
- end
98
-
99
- def analyse_statement local_scope
100
- @type = DataType::ULInt.new
101
- super
102
- end
103
-
104
- def c_code local_scope
105
- "sizeof(#{@size_of_type})"
106
- end
107
- end # class SizeOf
108
-
109
- class Binary < Base
110
- include Rubex::Helpers::NodeTypeMethods
111
-
112
- attr_reader :operator
113
- attr_accessor :left, :right
114
- # Final return type of expression
115
- attr_accessor :type, :subexprs
116
-
117
- def initialize left, operator, right
118
- @left, @operator, @right = left, operator, right
119
- @@analyse_visited = []
120
- @subexprs = []
121
- end
122
-
123
- def analyse_statement local_scope
124
- analyse_left_and_right_nodes local_scope, self
125
- analyse_return_type local_scope, self
126
- super
127
- end
128
-
129
- def allocate_temps local_scope
130
- @subexprs.each do |expr|
131
- if expr.is_a?(Binary)
132
- expr.allocate_temps local_scope
133
- else
134
- expr.allocate_temp local_scope, expr.type
135
- end
65
+ @subexprs.each { |expr| expr.release_temps(local_scope) }
136
66
  end
67
+ release_temp local_scope
137
68
  end
138
69
 
139
- def generate_evaluation_code code, local_scope
140
- @left.generate_evaluation_code code, local_scope
141
- @right.generate_evaluation_code code, local_scope
142
- end
143
-
144
- def generate_disposal_code code
145
- @left.generate_disposal_code code
146
- @right.generate_disposal_code code
147
- end
148
-
149
- def c_code local_scope
150
- code = super
151
- code << "( "
152
- left_code = @left.c_code(local_scope)
153
- right_code = @right.c_code(local_scope)
154
- if type_of(@left).object? || type_of(@right).object?
155
- left_ruby_code = @left.type.to_ruby_object(left_code)
156
- right_ruby_code = @right.type.to_ruby_object(right_code)
157
-
158
- if ["&&", "||"].include?(@operator)
159
- code << Rubex::C_MACRO_INT2BOOL +
160
- "(RTEST(#{left_ruby_code}) #{@operator} RTEST(#{right_ruby_code}))"
161
- else
162
- code << "rb_funcall(#{left_ruby_code}, rb_intern(\"#{@operator}\") "
163
- code << ", 1, #{right_ruby_code})"
164
- end
165
- else
166
- code << "#{left_code} #{@operator} #{right_code}"
167
- end
168
- code << " )"
169
-
170
- code
171
- end
172
-
173
- def == other
174
- self.class == other.class && @type == other.type &&
175
- @left == other.left && @right == other.right &&
176
- @operator == other.operator
177
- end
178
-
179
- private
70
+ def generate_evaluation_code(code, local_scope); end
180
71
 
181
- def type_of expr
182
- t = expr.type
183
- return (t.c_function? ? t.type : t)
184
- end
185
-
186
- def analyse_left_and_right_nodes local_scope, tree
187
- if tree.respond_to?(:left)
188
- analyse_left_and_right_nodes local_scope, tree.left
189
-
190
- if !@@analyse_visited.include?(tree.left.object_id)
191
- if tree.right.type
192
- tree.left.analyse_for_target_type(tree.right.type, local_scope)
193
- else
194
- tree.left.analyse_statement(local_scope)
195
- end
196
- @subexprs << tree.left
197
- @@analyse_visited << tree.left.object_id
198
- end
199
-
200
- if !@@analyse_visited.include?(tree.right.object_id)
201
- if tree.left.type
202
- tree.right.analyse_for_target_type(tree.left.type, local_scope)
203
- else
204
- tree.right.analyse_statement(local_scope)
205
- end
206
- @subexprs << tree.right
207
- @@analyse_visited << tree.right.object_id
208
- end
209
-
210
- @@analyse_visited << tree.object_id
211
-
212
- analyse_left_and_right_nodes local_scope, tree.right
213
- end
214
- end
215
-
216
- def analyse_return_type local_scope, tree
217
- if tree.respond_to? :left
218
- analyse_return_type local_scope, tree.left
219
- analyse_return_type local_scope, tree.right
220
-
221
- if ['==', '<', '>', '<=', '>=', '||', '&&', '!='].include? tree.operator
222
- if type_of(tree.left).object? || type_of(tree.right).object?
223
- tree.type = Rubex::DataType::Boolean.new
224
- else
225
- tree.type = Rubex::DataType::CBoolean.new
226
- end
227
- else
228
- if tree.left.type.bool? || tree.right.type.bool?
229
- raise Rubex::TypeMismatchError, "Operation #{tree.operator} cannot"\
230
- "be performed between #{tree.left} and #{tree.right}"
231
- end
232
- tree.type = Rubex::Helpers.result_type_for(
233
- type_of(tree.left), type_of(tree.right))
234
- end
235
- end
236
- end
237
- end # class Binary
238
-
239
- class UnaryBase < Base
240
- def initialize expr
241
- @expr = expr
242
- end
243
-
244
- def analyse_statement local_scope
245
- @expr.analyse_statement local_scope
246
- @type = @expr.type
247
- @expr.allocate_temps local_scope
248
- @expr.allocate_temp local_scope, @type
249
- @expr.release_temps local_scope
250
- @expr.release_temp local_scope
251
- @expr = @expr.to_ruby_object if @type.object?
252
- end
253
-
254
- def generate_evaluation_code code, local_scope
255
- @expr.generate_evaluation_code code, local_scope
256
- end
257
- end
258
-
259
- class UnaryNot < UnaryBase
260
- attr_reader :type
261
-
262
- def c_code local_scope
263
- code = @expr.c_code(local_scope)
264
- if @type.object?
265
- "rb_funcall(#{code}, rb_intern(\"!\"), 0)"
266
- else
267
- "!#{code}"
268
- end
269
- end
270
- end
271
-
272
- class UnarySub < UnaryBase
273
- attr_reader :type
274
-
275
- def c_code local_scope
276
- code = @expr.c_code(local_scope)
277
- if @type.object?
278
- "rb_funcall(#{code}, rb_intern(\"-\"), 0)"
279
- else
280
- "-#{code}"
281
- end
282
- end
283
- end
284
-
285
- class Ampersand < UnaryBase
286
- attr_reader :type
287
-
288
- def analyse_statement local_scope
289
- @expr.analyse_statement local_scope
290
- @type = DataType::CPtr.new @expr.type
291
- end
292
-
293
- def c_code local_scope
294
- "&#{@expr.c_code(local_scope)}"
295
- end
296
- end
297
-
298
- class UnaryBitNot < UnaryBase
299
- attr_reader :type
300
-
301
- def c_code local_scope
302
- code = @expr.c_code(local_scope)
303
- if @type.object?
304
- "rb_funcall(#{code}, rb_intern(\"~\"), 0)"
305
- else
306
- "~#{code}"
307
- end
308
- end
309
- end
310
-
311
- class Unary < Base
312
- attr_reader :operator, :expr, :type
313
-
314
- OP_CLASS_MAP = {
315
- '&' => Ampersand,
316
- '-' => UnarySub,
317
- '!' => UnaryNot,
318
- '~' => UnaryBitNot
319
- }
320
-
321
- def initialize operator, expr
322
- @operator, @expr = operator, expr
323
- end
324
-
325
- def analyse_statement local_scope
326
- @expr = OP_CLASS_MAP[@operator].new(@expr)
327
- @expr.analyse_statement local_scope
328
- @type = @expr.type
329
- super
330
- end
331
-
332
- def generate_evaluation_code code, local_scope
333
- @expr.generate_evaluation_code code, local_scope
334
- end
335
-
336
- def c_code local_scope
337
- code = super
338
- code << @expr.c_code(local_scope)
339
- end
340
- end # class Unary
341
-
342
- class ElementRef < Base
343
- attr_reader :entry, :pos, :type, :name, :object_ptr
344
-
345
- def initialize name, pos
346
- @name, @pos = name, pos
347
- @subexprs = []
348
- end
349
-
350
- # FIXME: This method needs to be implemented for all exprs that are
351
- # possible LHS candidates.
352
- # def analyse_declaration rhs, local_scope
353
- # analyse_statement local_scope
354
- # @has_temp = false
355
- # end
356
-
357
- def analyse_statement local_scope, struct_scope=nil
358
- if struct_scope.nil?
359
- @entry = local_scope.find @name
360
- else
361
- @entry = struct_scope[@name]
362
- end
363
-
364
- @object_ptr = true if @entry.type.cptr? && @entry.type.type.object?
365
- @type = @entry.type.object? ? @entry.type : @entry.type.type
366
-
367
- if @type.object? && !@object_ptr
368
- @has_temp = true
369
- @pos.analyse_statement local_scope
370
- if !(@type.ruby_array?)
371
- @pos = @pos.to_ruby_object
372
- end
373
- @subexprs << @pos
374
- else
375
- @pos.analyse_statement local_scope
376
- end
377
- super(local_scope)
378
- end
379
-
380
- # This method will be called when [] ruby method or C array element
381
- # reference is called.
382
- # TODO: refactor this by creating separate classes for ruby object, object
383
- # ptr, c type.
384
- def generate_evaluation_code code, local_scope
385
- if @type.object? && !@object_ptr
386
- if @type.ruby_array?
387
- code << "#{@c_code} = RARRAY_AREF(#{@entry.c_name}, #{@pos.c_code(local_scope)});"
388
- elsif @type.ruby_hash?
389
- @pos.generate_evaluation_code code, local_scope
390
- code << "#{@c_code} = rb_hash_aref(#{@entry.c_name}, #{@pos.c_code(local_scope)});"
391
- else
392
- @pos.generate_evaluation_code code, local_scope
393
- code << "#{@c_code} = rb_funcall(#{@entry.c_name}, rb_intern(\"[]\"), 1, "
394
- code << "#{@pos.c_code(local_scope)});"
395
- end
396
- code.nl
397
- @pos.generate_disposal_code code
398
- else
399
- @pos.generate_evaluation_code code, local_scope
400
- @c_code = "#{@entry.c_name}[#{@pos.c_code(local_scope)}]"
401
- end
402
- end
403
-
404
- def generate_disposal_code code
405
- if @type.object? && !@object_ptr
72
+ def generate_disposal_code(code)
73
+ if @has_temp
406
74
  code << "#{@c_code} = 0;"
407
75
  code.nl
408
76
  end
409
77
  end
410
78
 
411
- # This method will be called when []= ruby method or C array assignment
412
- # takes place.
413
- def generate_assignment_code rhs, code, local_scope
414
- if @type.object? && !@object_ptr
415
- @pos.generate_evaluation_code code, local_scope
416
- if @type.ruby_hash?
417
- code << "rb_hash_aset(#{@entry.c_name}, #{@pos.c_code(local_scope)}, #{rhs.c_code(local_scope)});"
418
- else
419
- code << "rb_funcall(#{@entry.c_name}, rb_intern(\"[]=\"), 2, "
420
- code << "#{@pos.c_code(local_scope)}, #{rhs.c_code(local_scope)});"
421
- end
422
- @pos.generate_disposal_code code
423
- else
424
- code << "#{@entry.c_name}[#{@pos.c_code(local_scope)}] = "
425
- code << "#{rhs.c_code(local_scope)};"
426
- end
427
- code.nl
428
- end
429
-
430
- # FIXME: This is jugaad. Change.
431
- def generate_element_ref_code expr, code, local_scope
432
- if !@object_ptr
433
- @pos.generate_evaluation_code code, local_scope
434
- str = "#{@c_code} = rb_funcall(#{expr.c_code(local_scope)}."
435
- str << "#{@entry.c_name}, rb_intern(\"[]\"), 1, "
436
- str << "#{@pos.c_code(local_scope)});"
437
- code << str
438
- code.nl
439
- @pos.generate_disposal_code code
440
- else
441
- generate_evaluation_code code, local_scope
442
- end
443
- end
444
-
445
- def c_code local_scope
446
- code = super
447
- code << @c_code
448
- code
449
- end
450
- end # class ElementRef
451
-
452
- class Self < Base
453
- def c_code local_scope
454
- local_scope.self_name
455
- end
456
-
457
- def type
458
- Rubex::DataType::RubyObject.new
459
- end
460
- end # class Self
461
-
462
- class RubyConstant < Base
463
- include Rubex::AST::Expression
464
- attr_reader :name, :entry, :type
465
-
466
- def initialize name
467
- @name = name
468
- end
469
-
470
- def analyse_statement local_scope
471
- @type = Rubex::DataType::RubyConstant.new @name
472
- c_name = Rubex::DEFAULT_CLASS_MAPPINGS[@name]
473
- @entry = Rubex::SymbolTable::Entry.new name, c_name, @type, nil
474
- end
475
-
476
- def c_code local_scope
477
- if @entry.c_name # built-in constant.
478
- @entry.c_name
479
- else
480
- "rb_const_get(CLASS_OF(#{local_scope.self_name}), rb_intern(\"#{@entry.name}\"))"
481
- end
482
- end
483
- end # class RubyConstant
484
-
485
- # Singular name node with no sub expressions.
486
- class Name < Base
487
- attr_reader :name, :entry, :type
488
-
489
- def initialize name
490
- @name = name
491
- end
492
-
493
- # Used when the node is a LHS of an assign statement.
494
- def analyse_declaration rhs, local_scope
495
- @entry = local_scope.find @name
496
- unless @entry
497
- local_scope.add_ruby_obj(name: @name,
498
- c_name: Rubex::VAR_PREFIX + @name, value: @rhs)
499
- @entry = local_scope[@name]
500
- end
501
- @type = @entry.type
502
- end
503
-
504
- def analyse_for_target_type target_type, local_scope
505
- @entry = local_scope.find @name
506
-
507
- if @entry && @entry.type.c_function? && target_type.c_function_ptr?
508
- @type = @entry.type
509
- else
510
- analyse_statement local_scope
511
- end
512
- end
513
-
514
- # Analyse a Name node. This can either be a variable name or a method call
515
- # without parenthesis. Code in this method that creates a CommandCall
516
- # node primarily exists because in Ruby methods without arguments can
517
- # be called without parentheses. These names can potentially be Ruby
518
- # methods that are not visible to Rubex, but are present in the Ruby
519
- # run time.
520
- def analyse_statement local_scope
521
- @entry = local_scope.find @name
522
- # FIXME: Figure out a way to perform compile time checking of expressions
523
- # to see if the said Ruby methods are actually present in the Ruby
524
- # runtime. Maybe read symbols in the Ruby interpreter and load them
525
- # as a pre-compilation step?
526
-
527
- # If entry is not present, assume its a Ruby method call to some method
528
- # outside of the current Rubex scope or a Ruby constant.
529
- if !@entry
530
- # Check if first letter is a capital to check for Ruby constant.
531
- if @name[0].match /[A-Z]/
532
- @name = Expression::RubyConstant.new @name
533
- @name.analyse_statement local_scope
534
- @entry = @name.entry
535
- else # extern Ruby method
536
- @entry = local_scope.add_ruby_method(
537
- name: @name,
538
- c_name: @name,
539
- extern: true,
540
- scope: nil,
541
- arg_list: [])
542
- end
543
- end
544
- # If the entry is a RubyMethod, it should be interpreted as a command
545
- # call. So, make the @name a CommandCall Node.
546
- if @entry.type.ruby_method? #|| @entry.type.c_function?
547
- @name = Rubex::AST::Expression::CommandCall.new(
548
- Expression::Self.new, @name, [])
549
- @name.analyse_statement local_scope
550
- end
551
-
552
- if @entry.type.alias_type? || @entry.type.ruby_method? ||
553
- @entry.type.c_function?
554
- @type = @entry.type.type
555
- else
556
- @type = @entry.type
557
- end
558
- super
559
- end
560
-
561
- def generate_evaluation_code code, local_scope
562
- if @name.respond_to? :generate_evaluation_code
563
- @name.generate_evaluation_code code, local_scope
564
- end
565
- end
566
-
567
- def generate_disposal_code code
568
- if @name.respond_to? :generate_disposal_code
569
- @name.generate_disposal_code code
570
- end
571
- end
572
-
573
- def generate_assignment_code rhs, code, local_scope
574
- code << "#{self.c_code(local_scope)} = #{rhs.c_code(local_scope)};"
575
- code.nl
576
- rhs.generate_disposal_code code
577
- end
578
-
579
- def c_code local_scope
580
- code = super
581
- if @name.is_a?(Rubex::AST::Expression::Base)
582
- code << @name.c_code(local_scope)
583
- else
584
- code << @entry.c_name
585
- end
586
-
587
- code
588
- end
589
- end # class Name
590
-
591
- class MethodCall < Base
592
- attr_reader :method_name, :type
593
-
594
- def initialize method_name, invoker, arg_list
595
- @method_name, @invoker, @arg_list = method_name, invoker, arg_list
596
- end
597
-
598
- # Analyse a method call. If the method that is being called is defined
599
- # in a class in a Rubex file, it can easily be interpreted as a Ruby
600
- # method. However, in case it is not, a new symtab entry will be created
601
- # which will mark the method as 'extern' so that future calls to that
602
- # same method can be simply pulled from the symtab.
603
- # local_scope is the local method scope.
604
- def analyse_statement local_scope
605
- entry = local_scope.find(@method_name)
606
- if !entry
607
- entry = local_scope.add_ruby_method(
608
- name: @method_name,
609
- c_name: @method_name,
610
- extern: true,
611
- arg_list: @arg_list,
612
- scope: nil)
613
- end
614
-
615
- if method_not_within_scope? local_scope
616
- raise Rubex::NoMethodError, "Cannot call #{@name} from this method."
617
- end
618
-
619
- # FIXME: Print a warning during compilation if a symbol is being
620
- # interpreted as a Ruby method call due it not being found in the
621
- # symbol table.
622
-
623
- # A symtab entry for a predeclared extern C func.
624
- if entry && entry.type.base_type.c_function?
625
- @type = entry.type.base_type
626
- # All C functions have compulsory last arg as self. This does not
627
- # apply to extern functions as they are usually not made for accepting
628
- # a VALUE last arg.
629
- @arg_list << Expression::Self.new if !entry.extern?
630
- type_check_arg_types entry
631
- else
632
- @type = Rubex::DataType::RubyObject.new
633
- end
634
-
635
- if entry.type.ruby_method? && !entry.extern? && @arg_list.size > 0
636
- @arg_list_var = entry.c_name + Rubex::ACTUAL_ARGS_SUFFIX
637
-
638
- args_size = entry.type.arg_list&.size || 0
639
- local_scope.add_carray(name: @arg_list_var, c_name: @arg_list_var,
640
- dimension: Literal::Int.new("#{args_size}"),
641
- type: Rubex::DataType::RubyObject.new)
642
- end
643
- super
644
- end
645
-
646
- def generate_evaluation_code code, local_scope
647
- end
648
-
649
- def generate_disposal_code code
650
- end
651
-
652
- def c_code local_scope
653
- code = super
654
- entry = local_scope.find(@method_name)
655
- if entry.type.ruby_method?
656
- code << code_for_ruby_method_call(local_scope)
657
- else
658
- code << code_for_c_method_call(local_scope, entry)
659
- end
660
-
661
- code
662
- end
663
-
664
- private
665
-
666
- def type_check_arg_types entry
667
- @arg_list.map!.with_index do |arg, idx|
668
- Helpers.to_lhs_type(entry.type.base_type.arg_list[idx], arg)
669
- end
670
- end
671
-
672
- # Checks if method being called is of the same type of the caller. For
673
- # example, only instance methods can call instance methods and only
674
- # class methods can call class methods. C functions are accessible from
675
- # both instance methods and class methods.
676
- #
677
- # Since there is no way to determine whether methods outside the scope
678
- # of the compiled Rubex file are singletons or not, Rubex will assume
679
- # that they belong to the correct scope and will compile a call to those
680
- # methods anyway. Error, if any, will be caught only at runtime.
681
- def method_not_within_scope? local_scope
682
- entry = local_scope.find @method_name
683
- caller_entry = local_scope.find local_scope.name
684
- if ( caller_entry.singleton? && entry.singleton?) ||
685
- (!caller_entry.singleton? && !entry.singleton?) ||
686
- entry.c_function?
687
- false
688
- else
689
- true
690
- end
691
- end
692
-
693
- def code_for_c_method_call local_scope, entry
694
- str = "#{entry.c_name}("
695
- str << @arg_list.map { |a| a.c_code(local_scope) }.join(",")
696
- str << ")"
697
- str
698
- end
699
-
700
- def code_for_ruby_method_call local_scope
701
- entry = local_scope.find @method_name
702
- str = ""
703
- if entry.extern?
704
- str << "rb_funcall(#{@invoker.c_code(local_scope)}, "
705
- str << "rb_intern(\"#{@method_name}\"), "
706
- str << "#{@arg_list.size}"
707
- @arg_list.each do |arg|
708
- str << " ,#{arg.type.to_ruby_object(arg.c_code(local_scope))}"
709
- end
710
- str << ", NULL" if @arg_list.empty?
711
- str << ")"
712
- else
713
- str << populate_method_args_into_value_array(local_scope)
714
- str << actual_ruby_method_call(local_scope, entry)
715
- end
716
- str
717
- end
718
-
719
- def actual_ruby_method_call local_scope, entry
720
- str = "#{entry.c_name}(#{@arg_list.size}, #{@arg_list_var || "NULL"},"
721
- str << "#{local_scope.self_name})"
722
- end
723
-
724
- def populate_method_args_into_value_array local_scope
725
- str = ""
726
- @arg_list.each_with_index do |arg, idx|
727
- str = "#{@arg_list_var}[#{idx}] = "
728
- str << "#{arg.type.to_ruby_object(arg.c_code(local_scope))}"
729
- str << ";\n"
730
- end
731
-
732
- str
733
- end
734
- end # class MethodCall
735
-
736
- class CommandCall < Base
737
- attr_reader :expr, :command, :arg_list, :type
738
-
739
- def initialize expr, command, arg_list
740
- @expr, @command, @arg_list = expr, command, arg_list
741
- @subexprs = []
742
- end
743
-
744
- # Analyse the command call. If the @command is found in the symbol table,
745
- # it is either a struct member or a method call. If not found, it is
746
- # assumed to be a Ruby method call and passed on the MethodCall node
747
- # where it is interpreted likewise. The upside is that Rubex can call
748
- # arbitrary Ruby methods that are defined in external Ruby scripts and
749
- # not visible to Rubex at compile time. The downside is that errors with
750
- # such methods will be visible to the programmer only during runtime.
751
- def analyse_statement local_scope
752
- @arg_list.each do |arg|
753
- arg.analyse_statement local_scope
754
- @subexprs << arg
755
- end
756
- # Case for implicit 'self' when a method in the class itself is being called.
757
- if @expr.nil?
758
- entry = local_scope.find(@command)
759
- @expr = Expression::Self.new if entry && !entry.extern?
760
- else
761
- @expr.analyse_statement(local_scope)
762
- @expr.allocate_temps local_scope
763
- @expr.allocate_temp local_scope, @expr.type
764
- end
765
- analyse_command_type local_scope
766
- super
767
- end
768
-
769
- # FIXME: refactor this method (or class). Too many ifs. Too much jagaad.
770
- def generate_evaluation_code code, local_scope
771
- @c_code = ""
772
- @arg_list.each do |arg|
773
- arg.generate_evaluation_code code, local_scope
774
- end
775
- @expr.generate_evaluation_code(code, local_scope) if @expr
776
-
777
- if @expr && @type.object? && @command.is_a?(Rubex::AST::Expression::ElementRef) &&
778
- !@command.object_ptr
779
- @command.generate_element_ref_code @expr, code, local_scope
780
- @c_code << "#{@command.c_code(local_scope)}"
781
- else
782
- @command.generate_evaluation_code code, local_scope
783
- # Interpreted as a method call
784
- if @command.is_a? Rubex::AST::Expression::MethodCall
785
- @c_code << @command.c_code(local_scope)
786
- else # interpreted as referencing the contents of a struct
787
- op = @expr.type.cptr? ? "->" : "."
788
-
789
- @c_code << "#{@expr.c_code(local_scope)}#{op}#{@command.c_code(local_scope)}"
790
- end
791
- end
792
- end
79
+ def generate_assignment_code(rhs, code, local_scope); end
793
80
 
794
- def generate_disposal_code code
795
- @expr.generate_disposal_code(code) if @expr
796
- # @command.generate_disposal_code code
797
- @arg_list.each do |arg|
798
- arg.generate_disposal_code code
81
+ def generate_and_dispose_subexprs(code, local_scope, &block)
82
+ @subexprs.each do |s|
83
+ s.generate_evaluation_code code, local_scope
799
84
  end
800
- end
801
-
802
- def generate_assignment_code rhs, code, local_scope
803
- generate_evaluation_code code, local_scope
804
- code << "#{self.c_code(local_scope)} = #{rhs.c_code(local_scope)};"
805
- code.nl
806
- end
807
-
808
- def c_code local_scope
809
- code = super
810
- code << @c_code
811
- code
812
- end
813
-
814
- private
815
-
816
- def analyse_command_type local_scope
817
- if @expr && ((@expr.type.cptr? && @expr.type.type.struct_or_union?) ||
818
- (@expr.type.struct_or_union?))
819
- scope = @expr.type.base_type.scope
820
- if @command.is_a? String
821
- @command = Expression::Name.new @command
822
- @command.analyse_statement scope
823
- end
824
-
825
- if !scope.has_entry?(@command.name)
826
- raise "Entry #{@command.name} does not exist in #{@expr}."
827
- end
828
-
829
- if @command.is_a? Rubex::AST::Expression::ElementRef
830
- @command.analyse_statement local_scope, scope
831
- end
832
- else
833
- @command = Expression::MethodCall.new @command, @expr, @arg_list
834
- @command.analyse_statement local_scope
85
+ block.call if block_given?
86
+ @subexprs.each do |s|
87
+ s.generate_disposal_code code
835
88
  end
836
- @type = @command.type
837
- @command.allocate_temps local_scope
838
- @command.allocate_temp local_scope, @type
839
- @command.release_temps local_scope
840
- @command.release_temp local_scope
841
89
  end
842
- end # class CommandCall
843
-
844
-
845
- class ArgDeclaration < Base
846
- attr_reader :entry, :type
847
-
848
- # data_hash - a Hash containing data about the variable.
849
- def initialize data_hash
850
- @data_hash = data_hash
851
- end
852
-
853
- def analyse_statement local_scope, inside_func_ptr: false, extern: false
854
- # FIXME: Support array of function pointers and array in arguments.
855
- var = @data_hash[:variables][0]
856
- dtype = @data_hash[:dtype]
857
- ident = var[:ident]
858
- ptr_level = var[:ptr_level]
859
- value = var[:value]
860
-
861
- if ident.is_a?(Hash) # function pointer
862
- cfunc_return_type = Helpers.determine_dtype(dtype,
863
- ident[:return_ptr_level])
864
- arg_list = ident[:arg_list].analyse_statement(local_scope,
865
- inside_func_ptr: true)
866
- ptr_level = "*" if ptr_level.empty?
867
-
868
- if inside_func_ptr
869
- name, c_name = nil, nil
870
- else
871
- name = ident[:name]
872
- c_name = Rubex::ARG_PREFIX + name
873
- end
874
-
875
- @type = Helpers.determine_dtype(
876
- DataType::CFunction.new(name, c_name, arg_list, cfunc_return_type, nil),
877
- ptr_level)
878
- else
879
- if !inside_func_ptr
880
- name, c_name = ident, Rubex::ARG_PREFIX + ident
881
- end
882
- @type = Helpers.determine_dtype(dtype, ptr_level)
883
- end
884
-
885
- value.analyse_statement(local_scope) if value
886
-
887
- if !extern && !inside_func_ptr
888
- @entry = local_scope.add_arg(name: name, c_name: c_name, type: @type,
889
- value: value)
890
- end
891
- end # def analyse_statement
892
- end # class ArgDeclaration
893
-
894
- class CoerceObject < Base
895
- attr_reader :expr
896
-
897
- extend Forwardable
898
-
899
- def_delegators :@expr, :generate_evaluation_code, :generate_disposal_code,
900
- :generate_assignment_code, :allocate_temp, :allocate_temps,
901
- :release_temp, :release_temps, :type
902
90
  end
903
-
904
- # Internal class to typecast from a C type to another C type.
905
- class TypecastTo < CoerceObject
906
- def initialize dtype
907
-
908
- end
909
- # TODO
910
- end
911
-
912
- # internal node for converting to ruby object.
913
- class ToRubyObject < CoerceObject
914
- attr_reader :type
915
-
916
- def initialize expr
917
- @expr = expr
918
- @type = Rubex::DataType::RubyObject.new
919
- end
920
-
921
- def c_code local_scope
922
- t = @expr.type
923
- t = (t.c_function? || t.alias_type?) ? t.type : t
924
- "#{t.to_ruby_object(@expr.c_code(local_scope))}"
925
- end
926
- end
927
-
928
- # internal node for converting from ruby object.
929
- class FromRubyObject < CoerceObject
930
- # expr - Expression to convert
931
- # from_node - LHS expression. Of type Rubex::AST::Expression
932
- def initialize expr, from_node
933
- @expr = expr
934
- @type = @expr.type
935
- @from_node = from_node
936
- end
937
-
938
- def c_code local_scope
939
- "#{@from_node.type.from_ruby_object(@expr.c_code(local_scope))}"
940
- end
941
- end
942
-
943
- class BlockGiven < Base
944
- attr_reader :type
945
-
946
- def analyse_statement local_scope
947
- @type = DataType::CBoolean.new
948
- end
949
-
950
- def c_code local_scope
951
- "rb_block_given_p()"
952
- end
953
- end
954
-
955
- # Internal node that denotes empty expression for a statement for example
956
- # the `return` for a C function with return type `void`.
957
- class Empty < Base
958
- attr_reader :type
959
-
960
- def analyse_statement local_scope
961
- @type = DataType::Void.new
962
- end
963
- end
964
-
965
- module Literal
966
- class Base < Rubex::AST::Expression::Base
967
- attr_reader :name, :type
968
-
969
- def initialize name
970
- @name = name
971
- end
972
-
973
- def c_code local_scope
974
- code = super
975
- code << @name
976
- end
977
-
978
- def c_name
979
- @name
980
- end
981
-
982
- def literal?; true; end
983
-
984
- def == other
985
- self.class == other.class && @name == other.name
986
- end
987
- end # class Base
988
-
989
- class ArrayLit < Literal::Base
990
- include Enumerable
991
-
992
- attr_accessor :c_array
993
-
994
- def each &block
995
- @array_list.each(&block)
996
- end
997
-
998
- def initialize array_list
999
- @array_list = array_list
1000
- @subexprs = []
1001
- end
1002
-
1003
- def analyse_statement local_scope
1004
- @has_temp = true
1005
- @type = DataType::RubyObject.new
1006
- @array_list.map! do |e|
1007
- e.analyse_statement local_scope
1008
- e = e.to_ruby_object
1009
- @subexprs << e
1010
- e
1011
- end
1012
- end
1013
-
1014
- def generate_evaluation_code code, local_scope
1015
- code << "#{@c_code} = rb_ary_new2(#{@array_list.size});"
1016
- code.nl
1017
- @array_list.each do |e|
1018
- code << "rb_ary_push(#{@c_code}, #{e.c_code(local_scope)});"
1019
- code.nl
1020
- end
1021
- end
1022
-
1023
- def generate_disposal_code code
1024
- code << "#{@c_code} = 0;"
1025
- code.nl
1026
- end
1027
-
1028
- def c_code local_scope
1029
- @c_code
1030
- end
1031
- end # class ArrayLit
1032
-
1033
- class HashLit < Literal::Base
1034
- def initialize key_val_pairs
1035
- @key_val_pairs = key_val_pairs
1036
- end
1037
-
1038
- def analyse_statement local_scope
1039
- @has_temp = true
1040
- @type = Rubex::DataType::RubyObject.new
1041
- @key_val_pairs.map! do |k, v|
1042
- k.analyse_for_target_type(@type, local_scope)
1043
- v.analyse_for_target_type(@type, local_scope)
1044
- [k.to_ruby_object, v.to_ruby_object]
1045
- end
1046
- end
1047
-
1048
- def generate_evaluation_code code, local_scope
1049
- code << "#{@c_code} = rb_hash_new();"
1050
- code.nl
1051
- @key_val_pairs.each do |k, v|
1052
- k.generate_evaluation_code(code, local_scope)
1053
- v.generate_evaluation_code(code, local_scope)
1054
-
1055
- code << "rb_hash_aset(#{@c_code}, #{k.c_code(local_scope)}, "
1056
- code << "#{v.c_code(local_scope)});"
1057
- code.nl
1058
-
1059
- k.generate_disposal_code code
1060
- v.generate_disposal_code code
1061
- code.nl
1062
- end
1063
- end
1064
-
1065
- def allocate_temps local_scope
1066
- @key_val_pairs.each do |k,v|
1067
- k.allocate_temp local_scope, k.type
1068
- v.allocate_temp local_scope, v.type
1069
- end
1070
- end
1071
-
1072
- def release_temps local_scope
1073
- @key_val_pairs.each do |k,v|
1074
- k.release_temp local_scope
1075
- v.release_temp local_scope
1076
- end
1077
- end
1078
-
1079
- def generate_disposal_code code
1080
- code << "#{@c_code} = 0;"
1081
- code.nl
1082
- end
1083
-
1084
- def c_code local_scope
1085
- @c_code
1086
- end
1087
- end
1088
-
1089
- class RubySymbol < Literal::Base
1090
- def initialize name
1091
- super(name[1..-1])
1092
- @type = Rubex::DataType::RubySymbol.new
1093
- end
1094
-
1095
- def generate_evaluation_code code, local_scope
1096
- @c_code = "ID2SYM(rb_intern(\"#{@name}\"))"
1097
- end
1098
-
1099
- def c_code local_scope
1100
- @c_code
1101
- end
1102
- end
1103
-
1104
- class Double < Literal::Base
1105
- def initialize name
1106
- super
1107
- @type = Rubex::DataType::F64.new
1108
- end
1109
- end
1110
-
1111
- class Int < Literal::Base
1112
- def initialize name
1113
- super
1114
- @type = Rubex::DataType::Int.new
1115
- end
1116
- end
1117
-
1118
- class StringLit < Literal::Base
1119
- def initialize name
1120
- super
1121
- end
1122
-
1123
- def analyse_for_target_type target_type, local_scope
1124
- if target_type.char_ptr?
1125
- @type = Rubex::DataType::CStr.new
1126
- elsif target_type.object?
1127
- @type = Rubex::DataType::RubyString.new
1128
- analyse_statement local_scope
1129
- else
1130
- raise Rubex::TypeError, "Cannot assign #{target_type} to string."
1131
- end
1132
- end
1133
-
1134
- def analyse_statement local_scope
1135
- @type = Rubex::DataType::RubyString.new unless @type
1136
- @has_temp = 1
1137
- end
1138
-
1139
- def generate_evaluation_code code, local_scope
1140
- if @type.cstr?
1141
- @c_code = "\"#{@name}\""
1142
- else
1143
- code << "#{@c_code} = rb_str_new2(\"#{@name}\");"
1144
- code.nl
1145
- end
1146
- end
1147
-
1148
- def generate_disposal_code code
1149
- if @type.object?
1150
- code << "#{@c_code} = 0;"
1151
- code.nl
1152
- end
1153
- end
1154
-
1155
- def c_code local_scope
1156
- @c_code
1157
- end
1158
- end # class StringLit
1159
-
1160
- class Char < Literal::Base
1161
- def initialize name
1162
- super
1163
- end
1164
-
1165
- def analyse_for_target_type target_type, local_scope
1166
- if target_type.char?
1167
- @type = Rubex::DataType::Char.new
1168
- elsif target_type.object?
1169
- @type = Rubex::DataType::RubyString.new
1170
- analyse_statement local_scope
1171
- else
1172
- raise Rubex::TypeError, "Cannot assign #{target_type} to string."
1173
- end
1174
- end
1175
-
1176
- def analyse_statement local_scope
1177
- @type = Rubex::DataType::RubyString.new unless @type
1178
- end
1179
-
1180
- def generate_evaluation_code code, local_scope
1181
- if @type.char?
1182
- @c_code = @name
1183
- else
1184
- @c_code = "rb_str_new2(\"#{@name[1]}\")"
1185
- end
1186
- end
1187
-
1188
- def c_code local_scope
1189
- @c_code
1190
- end
1191
- end # class Char
1192
-
1193
- class True < Literal::Base
1194
- def initialize name
1195
- super
1196
- end
1197
-
1198
- def analyse_for_target_type target_type, local_scope
1199
- if target_type.object?
1200
- @type = Rubex::DataType::TrueType.new
1201
- else
1202
- @type = Rubex::DataType::CBoolean.new
1203
- end
1204
- end
1205
-
1206
- def analyse_statement local_scope
1207
- @type = Rubex::DataType::TrueType.new
1208
- end
1209
-
1210
- def c_code local_scope
1211
- if @type.object?
1212
- @name
1213
- else
1214
- "1"
1215
- end
1216
- end
1217
- end # class True
1218
-
1219
- class False < Literal::Base
1220
- def initialize name
1221
- super
1222
- end
1223
-
1224
- def analyse_for_target_type target_type, local_scope
1225
- if target_type.object?
1226
- @type = Rubex::DataType::FalseType.new
1227
- else
1228
- @type = Rubex::DataType::CBoolean.new
1229
- end
1230
- end
1231
-
1232
- def analyse_statement local_scope
1233
- @type = Rubex::DataType::FalseType.new
1234
- end
1235
-
1236
- def c_code local_scope
1237
- if @type.object?
1238
- @name
1239
- else
1240
- "0"
1241
- end
1242
- end
1243
- end # class False
1244
-
1245
- class Nil < Literal::Base
1246
- def initialize name
1247
- super
1248
- @type = Rubex::DataType::NilType.new
1249
- end
1250
- end # class Nil
1251
-
1252
- class CNull < Literal::Base
1253
- def initialize name
1254
- # Rubex treats NULL's dtype as void*
1255
- super
1256
- @type = Rubex::DataType::CPtr.new(Rubex::DataType::Void.new)
1257
- end
1258
- end # class CNull
1259
- end # module Literal
1260
91
  end # module Expression
1261
92
  end # module AST
1262
93
  end # module Rubex