fastruby 0.0.16 → 0.0.17
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.
- data/CHANGELOG +17 -1
- data/Rakefile +1 -1
- data/ext/fastruby_base/fastruby_base.inl +81 -3
- data/lib/fastruby/fastruby_sexp.rb +21 -0
- data/lib/fastruby/getlocals.rb +2 -1
- data/lib/fastruby/object.rb +1 -1
- data/lib/fastruby/sexp_extension.rb +189 -0
- data/lib/fastruby/sexp_extension_edges.rb +210 -0
- data/lib/fastruby/translator/modules/block.rb +29 -22
- data/lib/fastruby/translator/modules/call.rb +211 -34
- data/lib/fastruby/translator/modules/defn.rb +64 -29
- data/lib/fastruby/translator/modules/exceptions.rb +1 -1
- data/lib/fastruby/translator/modules/flow.rb +93 -31
- data/lib/fastruby/translator/modules/iter.rb +277 -340
- data/lib/fastruby/translator/modules/literal.rb +97 -20
- data/lib/fastruby/translator/modules/logical.rb +40 -5
- data/lib/fastruby/translator/modules/method_group.rb +41 -19
- data/lib/fastruby/translator/modules/nonlocal.rb +74 -29
- data/lib/fastruby/translator/modules/variable.rb +151 -42
- data/lib/fastruby/translator/scope_mode_helper.rb +161 -0
- data/lib/fastruby/translator/translator.rb +389 -302
- data/lib/fastruby.rb +1 -1
- data/lib/fastruby.rb~ +36 -0
- data/spec/edges_helper.rb +91 -0
- data/spec/graph/base_spec.rb +35 -0
- data/spec/graph/path_spec.rb +48 -0
- data/spec/graph/vertex_spec.rb +58 -0
- data/spec/ruby/block/proc_as_block_spec.rb +214 -0
- data/spec/ruby/block/redo_spec.rb +133 -0
- data/spec/ruby/defn/single_function_spec.rb +50 -0
- data/spec/scope_mode/base_spec.rb +55 -0
- data/spec/scope_mode/block_spec.rb +105 -0
- data/spec/scope_mode/call_spec.rb +24 -0
- data/spec/scope_mode/exception_spec.rb +34 -0
- data/spec/scope_mode/flow_spec.rb +99 -0
- data/spec/scope_mode/optimization_spec.rb +130 -0
- data/spec/sexp2graph/base_spec.rb +36 -0
- data/spec/sexp2graph/exception_spec.rb +172 -0
- data/spec/sexp2graph/flow_spec.rb +67 -0
- data/spec/sexp2graph/logical_spec.rb +21 -0
- data/spec/sexp2graph/variable_spec.rb +26 -0
- metadata +110 -120
- data/lib/fastruby/self +0 -82
- data/lib/len +0 -280
- data/spec/block/proc_as_block_spec.rb +0 -111
- data/spec/block/redo_spec.rb +0 -67
- /data/spec/{base_spec.rb → ruby/base_spec.rb} +0 -0
- /data/spec/{block → ruby/block}/arguments_spec.rb +0 -0
- /data/spec/{block → ruby/block}/block_as_proc_spec.rb +0 -0
- /data/spec/{block → ruby/block}/break_spec.rb +0 -0
- /data/spec/{block → ruby/block}/callcc_spec.rb +0 -0
- /data/spec/{block → ruby/block}/lambda_spec.rb +0 -0
- /data/spec/{block → ruby/block}/next_spec.rb +0 -0
- /data/spec/{block → ruby/block}/proc_spec.rb +0 -0
- /data/spec/{block → ruby/block}/retry_spec.rb +0 -0
- /data/spec/{block_spec.rb → ruby/block_spec.rb} +0 -0
- /data/spec/{call → ruby/call}/base_call_spec.rb +0 -0
- /data/spec/{call → ruby/call}/multiple_args_spec.rb +0 -0
- /data/spec/{control_spec.rb → ruby/control_spec.rb} +0 -0
- /data/spec/{defn → ruby/defn}/default_args_spec.rb +0 -0
- /data/spec/{defn → ruby/defn}/multiple_args_spec.rb +0 -0
- /data/spec/{defn → ruby/defn}/replacement_spec.rb +0 -0
- /data/spec/{exception → ruby/exception}/base_spec.rb +0 -0
- /data/spec/{exception → ruby/exception}/ensure_spec.rb +0 -0
- /data/spec/{exception → ruby/exception}/exc_trap_spec.rb +0 -0
- /data/spec/{exception → ruby/exception}/internal_ex_spec.rb +0 -0
- /data/spec/{exception → ruby/exception}/syntaxis_spec.rb +0 -0
- /data/spec/{expression_spec.rb → ruby/expression_spec.rb} +0 -0
- /data/spec/{flow_control → ruby/flow_control}/case_spec.rb +0 -0
- /data/spec/{flow_control → ruby/flow_control}/for_spec.rb +0 -0
- /data/spec/{integrity_spec.rb → ruby/integrity_spec.rb} +0 -0
- /data/spec/{jump → ruby/jump}/next_spec.rb +0 -0
- /data/spec/{literal_spec.rb → ruby/literal_spec.rb} +0 -0
- /data/spec/{module_spec.rb → ruby/module_spec.rb} +0 -0
- /data/spec/{return_spec.rb → ruby/return_spec.rb} +0 -0
- /data/spec/{singleton_spec.rb → ruby/singleton_spec.rb} +0 -0
- /data/spec/{sugar_spec.rb → ruby/sugar_spec.rb} +0 -0
- /data/spec/{variable_spec.rb → ruby/variable_spec.rb} +0 -0
| @@ -27,8 +27,27 @@ module FastRuby | |
| 27 27 | 
             
                  "rb_cvar_get(CLASS_OF(plocals->self) != rb_cClass ? CLASS_OF(plocals->self) : plocals->self,#{intern_num tree[1]})"
         | 
