crystalizer 0.2.2

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