rubex 0.1 → 0.1.1

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