| 28 28 | 
             
                end
         | 
| 29 29 |  | 
| 30 | 
            -
                def to_c_cvasgn(tree)
         | 
| 30 | 
            +
                def to_c_cvasgn(tree, result_var = nil)
         | 
| 31 | 
            +
                  if result_var
         | 
| 32 | 
            +
                    "
         | 
| 33 | 
            +
                      {
         | 
| 34 | 
            +
                        VALUE recv = CLASS_OF(plocals->self) != rb_cClass ? CLASS_OF(plocals->self) : plocals->self;
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                        #{to_c tree[2], result_var};
         | 
| 37 | 
            +
                        
         | 
| 38 | 
            +
                        #{if RUBY_VERSION =~ /^1\.9/
         | 
| 39 | 
            +
                          "rb_cvar_set(recv,#{intern_num tree[1]},#{result_var});"
         | 
| 40 | 
            +
                          elsif RUBY_VERSION =~ /^1\.8/
         | 
| 41 | 
            +
                          "rb_cvar_set(recv,#{intern_num tree[1]},#{result_var},Qfalse);"
         | 
| 42 | 
            +
                          else
         | 
| 43 | 
            +
                            raise RuntimeError, "unsupported ruby version #{RUBY_VERSION}"
         | 
| 44 | 
            +
                          end 
         | 
| 45 | 
            +
                        }
         | 
| 46 | 
            +
                      }
         | 
| 47 | 
            +
                   "
         | 
| 48 | 
            +
                  else
         | 
| 31 49 | 
             
                  "__rb_cvar_set(CLASS_OF(plocals->self) != rb_cClass ? CLASS_OF(plocals->self) : plocals->self,#{intern_num tree[1]},#{to_c tree[2]},Qfalse)"
         | 
| 50 | 
            +
                  end
         | 
| 32 51 | 
             
                end
         | 
| 33 52 |  | 
| 34 53 | 
             
                def to_c_gvar(tree)
         | 
| @@ -39,48 +58,81 @@ module FastRuby | |
| 39 58 | 
             
                  end
         | 
| 40 59 | 
             
                end
         | 
| 41 60 |  | 
| 42 | 
            -
                def to_c_gasgn(tree)
         | 
| 61 | 
            +
                def to_c_gasgn(tree, result_var = nil)
         | 
| 62 | 
            +
                  if result_var
         | 
| 63 | 
            +
                      "
         | 
