crystalizer 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. data/Changelog +27 -0
  2. data/README +79 -0
  3. data/Rakefile +24 -0
  4. data/TODO +14 -0
  5. data/VERSION +1 -0
  6. data/benchmarks/bench.rb +129 -0
  7. data/benchmarks/concretize_test.rb +26 -0
  8. data/benchmarks/extconf.rb +10 -0
  9. data/benchmarks/tak_rb.rb +7 -0
  10. data/benchmarks/tak_so.rb +7 -0
  11. data/benchmarks/tak_source.rb +16 -0
  12. data/bin/rb2cx +162 -0
  13. data/doc/eval2c.txt +246 -0
  14. data/doc/gen_html.rb +26 -0
  15. data/doc/html_template +10 -0
  16. data/doc/index.txt +169 -0
  17. data/doc/limitations.txt +529 -0
  18. data/doc/optimizations.txt +185 -0
  19. data/doc/rb2cx.txt +130 -0
  20. data/doc/style.css +27 -0
  21. data/lib/concretizer.rb +3 -0
  22. data/lib/ruby2cext/c_function.rb +617 -0
  23. data/lib/ruby2cext/common_node_comp.rb +1412 -0
  24. data/lib/ruby2cext/compiler.rb +311 -0
  25. data/lib/ruby2cext/concretize.rb +269 -0
  26. data/lib/ruby2cext/error.rb +15 -0
  27. data/lib/ruby2cext/eval2c.rb +126 -0
  28. data/lib/ruby2cext/parser.rb +36 -0
  29. data/lib/ruby2cext/plugin.rb +24 -0
  30. data/lib/ruby2cext/plugins/builtin_methods.rb +817 -0
  31. data/lib/ruby2cext/plugins/cache_call.rb +293 -0
  32. data/lib/ruby2cext/plugins/case_optimize.rb +102 -0
  33. data/lib/ruby2cext/plugins/const_cache.rb +36 -0
  34. data/lib/ruby2cext/plugins/direct_self_call.rb +70 -0
  35. data/lib/ruby2cext/plugins/inline_builtin.rb +797 -0
  36. data/lib/ruby2cext/plugins/inline_methods.rb +68 -0
  37. data/lib/ruby2cext/plugins/ivar_cache.rb +147 -0
  38. data/lib/ruby2cext/plugins/require_include.rb +69 -0
  39. data/lib/ruby2cext/plugins/util.rb +154 -0
  40. data/lib/ruby2cext/plugins/warnings.rb +121 -0
  41. data/lib/ruby2cext/scopes.rb +225 -0
  42. data/lib/ruby2cext/str_to_c_strlit.rb +12 -0
  43. data/lib/ruby2cext/tools.rb +80 -0
  44. data/lib/ruby2cext/version.rb +22 -0
  45. data/results +68 -0
  46. data/setup.rb +1585 -0
  47. data/stuff/builtin_methods.rb +69 -0
  48. data/stuff/builtin_methods_test.rb +37 -0
  49. data/test/bootstrap.rb +10 -0
  50. data/test/causes_crash_all_opts.rb +1165 -0
  51. data/test/eval2c/test_eval2c.rb +37 -0
  52. data/test/temp_17.rb +16 -0
  53. data/test/temp_18.rb +8 -0
  54. data/test/temp_19.rb +8 -0
  55. data/test/temp_2.rb +7 -0
  56. data/test/temp_20.rb +5 -0
  57. data/test/temp_21.rb +161 -0
  58. data/test/temp_22.rb +7 -0
  59. data/test/temp_23.rb +7 -0
  60. data/test/temp_24.rb +219 -0
  61. data/test/temp_25.rb +7 -0
  62. data/test/temp_26.rb +11 -0
  63. data/test/temp_27.rb +11 -0
  64. data/test/temp_28.rb +9 -0
  65. data/test/temp_29.rb +9 -0
  66. data/test/temp_3.rb +0 -0
  67. data/test/temp_30.rb +0 -0
  68. data/test/temp_31.rb +10 -0
  69. data/test/temp_32.rb +10 -0
  70. data/test/temp_33.rb +15 -0
  71. data/test/temp_34.rb +15 -0
  72. data/test/temp_35.rb +7 -0
  73. data/test/temp_36.rb +7 -0
  74. data/test/temp_37.rb +10 -0
  75. data/test/temp_38.rb +10 -0
  76. data/test/temp_39.rb +0 -0
  77. data/test/temp_4.rb +7 -0
  78. data/test/temp_40.rb +50 -0
  79. data/test/temp_41.rb +50 -0
  80. data/test/temp_42.rb +8 -0
  81. data/test/temp_43.rb +8 -0
  82. data/test/temp_44.rb +0 -0
  83. data/test/temp_48.rb +7 -0
  84. data/test/temp_49.rb +7 -0
  85. data/test/temp_5.rb +7 -0
  86. data/test/temp_59.rb +7 -0
  87. data/test/temp_6.rb +7 -0
  88. data/test/temp_60.rb +7 -0
  89. data/test/temp_68.rb +239 -0
  90. data/test/temp_7.rb +7 -0
  91. data/test/temp_70.rb +7 -0
  92. data/test/temp_71.rb +7 -0
  93. data/test/temp_72.rb +13 -0
  94. data/test/temp_73.rb +7 -0
  95. data/test/temp_74.rb +7 -0
  96. data/test/temp_76.rb +7 -0
  97. data/test/temp_77.rb +13 -0
  98. data/test/temp_79.rb +7 -0
  99. data/test/temp_8.rb +14 -0
  100. data/test/temp_81.rb +14 -0
  101. data/test/temp_83.rb +0 -0
  102. data/test/temp_84.rb +7 -0
  103. data/test/temp_85.rb +7 -0
  104. data/test/temp_86.rb +14 -0
  105. data/test/temp_87.rb +7 -0
  106. data/test/temp_88.rb +7 -0
  107. data/test/temp_89.rb +7 -0
  108. data/test/temp_9.rb +14 -0
  109. data/test/temp_90.rb +0 -0
  110. data/test/temp_91.rb +7 -0
  111. data/test/temp_92.rb +7 -0
  112. data/test/temp_93.rb +7 -0
  113. data/test/temp_94.rb +7 -0
  114. data/test/temp_95.rb +7 -0
  115. data/test/temp_96.rb +0 -0
  116. data/test/temp_97.rb +0 -0
  117. data/test/temp_98.rb +7 -0
  118. data/test/temp_99.rb +7 -0
  119. data/test/test_concretize.rb +132 -0
  120. data/test/test_concretize_all.rb +15 -0
  121. data/test/test_crystalize_block.rb +73 -0
  122. data/test/test_files/test.rb +615 -0
  123. data/test/test_files/vmode_test.rb +73 -0
  124. data/test/test_files/warn_test.rb +35 -0
  125. data/test/test_syntax.rb +25 -0
  126. metadata +268 -0