| 64 | 
            +
                      {
         | 
| 65 | 
            +
                      #{to_c tree[2], result_var}; 
         | 
| 66 | 
            +
                      rb_gvar_set((void*)#{global_entry(tree[1])},#{result_var});
         | 
| 67 | 
            +
                      }
         | 
| 68 | 
            +
                      "
         | 
| 69 | 
            +
                  else
         | 
| 43 70 | 
             
                  "_rb_gvar_set((void*)#{global_entry(tree[1])}, #{to_c tree[2]})"
         | 
| 71 | 
            +
                  end
         | 
| 44 72 | 
             
                end
         | 
| 45 73 |  | 
| 46 74 | 
             
                def to_c_ivar(tree)
         | 
| 47 75 | 
             
                  "rb_ivar_get(#{locals_accessor}self,#{intern_num tree[1]})"
         | 
| 48 76 | 
             
                end
         | 
| 49 77 |  | 
| 50 | 
            -
                def to_c_iasgn(tree)
         | 
| 51 | 
            -
                   | 
| 78 | 
            +
                def to_c_iasgn(tree, result_var = nil)
         | 
| 79 | 
            +
                  if result_var
         | 
| 80 | 
            +
                      "
         | 
| 81 | 
            +
                      {
         | 
| 82 | 
            +
                      #{to_c tree[2], result_var}; 
         | 
| 83 | 
            +
                      rb_ivar_set(#{locals_accessor}self,#{intern_num tree[1]},#{result_var});
         | 
| 84 | 
            +
                      }
         | 
| 85 | 
            +
                      "
         | 
| 86 | 
            +
                  else
         | 
| 87 | 
            +
                    "_rb_ivar_set(#{locals_accessor}self,#{intern_num tree[1]},#{to_c tree[2]})"
         | 
| 88 | 
            +
                  end
         | 
| 52 89 | 
             
                end
         | 
| 53 90 |  | 
| 54 91 | 
             
                def to_c_const(tree)
         | 
| 55 92 | 
             
                  "rb_const_get(CLASS_OF(plocals->self), #{intern_num(tree[1])})"
         | 
| 56 93 | 
             
                end
         | 
| 57 94 |  | 
| 58 | 
            -
                def to_c_cdecl(tree)
         | 
| 95 | 
            +
                def to_c_cdecl(tree, result_var_ = nil)
         | 
| 96 | 
            +
                  
         | 
| 97 | 
            +
                  result_var = result_var_ || "value"
         | 
| 98 | 
            +
                  
         | 
| 59 99 | 
             
                  if tree[1].instance_of? Symbol
         | 
| 60 | 
            -
                     | 
| 61 | 
            -
                       | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 100 | 
            +
                    code = "
         | 
| 101 | 
            +
                      {
         | 
| 102 | 
            +
                        // set constant #{tree[1].to_s}
         | 
| 103 | 
            +
                        #{to_c tree[2], result_var};
         | 
| 104 | 
            +
                        rb_const_set(rb_cObject, #{intern_num tree[1]}, #{result_var});
         | 
| 105 | 
            +
                      }
         | 
| 65 106 | 
             
                      "
         | 
| 66 107 | 
             
                  elsif tree[1].instance_of? FastRuby::FastRubySexp
         | 
| 67 108 |  | 
| 68 109 | 
             
                    if tree[1].node_type == :colon2
         | 
| 69 | 
            -
                       | 
| 70 | 
            -
                         | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 110 | 
            +
                      code = "
         | 
| 111 | 
            +
                        {
         | 
| 112 | 
            +
                          // set constant #{tree[1].to_s}
         | 
| 113 | 
            +
                          #{to_c tree[2], result_var};
         | 
| 114 | 
            +
                          VALUE klass = Qnil;
         | 
| 115 | 
            +
                          #{to_c tree[1][1], "klass"};
         | 
| 116 | 
            +
                          rb_const_set(klass, #{intern_num tree[1][2]}, #{result_var});
         | 
| 117 | 
            +
                        }
         | 
| 75 118 | 
             
                        "
         | 
| 76 119 | 
             
                    elsif tree[1].node_type == :colon3
         | 
| 77 | 
            -
                       | 
| 120 | 
            +
                      code = "
         | 
| 121 | 
            +
                        {
         | 
| 78 122 | 
             
                        // set constant #{tree[1].to_s}
         | 
| 79 | 
            -
                         | 
| 80 | 
            -
                        rb_const_set(rb_cObject, #{intern_num tree[1][1]},  | 
| 81 | 
            -
                         | 
| 123 | 
            +
                        #{to_c tree[2], result_var};
         | 
| 124 | 
            +
                        rb_const_set(rb_cObject, #{intern_num tree[1][1]}, #{result_var});
         | 
| 125 | 
            +
                        }
         | 
| 82 126 | 
             
                        "
         | 
| 83 127 | 
             
                    end
         | 
| 128 | 
            +
                    
         | 
| 129 | 
            +
                    if result_var_
         | 
| 130 | 
            +
                      code
         | 
| 131 | 
            +
                    else
         | 
| 132 | 
            +
                       inline_block "VALUE #{result_var} = Qnil;\n" + code + "
         | 
| 133 | 
            +
                        return #{result_var};
         | 
| 134 | 
            +
                       "
         | 
| 135 | 
            +
                    end
         | 
| 84 136 | 
             
                  end
         | 
| 85 137 | 
             
                end
         | 
| 86 138 |  | 
| @@ -88,15 +140,29 @@ module FastRuby | |
| 88 140 | 
             
                  "rb_const_get_from(rb_cObject, #{intern_num tree[1]})"
         | 
| 89 141 | 
             
                end
         | 
| 90 142 |  | 
| 91 | 
            -
                def to_c_colon2(tree)
         | 
| 92 | 
            -
                   | 
| 93 | 
            -
                     | 
| 143 | 
            +
                def to_c_colon2(tree, result_var = nil)
         | 
| 144 | 
            +
                  code = "
         | 
| 145 | 
            +
                    {
         | 
| 146 | 
            +
                    VALUE klass = Qnil;
         | 
| 147 | 
            +
                    
         | 
| 148 | 
            +
                    #{to_c tree[1],"klass"};
         | 
| 149 | 
            +
                        #{
         | 
| 150 | 
            +
                        if result_var
         | 
| 151 | 
            +
                          "#{result_var} = Qnil;"
         | 
| 152 | 
            +
                        end
         | 
| 153 | 
            +
                      }
         | 
| 94 154 |  | 
| 95 155 | 
             
                  if (rb_is_const_id(#{intern_num tree[2]})) {
         | 
| 96 156 | 
             
                    switch (TYPE(klass)) {
         | 
| 97 157 | 
             
                      case T_CLASS:
         | 
| 98 158 | 
             
                      case T_MODULE:
         | 
| 99 | 
            -
                         | 
| 159 | 
            +
                        #{
         | 
| 160 | 
            +
                        if result_var
         | 
| 161 | 
            +
                          "#{result_var} = rb_const_get_from(klass, #{intern_num tree[2]});"
         | 
| 162 | 
            +
                        else
         | 
| 163 | 
            +
                          "return rb_const_get_from(klass, #{intern_num tree[2]});"
         | 
| 164 | 
            +
                        end
         | 
| 165 | 
            +
                        }
         | 
| 100 166 | 
             
                        break;
         | 
| 101 167 | 
             
                      default:
         | 
| 102 168 | 
             
                        #{_raise("rb_eTypeError","not a class/module")};
         | 
| @@ -104,35 +170,78 @@ module FastRuby | |
| 104 170 | 
             
                    }
         | 
| 105 171 | 
             
                  }
         | 
| 106 172 | 
             
                  else {
         | 
| 107 | 
            -
             | 
| 173 | 
            +
                        #{
         | 
| 174 | 
            +
                        if result_var
         | 
| 175 | 
            +
                          "#{result_var} = rb_funcall(klass, #{intern_num tree[2]}, 0, 0);"
         | 
| 176 | 
            +
                        else
         | 
| 177 | 
            +
                          "return rb_funcall(klass, #{intern_num tree[2]}, 0, 0);"
         | 
| 178 | 
            +
                        end
         | 
| 179 | 
            +
                        }
         | 
| 108 180 | 
             
                  }
         | 
| 109 | 
            -
             | 
| 110 | 
            -
             | 
| 181 | 
            +
                    
         | 
| 182 | 
            +
                        #{
         | 
| 183 | 
            +
                        unless result_var
         | 
| 184 | 
            +
                          "return Qnil;"
         | 
| 185 | 
            +
                        end
         | 
| 186 | 
            +
                        }
         | 
| 187 | 
            +
                    }
         | 
| 111 188 | 
             
                  "
         | 
| 189 | 
            +
                  
         | 
| 190 | 
            +
                  if result_var
         | 
| 191 | 
            +
                    code
         | 
| 192 | 
            +
                  else
         | 
| 193 | 
            +
                    inline_block code
         | 
| 194 | 
            +
                  end
         | 
| 112 195 | 
             
                end
         | 
| 113 196 |  | 
| 114 | 
            -
                def to_c_lasgn(tree)
         | 
| 115 | 
            -
                   | 
| 116 | 
            -
             | 
| 117 | 
            -
             | 
| 197 | 
            +
                def to_c_lasgn(tree, result_var = nil)
         | 
| 198 | 
            +
                  code = "
         | 
| 199 | 
            +
                      {
         | 
| 200 | 
            +
                        #{to_c tree[2], result_var};
         | 
| 201 | 
            +
                        #{locals_accessor}#{tree[1]} = #{result_var};
         | 
| 202 | 
            +
                       }
         | 
| 203 | 
            +
                       "
         | 
| 118 204 |  | 
| 119 | 
            -
             | 
| 120 | 
            -
             | 
| 121 | 
            -
             | 
| 205 | 
            +
                  if result_var
         | 
| 206 | 
            +
                    if options[:validate_lvar_types]
         | 
| 207 | 
            +
                      klass = @infer_lvar_map[tree[1]]
         | 
| 208 | 
            +
                      if klass
         | 
| 209 | 
            +
                        "
         | 
| 210 | 
            +
                        {
         | 
| 211 | 
            +
                          #{to_c tree[2], result_var};
         | 
| 212 | 
            +
                          if (CLASS_OF(#{result_var})!=#{literal_value klass}) {
         | 
| 122 213 | 
             
                            #{_raise(literal_value(FastRuby::TypeMismatchAssignmentException), "Illegal assignment at runtime (type mismatch)")};
         | 
| 123 214 | 
             
                          }
         | 
| 124 | 
            -
                           | 
| 215 | 
            +
                          #{locals_accessor}#{tree[1]} = #{result_var};
         | 
| 125 216 | 
             
                        }
         | 
| 126 | 
            -
             | 
| 127 | 
            -
                       | 
| 128 | 
            -
             | 
| 129 | 
            -
             | 
| 130 | 
            -
                      "_lvar_assing(&#{locals_accessor}#{tree[1]}, #{anonymous_function(&verify_type_function)}(#{to_c tree[2]},pframe))"
         | 
| 217 | 
            +
                       "
         | 
| 218 | 
            +
                      else
         | 
| 219 | 
            +
                        code
         | 
| 220 | 
            +
                      end
         | 
| 131 221 | 
             
                    else
         | 
| 132 | 
            -
                       | 
| 222 | 
            +
                      code
         | 
| 133 223 | 
             
                    end
         | 
| 134 224 | 
             
                  else
         | 
| 135 | 
            -
                     | 
| 225 | 
            +
                    if options[:validate_lvar_types]
         | 
| 226 | 
            +
                      klass = @infer_lvar_map[tree[1]]
         | 
| 227 | 
            +
                      if klass
         | 
| 228 | 
            +
                        verify_type_function = proc { |name| "
         | 
| 229 | 
            +
                          static VALUE #{name}(VALUE arg, void* pframe ) {
         | 
| 230 | 
            +
                            if (CLASS_OF(arg)!=#{literal_value klass}) {
         | 
| 231 | 
            +
                              #{_raise(literal_value(FastRuby::TypeMismatchAssignmentException), "Illegal assignment at runtime (type mismatch)")};
         | 
| 232 | 
            +
                            }
         | 
| 233 | 
            +
                            return arg;
         | 
| 234 | 
            +
                          }
         | 
| 235 | 
            +
                        "
         | 
| 236 | 
            +
                        }
         | 
| 237 | 
            +
                        
         | 
| 238 | 
            +
                        "_lvar_assing(&#{locals_accessor}#{tree[1]}, #{anonymous_function(&verify_type_function)}(#{to_c tree[2]},pframe))"
         | 
| 239 | 
            +
                      else
         | 
| 240 | 
            +
                        "_lvar_assing(&#{locals_accessor}#{tree[1]},#{to_c tree[2]})"
         | 
| 241 | 
            +
                      end
         | 
| 242 | 
            +
                    else
         | 
| 243 | 
            +
                      "_lvar_assing(&#{locals_accessor}#{tree[1]},#{to_c tree[2]})"
         | 
| 244 | 
            +
                    end
         | 
| 136 245 | 
             
                  end
         | 
| 137 246 | 
             
                end
         | 
| 138 247 |  | 
| @@ -0,0 +1,161 @@ | |
| 1 | 
            +
            =begin
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            This file is part of the fastruby project, http://github.com/tario/fastruby
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Copyright (c) 2011 Roberto Dario Seminara <robertodarioseminara@gmail.com>
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            fastruby is free software: you can redistribute it and/or modify
         | 
| 8 | 
            +
            it under the terms of the gnu general public license as published by
         | 
| 9 | 
            +
            the free software foundation, either version 3 of the license, or
         | 
| 10 | 
            +
            (at your option) any later version.
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            fastruby is distributed in the hope that it will be useful,
         | 
| 13 | 
            +
            but without any warranty; without even the implied warranty of
         | 
| 14 | 
            +
            merchantability or fitness for a particular purpose.  see the
         | 
| 15 | 
            +
            gnu general public license for more details.
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            you should have received a copy of the gnu general public license
         | 
| 18 | 
            +
            along with fastruby.  if not, see <http://www.gnu.org/licenses/>.
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            =end
         | 
| 21 | 
            +
            require "fastruby/sexp_extension"
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            module FastRuby
         | 
| 24 | 
            +
              class ScopeModeHelper
         | 
| 25 | 
            +
                def self.get_scope_mode(tree_)
         | 
| 26 | 
            +
                  new.get_scope_mode(tree_)
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def when_array_to_if(array)
         | 
| 30 | 
            +
                  if array.size == 1
         | 
| 31 | 
            +
                    array[0] || s(:nil)
         | 
| 32 | 
            +
                  else
         | 
| 33 | 
            +
                    first_when_tree = array[0]
         | 
| 34 | 
            +
                    comparers = first_when_tree[1][1..-1]
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                    condition_tree = s(:or)
         | 
| 37 | 
            +
                    comparers.each do |st|
         | 
| 38 | 
            +
                      condition_tree << s(:call, st, :===, s(:arglist, s(:lvar, :temporal_case_var))) 
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    s(:if, condition_tree, first_when_tree[2], when_array_to_if(array[1..-1]) )
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
                
         | 
| 45 | 
            +
                def get_scope_mode(tree_)
         | 
| 46 | 
            +
                  tree = FastRuby::FastRubySexp.from_sexp(tree_).transform do |subtree|
         | 
| 47 | 
            +
                    if subtree.node_type == :for
         | 
| 48 | 
            +
                      s(:iter,s(:call, subtree[1],:each, s(:arglist)),subtree[2], subtree[3] )
         | 
| 49 | 
            +
                    elsif subtree.node_type == :case
         | 
| 50 | 
            +
                      ifs = when_array_to_if(subtree[2..-1])
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                      s(:block, s(:lasgn, :temporal_case_var, subtree[1]), ifs)
         | 
| 53 | 
            +
                    else
         | 
| 54 | 
            +
                      nil
         | 
| 55 | 
            +
                    end
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  if tree.node_type == :defn
         | 
| 59 | 
            +
                    args_tree = tree[2]
         | 
| 60 | 
            +
                    impl_tree = tree[3]
         | 
| 61 | 
            +
                  elsif tree.node_type == :defs
         | 
| 62 | 
            +
                    args_tree = tree[3]
         | 
| 63 | 
            +
                    impl_tree = tree[4]
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  graph = impl_tree.to_graph
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  args_tree[1..-1].each do |subtree|
         | 
| 69 | 
            +
                    return :dag if subtree.to_s =~ /^\&/
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  tree.walk_tree do |subtree|
         | 
| 73 | 
            +
                    if subtree.node_type == :iter
         | 
| 74 | 
            +
                      iter_impl = subtree[3]
         | 
| 75 | 
            +
                      
         | 
| 76 | 
            +
                      return :dag if has_local_variable_access?(subtree[3])
         | 
| 77 | 
            +
                      return :dag if subtree[2]
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                      if iter_impl
         | 
| 80 | 
            +
                        return_node = iter_impl.find_tree{|st2| st2.node_type == :return}
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                        if return_node
         | 
| 83 | 
            +
                          return :dag
         | 
| 84 | 
            +
                        end
         | 
| 85 | 
            +
                      end
         | 
| 86 | 
            +
                    elsif subtree.node_type == :block_pass
         | 
| 87 | 
            +
                      return :dag
         | 
| 88 | 
            +
                    end
         | 
| 89 | 
            +
                  end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  impl_tree.walk_tree do |subtree|
         | 
| 92 | 
            +
                    graph.each_path_from(subtree) do |path|
         | 
| 93 | 
            +
                      # verify path prohibitive for :linear scope (local variable read after call)
         | 
| 94 | 
            +
                      has_call = false
         | 
| 95 | 
            +
                      writes = Set.new
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                      path.each do |st2|
         | 
| 98 | 
            +
                        if st2.node_type == :call
         | 
| 99 | 
            +
                          if has_call and st2[1] == nil
         | 
| 100 | 
            +
                            return :dag
         | 
| 101 | 
            +
                          end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                          writes.clear
         | 
| 104 | 
            +
                          has_call = true
         | 
| 105 | 
            +
                        elsif st2.node_type == :iter
         | 
| 106 | 
            +
                          if has_call and st2[1][1] == nil
         | 
| 107 | 
            +
                            return :dag
         | 
| 108 | 
            +
                          end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                          writes.clear
         | 
| 111 | 
            +
                          has_call = true
         | 
| 112 | 
            +
                        elsif st2.node_type == :lasgn
         | 
| 113 | 
            +
                          writes << st2[1] # record local writes
         | 
| 114 | 
            +
                        elsif st2.node_type == :lvar or st2.node_type == :self or 
         | 
| 115 | 
            +
                              st2.node_type == :return or st2.node_type == :yield
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                          if has_call
         | 
| 118 | 
            +
                            if st2.node_type == :lvar
         | 
| 119 | 
            +
                              if writes.include? st2[1]
         | 
| 120 | 
            +
                                # no problem
         | 
| 121 | 
            +
                              else
         | 
| 122 | 
            +
                                # read after call, the scope of this function must be implemented on heap
         | 
| 123 | 
            +
                                return :dag
         | 
| 124 | 
            +
                              end
         | 
| 125 | 
            +
                            else
         | 
| 126 | 
            +
                              return :dag
         | 
| 127 | 
            +
                            end              
         | 
| 128 | 
            +
                          end
         | 
| 129 | 
            +
                        end
         | 
| 130 | 
            +
                      end
         | 
| 131 | 
            +
                    end
         | 
| 132 | 
            +
                  end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                  :linear
         | 
| 135 | 
            +
                end
         | 
| 136 | 
            +
                
         | 
| 137 | 
            +
            private
         | 
| 138 | 
            +
                def has_local_variable_access?(*trees) 
         | 
| 139 | 
            +
                  trees.each do |tree|
         | 
| 140 | 
            +
                    return false unless tree.kind_of? FastRuby::FastRubySexp
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                    tree.walk_tree do |subtree|
         | 
| 143 | 
            +
                      if subtree.node_type == :lvar or 
         | 
| 144 | 
            +
                        subtree.node_type == :self or 
         | 
| 145 | 
            +
                        subtree.node_type == :yield or
         | 
| 146 | 
            +
                        subtree.node_type == :return or 
         | 
| 147 | 
            +
                        subtree.node_type == :lasgn
         | 
| 148 | 
            +
                        return true
         | 
| 149 | 
            +
                      end
         | 
| 150 | 
            +
                      
         | 
| 151 | 
            +
                      if subtree.node_type == :call
         | 
| 152 | 
            +
                        if subtree[1] == nil
         | 
| 153 | 
            +
                          return true
         | 
| 154 | 
            +
                        end
         | 
| 155 | 
            +
                      end
         | 
| 156 | 
            +
                    end
         | 
| 157 | 
            +
                  end
         | 
| 158 | 
            +
                  false
         | 
| 159 | 
            +
                end 
         | 
| 160 | 
            +
              end
         | 
| 161 | 
            +
            end
         |