@@ -0,0 +1,68 @@
1
+ # this one inlines [trivial] ruby methods, like #nil?
2
+
3
+ module Ruby2CExtension::Plugins
4
+
5
+ class InlineMethods < Ruby2CExtension::Plugin
6
+
7
+ METHODS = {
8
+ [:nil?, 0] => proc { |cfun, recv, args|
9
+ "(Qnil == (#{recv}) ? Qtrue : Qfalse)"
10
+ },
11
+ [:equal?, 1] => proc { |cfun, recv, args|
12
+ cfun.instance_eval {
13
+ c_scope_res {
14
+ l "VALUE recv = #{recv};"
15
+ "(recv == (#{comp(args[0])}) ? Qtrue : Qfalse)"
16
+ }
17
+ }
18
+ },
19
+ :__send__ => proc { |cfun, recv, args|
20
+ unless args
21
+ raise Ruby2CExtension::Ruby2CExtError, "inlining #__send__ without arguments is not allowed"
22
+ end
23
+ cfun.instance_eval {
24
+ add_helper <<-EOC
25
+ static void inline_method_send_no_method_name() {
26
+ rb_raise(rb_eArgError, "no method name given");
27
+ }
28
+ EOC
29
+ c_scope_res {
30
+ l "VALUE recv = #{recv};"
31
+ build_args(args)
32
+ l "if (argc == 0) inline_method_send_no_method_name();"
33
+ "rb_funcall2(recv, rb_to_id(argv[0]), argc - 1, (&(argv[0])) + 1)"
34
+ }
35
+ }
36
+ },
37
+ }
38
+
39
+ def initialize(compiler)
40
+ super
41
+ self_node = [:self, {}]
42
+ compiler.add_preprocessor(:vcall) { |cfun, node|
43
+ handle(cfun, node.last[:mid], self_node, false) || node
44
+ }
45
+ compiler.add_preprocessor(:fcall) { |cfun, node|
46
+ handle(cfun, node.last[:mid], self_node, node.last[:args]) || node
47
+ }
48
+ compiler.add_preprocessor(:call) { |cfun, node|
49
+ handle(cfun, node.last[:mid], node.last[:recv], node.last[:args]) || node
50
+ }
51
+ end
52
+
53
+ def handle(cfun, method, recv, args)
54
+ if (pr = METHODS[method])
55
+ pr.call(cfun, cfun.comp(recv), args)
56
+ else
57
+ args ||= [:array, []]
58
+ if args.first == :array && (pr = METHODS[[method, args.last.size]])
59
+ pr.call(cfun, cfun.comp(recv), args.last)
60
+ else
61
+ nil
62
+ end
63
+ end
64
+ end
65
+
66
+ end
67
+
68
+ end
@@ -0,0 +1,147 @@
1
+ # this one makes for faster
2
+ # @a = 3
3
+ # @b = 4
4
+ # by doing the lookups locally, in C, instead of having ruby do it for us by a rb_ivar_set call.
5
+
6
+ module Ruby2CExtension::Plugins
7
+
8
+ class IVarCache < Ruby2CExtension::Plugin
9
+
10
+ include Util
11
+
12
+ def initialize(compiler)
13
+ super(compiler)
14
+ @cache_index = Hash.new { |h,k| h[k] = h.size }
15
+ compiler.add_preprocessor(:ivar) { |cfun, node|
16
+ hash = node.last
17
+ vid = hash[:vid]
18
+ key = [vid, cfun.__id__]
19
+ index = @cache_index[key]
20
+ entry = "ivar_cache[#{index}]"
21
+ "cache_ivar_get(&#{entry}, #{cfun.get_self}, #{cfun.sym(vid)})"
22
+ }
23
+ compiler.add_preprocessor(:iasgn) { |cfun, node|
24
+ hash = node.last
25
+ vid = hash[:vid]
26
+ key = [vid, cfun.__id__]
27
+ index = @cache_index[key]
28
+ entry = "ivar_cache[#{index}]"
29
+ "cache_ivar_set(&#{entry}, #{cfun.get_self}, #{cfun.sym(vid)}, #{cfun.comp(hash[:value])})"
30
+ }
31
+ end
32
+
33
+ def global_c_code
34
+ code = %{
35
+ typedef struct {
36
+ unsigned num_bins;
37
+ unsigned bin_pos;
38
+ } ivar_cache_entry;
39
+ static ivar_cache_entry ivar_cache[#{@cache_index.size}];
40
+ static void init_ivar_cache() {
41
+ ivar_cache_entry* entry;
42
+ for (entry = &ivar_cache[#{@cache_index.size-1}]; entry >= ivar_cache; --entry) {
43
+ entry->num_bins = 0;
44
+ entry->bin_pos = 0;
45
+ }
46
+ }
47
+ typedef struct st_table_entry st_table_entry;
48
+ struct st_table_entry {
49
+ unsigned int hash;
50
+ st_data_t key;
51
+ st_data_t record;
52
+ st_table_entry *next;
53
+ };
54
+ static st_table_entry *st_find_collided(st_table_entry **prev, ID id) {
55
+ st_table_entry *cur = *prev;
56
+ while (cur = cur->next) {
57
+ if (cur->hash == id) {
58
+ (*prev)->next = cur->next;
59
+ cur->next = *prev;
60
+ *prev = cur;
61
+ return cur;
62
+ }
63
+ prev = &(*prev)->next;
64
+ }
65
+ return 0;
66
+ }
67
+ static VALUE cache_ivar_get(ivar_cache_entry* entry,
68
+ VALUE obj, ID id)
69
+ {
70
+ st_table* table = ROBJECT(obj)->iv_tbl;
71
+ unsigned bin_pos;
72
+ st_table_entry *cur;
73
+ switch (TYPE(obj)) {
74
+ case T_OBJECT:
75
+ case T_CLASS:
76
+ case T_MODULE:
77
+ break;
78
+ default:
79
+ return rb_ivar_get(obj, id);
80
+ }
81
+ if (!table) return Qnil;
82
+ if (entry->num_bins==table->num_bins) {
83
+ bin_pos = entry->bin_pos;
84
+ } else {
85
+ entry->num_bins = table->num_bins;
86
+ bin_pos = entry->bin_pos = id % table->num_bins;
87
+ }
88
+ cur = table->bins[bin_pos];
89
+ if (!cur) return Qnil;
90
+ if (cur->hash == id) return cur->record;
91
+ cur = st_find_collided(&table->bins[bin_pos], id);
92
+ return cur ? cur->record : Qnil;
93
+ }
94
+ static VALUE cache_ivar_set(ivar_cache_entry* entry,
95
+ VALUE obj, ID id, VALUE val)
96
+ {
97
+ st_table* table;
98
+ unsigned bin_pos;
99
+ st_table_entry *cur;
100
+ if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4 || OBJ_FROZEN(obj))
101
+ return rb_ivar_set(obj, id, val);
102
+ switch (TYPE(obj)) {
103
+ case T_OBJECT:
104
+ case T_CLASS:
105
+ case T_MODULE:
106
+ break;
107
+ default:
108
+ return rb_ivar_set(obj, id, val);
109
+ }
110
+ table = ROBJECT(obj)->iv_tbl;
111
+ if (!table) {
112
+ table = ROBJECT(obj)->iv_tbl = st_init_numtable();
113
+ }
114
+ if (entry->num_bins==table->num_bins) {
115
+ bin_pos = entry->bin_pos;
116
+ } else {
117
+ entry->num_bins = table->num_bins;
118
+ bin_pos = entry->bin_pos = id % table->num_bins;
119
+ }
120
+ cur = table->bins[bin_pos];
121
+ if (!cur) {
122
+ st_add_direct(table, id, val);
123
+ return val;
124
+ }
125
+ if (cur->hash == id) return (cur->record = val);
126
+ cur = st_find_collided(&table->bins[bin_pos], id);
127
+ if (cur) {
128
+ return (cur->record = val);
129
+ } else {
130
+ st_add_direct(table, id, val);
131
+ return val;
132
+ }
133
+ }
134
+ }
135
+ code
136
+ end
137
+
138
+ def init_c_code
139
+ %{
140
+ init_ivar_cache();
141
+ }
142
+ end
143
+
144
+ end
145
+
146
+ end
147
+
@@ -0,0 +1,69 @@
1
+
2
+ module Ruby2CExtension::Plugins
3
+
4
+ class RequireInclude < Ruby2CExtension::Plugin
5
+
6
+ attr_reader :include_paths
7
+
8
+ def initialize(compiler, include_paths, ignore_files = nil)
9
+ super(compiler)
10
+ @include_paths = include_paths
11
+ done = {}
12
+ if ignore_files
13
+ ignore_files.each { |file|
14
+ done[File.expand_path(file)] = true
15
+ }
16
+ end
17
+ compiler.add_preprocessor(:fcall) { |cfun, node|
18
+ hash = node.last
19
+ if hash[:mid] == :require &&
20
+ (args = hash[:args]) &&
21
+ args.first == :array &&
22
+ (args = args.last).size == 1 &&
23
+ Array === args[0] &&
24
+ args[0].first == :str &&
25
+ (file = search_file(args[0].last[:lit]))
26
+ unless done[File.expand_path(file)]
27
+ done[File.expand_path(file)] = true
28
+ cfun.compiler.log "including require'd file: #{file}"
29
+ cfun.instance_eval {
30
+ add_helper <<-EOC
31
+ static NODE * find_top_cref(NODE *cref) {
32
+ while (cref && cref->nd_next) cref = cref->nd_next;
33
+ return cref;
34
+ }
35
+ EOC
36
+ c_scope {
37
+ l "NODE *top_cref = find_top_cref(#{get_cref});"
38
+ l "static int done = 0;"
39
+ c_if("!done") {
40
+ l "done = 1;"
41
+ compiler.rb_file_to_toplevel_functions(IO.read(file), file).each { |tlfn|
42
+ l "#{tlfn}(org_ruby_top_self, top_cref);"
43
+ }
44
+ }
45
+ }
46
+ }
47
+ end
48
+ "Qtrue"
49
+ else
50
+ node
51
+ end
52
+ }
53
+ end
54
+
55
+ def search_file(req_str)
56
+ req_str = req_str.dup
57
+ unless req_str =~ /\.rb\z/
58
+ req_str << ".rb"
59
+ end
60
+ res = false
61
+ include_paths.map { |path|
62
+ File.join(path, req_str)
63
+ }.find { |file|
64
+ File.exists? file
65
+ }
66
+ end
67
+ end
68
+
69
+ end
@@ -0,0 +1,154 @@
1
+
2
+ module Ruby2CExtension::Plugins
3
+
4
+ module Util
5
+
6
+ def deduce_type(node)
7
+ while true
8
+ Array === node or return
9
+ case node.first
10
+ when :lit
11
+ return Kernel.const_get(node.last[:lit].class.name)
12
+ when :nil
13
+ return NilClass
14
+ when :false
15
+ return FalseClass
16
+ when :true
17
+ return TrueClass
18
+ when :str, :dstr
19
+ return String
20
+ when :dsym
21
+ return Symbol
22
+ when :array, :zarray, :masgn
23
+ return Array
24
+ when :hash
25
+ return Hash
26
+ when :dregx, :dregx_once
27
+ return Regexp
28
+ when :dasn_curr, :iasgn, :cvdecl, :gasgn, :cdecl
29
+ node = node.last[:value]
30
+ when :attrasgn
31
+ args = node.last[:args]
32
+ Array === args or return
33
+ case args.first
34
+ when :array
35
+ node = args.last.last
36
+ when :argspush
37
+ node = args.last[:body]
38
+ else
39
+ return
40
+ end
41
+ else
42
+ return
43
+ end
44
+ end
45
+ end
46
+
47
+ def values(cfun, nreused, *rvalues) # :yield: *vals
48
+ header = "{"
49
+ cfun.l(header)
50
+ res = 0
51
+ reuse = 0
52
+ vals = []
53
+ res_assign = ""
54
+ res_val = ""
55
+ direct = /\A\s*(\w+(\s*\[\s*\d+\s*\])?|\d+)\s*\Z/
56
+ rvalues.each { |rvalue|
57
+ nreused -= 1
58
+ val = rvalue && cfun.comp(rvalue)
59
+ if val == "res"
60
+ if res_assign
61
+ header.concat("VALUE res#{res};")
62
+ res += 1
63
+ end
64
+ var = "res#{res}"
65
+ cfun.l(res_assign = "#{var} = #{val};")
66
+ res_val = val = var
67
+ elsif nreused >= 0 and val and val !~ direct
68
+ var = "reuse#{reuse}"
69
+ header.concat("VALUE #{var};")
70
+ cfun.l("#{var} = #{val};")
71
+ val = var
72
+ end
73
+ vals << val
74
+ }
75
+ res_assign.replace("")
76
+ res_val.replace("res")
77
+ if header.size == 1
78
+ header.replace("")
79
+ yield(*vals)
80
+ else
81
+ res_rvalue = yield(*vals)
82
+ cfun.assign_res(res_rvalue)
83
+ cfun.l "}"
84
+ "res"
85
+ end
86
+ end
87
+
88
+ def split_args(arity, args, extra_allowed=nil)
89
+ if arity<0
90
+ extra_allowed = true
91
+ arity = -arity -1
92
+ end
93
+ data = args.last
94
+ required = []
95
+ remaining = nil
96
+ case args.first
97
+ when :array
98
+ if data.size>arity
99
+ required = data[0, arity]
100
+ remaining = [:array, data[arity, data.size-arity]]
101
+ else
102
+ required = data
103
+ end
104
+ when :splat
105
+ remaining = args
106
+ when :argscat
107
+ required = split_args(arity, data[:head], true) or return nil
108
+ remaining = [:argscat, {:head => required.pop, :body => data[:body]}]
109
+ when :argspush
110
+ if extra_allowed
111
+ required = split_args(arity, data[:head], true) or return nil
112
+ remaining = [:argspush, {:head => required.pop, :body => data[:body]}]
113
+ else
114
+ required = split_args(arity-1, data[:head], false) or return nil
115
+ required << data[:body]
116
+ end
117
+ else
118
+ return nil
119
+ end
120
+ if required.size<arity
121
+ nil
122
+ elsif extra_allowed
123
+ remaining ||= [:array, []]
124
+ required << remaining
125
+ elsif remaining
126
+ nil
127
+ else
128
+ required
129
+ end
130
+ end
131
+
132
+ def args_arity(args)
133
+ data = args.last
134
+ case args.first
135
+ when :array
136
+ data.size
137
+ when :splat
138
+ -1
139
+ when :argscat
140
+ arity = args_arity(data[:head])
141
+ (arity<0) ? arity : -arity - 1
142
+ when :argspush
143
+ arity = args_arity(data[:head])
144
+ (arity<0) ? arity : arity + 1
145
+ else
146
+ -1
147
+ end
148
+ end
149
+
150
+ end
151
+
152
+ end
153
+
154
+
@@ -0,0 +1,121 @@
1
+
2
+ module Ruby2CExtension::Plugins
3
+
4
+ # TODO: Module.nesting, Module.constants, Kernel#autoload and Kernel#autoload?
5
+
6
+ class Warnings < Ruby2CExtension::Plugin
7
+
8
+ CALL_TYPES = [:vcall, :fcall, :call]
9
+
10
+ exp = "might not behave as expected"
11
+ exp2 = "will not behave as expected"
12
+ vis_exp = "visibility of the defined %s might not be as expected"
13
+
14
+ VCALL_WARNINGS = {
15
+ :binding => exp2,
16
+ :local_variables => exp2,
17
+ :callcc => exp,
18
+ }
19
+
20
+ FCALL_WARNINGS = {
21
+ :set_trace_func => exp,
22
+ :eval => exp,
23
+ :define_method => vis_exp % "method",
24
+ :attr => vis_exp % "attribute",
25
+ :attr_reader => vis_exp % "attribute(s)",
26
+ :attr_writer => vis_exp % "attribute(s)",
27
+ :attr_accessor => vis_exp % "attribute(s)",
28
+ :instance_eval => exp,
29
+ :module_eval => exp,
30
+ :class_eval => exp,
31
+ }
32
+
33
+ CALL_WARNINGS = {
34
+ :arity => "will return -1 for all methods defined in compiled Ruby code",
35
+ :instance_eval => exp,
36
+ :module_eval => exp,
37
+ :class_eval => exp,
38
+ }
39
+
40
+ BLOCK_PASS_WARNINGS = {
41
+ :define_method => true,
42
+ :instance_eval => true,
43
+ :module_eval => true,
44
+ :class_eval => true,
45
+ }
46
+
47
+ NO_WARNING_WITH_ITER = {
48
+ :instance_eval => true,
49
+ :module_eval => true,
50
+ :class_eval => true,
51
+ }
52
+
53
+ def initialize(compiler)
54
+ super
55
+ CALL_TYPES.each { |ct|
56
+ ct_sym = "check_#{ct}".to_sym
57
+ compiler.add_preprocessor(ct) { |cfun, node|
58
+ send(ct_sym, node.last)
59
+ node
60
+ }
61
+ }
62
+ [:iter, :block_pass].each { |it|
63
+ it_sym = "check_#{it}".to_sym
64
+ compiler.add_preprocessor(it) { |cfun, node|
65
+ if node.last[:iter] && CALL_TYPES.include?(node.last[:iter].first)
66
+ send(it_sym, node.last[:iter])
67
+ end
68
+ node
69
+ }
70
+ }
71
+ end
72
+
73
+ def warn(str, node_hash = {})
74
+ lstr = ""
75
+ if (n = node_hash[:node])
76
+ lstr << "#{n.file}:#{n.line}: "
77
+ end
78
+ lstr << "warning: " << str
79
+ compiler.log(lstr, true)
80
+ end
81
+
82
+ def check_vcall(hash)
83
+ if (m = VCALL_WARNINGS[hash[:mid]])
84
+ warn("#{hash[:mid]}: #{m}", hash)
85
+ end
86
+ end
87
+
88
+ def check_fcall(hash)
89
+ if (m = FCALL_WARNINGS[hash[:mid]])
90
+ warn("#{hash[:mid]}: #{m}", hash)
91
+ else
92
+ unless hash[:args]
93
+ check_vcall(hash)
94
+ end
95
+ end
96
+ end
97
+
98
+ def check_call(hash)
99
+ if (m = CALL_WARNINGS[hash[:mid]])
100
+ warn("#{hash[:mid]}: #{m}", hash)
101
+ end
102
+ end
103
+
104
+ def check_iter(iter_node)
105
+ mid = iter_node.last[:mid]
106
+ unless NO_WARNING_WITH_ITER[mid]
107
+ send("check_#{iter_node.first}", iter_node.last)
108
+ end
109
+ end
110
+
111
+ def check_block_pass(iter_node)
112
+ mid = iter_node.last[:mid]
113
+ if BLOCK_PASS_WARNINGS[mid]
114
+ warn("#{mid} with block_pass: might not behave as expected", iter_node.last)
115
+ else
116
+ send("check_#{iter_node.first}", iter_node.last)
117
+ end
118
+ end
119
+ end
120
+
121
+ end