class TypeProf::Core::AST::CallBaseNode - typeprof: Ruby Standard Library Documentation

# class TypeProf::Core::AST::CallBaseNode

### Attributes

block_body[R]
block_f_args[R]
block_pass[R]
block_tbl[R]
keyword_args[R]
mid[R]
mid_code_range[R]
positional_args[R]
recv[R]
splat_flags[R]
yield[R]

### Public Class Methods

new(raw_node, recv, mid, mid_code_range, raw_args, last_arg, raw_block, lenv) click to toggle source
Calls superclass method `TypeProf::Core::AST::Node::new`

    # File typeprof-0.30.1/lib/typeprof/core/ast/call.rb, line 4
    def initialize(raw_node, recv, mid, mid_code_range, raw_args, last_arg, raw_block, lenv)
      super(raw_node, lenv)

      @recv = recv
      @mid = mid
      @mid_code_range = mid_code_range

      # args
      @positional_args = []
      @splat_flags = []
      @keyword_args = nil

      @block_pass = nil
      @block_tbl = nil
      @block_f_args = nil
      @block_body = nil

      if raw_args
        args = []
        @splat_flags = []
        raw_args.arguments.each do |raw_arg|
          if raw_arg.is_a?(Prism::SplatNode)
            args << raw_arg.expression
            @splat_flags << true
          else
            args << raw_arg
            @splat_flags << false
          end
        end
        @positional_args = args.map {|arg| AST.create_node(arg, lenv) }

        if @positional_args.last.is_a?(TypeProf::Core::AST::HashNode) && @positional_args.last.keywords
          @keyword_args = @positional_args.pop
        end
      end

      @positional_args << last_arg if last_arg

      if raw_block
        if raw_block.type == :block_argument_node
          @block_pass = AST.create_node(raw_block.expression, lenv)
        else
          @block_pass = nil
          @block_tbl = raw_block.locals
          # TODO: optional args, etc.
          @block_f_args = case raw_block.parameters
                          when Prism::BlockParametersNode
                            raw_block.parameters.parameters.requireds.map {|n| n.is_a?(Prism::MultiTargetNode) ? nil : n.name }
                          when Prism::NumberedParametersNode
                            1.upto(raw_block.parameters.maximum).map { |n| :"_#{n}" }
                          when nil
                            []
                          else
                            raise "not supported yet: #{ raw_block.parameters.class }"
                          end
          ncref = CRef.new(lenv.cref.cpath, :instance, @mid, lenv.cref)
          nlenv = LocalEnv.new(@lenv.path, ncref, {}, @lenv.return_boxes)
          @block_body = raw_block.body ? AST.create_node(raw_block.body, nlenv) : DummyNilNode.new(code_range, lenv)
        end
      end

      @yield = raw_node.type == :yield_node
    end

### Public Instance Methods

attrs(= { mid:, splat_flags:, block_tbl:, block_f_args:, yield: }) click to toggle source

    # File typeprof-0.30.1/lib/typeprof/core/ast/call.rb, line 73
      def attrs = { mid:, splat_flags:, block_tbl:, block_f_args:, yield: }

      def install0(genv)
        recv = @recv ? @recv.install(genv) : @yield ? @lenv.get_var(:"*given_block") : @lenv.get_var(:"*self")

        positional_args = @positional_args.map do |arg|
          arg.install(genv)
        end

        keyword_args = @keyword_args ? @keyword_args.install(genv) : nil

        if @block_body
          @lenv.locals.each {|var, vtx| @block_body.lenv.locals[var] = vtx }
          @block_tbl.each {|var| @block_body.lenv.locals[var] = Source.new(genv.nil_type) }
          @block_body.lenv.locals[:"*self"] = @block_body.lenv.cref.get_self(genv)

          blk_f_args = []
          if @block_f_args
            @block_f_args.each do |arg|
              blk_f_args << @block_body.lenv.new_var(arg, self)
            end
          end

          @lenv.locals.each do |var, vtx|
            @block_body.lenv.set_var(var, vtx)
          end
          vars = []
          @block_body.modified_vars(@lenv.locals.keys - @block_tbl, vars)
          vars.uniq!
          vars.each do |var|
            vtx = @lenv.get_var(var)
            nvtx = vtx.new_vertex(genv, self)
            @lenv.set_var(var, nvtx)
            @block_body.lenv.set_var(var, nvtx)
          end

          e_ret = @block_body.lenv.locals[:"*expected_block_ret"] = Vertex.new(self)
          @block_body.install(genv)
          @block_body.lenv.add_next_box(@changes.add_escape_box(genv, @block_body.ret, e_ret))

          vars.each do |var|
            @changes.add_edge(genv, @block_body.lenv.get_var(var), @lenv.get_var(var))
          end

          blk_f_ary_arg = Vertex.new(self)
          @changes.add_masgn_box(genv, blk_f_ary_arg, blk_f_args, nil, nil) # TODO: support splat "do |a, *b, c|"
          block = Block.new(self, blk_f_ary_arg, blk_f_args, @block_body.lenv.next_boxes)
          blk_ty = Source.new(Type::Proc.new(genv, block))
        elsif @block_pass
          blk_ty = @block_pass.install(genv)
        end

        a_args = ActualArguments.new(positional_args, @splat_flags, keyword_args, blk_ty)
        box = @changes.add_method_call_box(genv, recv, @mid, a_args, !@recv)

        if @block_body && @block_body.lenv.break_vtx
          ret = Vertex.new(self)
          @changes.add_edge(genv, box.ret, ret)
          @changes.add_edge(genv, @block_body.lenv.break_vtx, ret)
          ret
        else
          box.ret
        end
      end

      def block_last_stmt_code_range
        if @block_body
          if @block_body.is_a?(AST::StatementsNode)
            @block_body.stmts.last.code_range
          else
            @block_body.code_range
          end
        else
          nil
        end
      end

      def retrieve_at(pos, &blk)
        yield self if @mid_code_range && @mid_code_range.include?(pos)
        each_subnode do |subnode|
          next unless subnode
          subnode.retrieve_at(pos, &blk)
        end
      end

      def modified_vars(tbl, vars)
        subnodes.each do |key, subnode|
          next unless subnode
          if key == :block_body
            subnode.modified_vars(tbl - self.block_tbl, vars)
          elsif subnode.is_a?(AST::Node)
            subnode.modified_vars(tbl, vars)
          else
            subnode.each {|n| n.modified_vars(tbl, vars) }
          end
        end
      end
    end

block_last_stmt_code_range() click to toggle source

    # File typeprof-0.30.1/lib/typeprof/core/ast/call.rb, line 138
    def block_last_stmt_code_range
      if @block_body
        if @block_body.is_a?(AST::StatementsNode)
          @block_body.stmts.last.code_range
        else
          @block_body.code_range
        end
      else
        nil
      end
    end

install0(genv) click to toggle source

    # File typeprof-0.30.1/lib/typeprof/core/ast/call.rb, line 75
    def install0(genv)
      recv = @recv ? @recv.install(genv) : @yield ? @lenv.get_var(:"*given_block") : @lenv.get_var(:"*self")

      positional_args = @positional_args.map do |arg|
        arg.install(genv)
      end

      keyword_args = @keyword_args ? @keyword_args.install(genv) : nil

      if @block_body
        @lenv.locals.each {|var, vtx| @block_body.lenv.locals[var] = vtx }
        @block_tbl.each {|var| @block_body.lenv.locals[var] = Source.new(genv.nil_type) }
        @block_body.lenv.locals[:"*self"] = @block_body.lenv.cref.get_self(genv)

        blk_f_args = []
        if @block_f_args
          @block_f_args.each do |arg|
            blk_f_args << @block_body.lenv.new_var(arg, self)
          end
        end

        @lenv.locals.each do |var, vtx|
          @block_body.lenv.set_var(var, vtx)
        end
        vars = []
        @block_body.modified_vars(@lenv.locals.keys - @block_tbl, vars)
        vars.uniq!
        vars.each do |var|
          vtx = @lenv.get_var(var)
          nvtx = vtx.new_vertex(genv, self)
          @lenv.set_var(var, nvtx)
          @block_body.lenv.set_var(var, nvtx)
        end

        e_ret = @block_body.lenv.locals[:"*expected_block_ret"] = Vertex.new(self)
        @block_body.install(genv)
        @block_body.lenv.add_next_box(@changes.add_escape_box(genv, @block_body.ret, e_ret))

        vars.each do |var|
          @changes.add_edge(genv, @block_body.lenv.get_var(var), @lenv.get_var(var))
        end

        blk_f_ary_arg = Vertex.new(self)
        @changes.add_masgn_box(genv, blk_f_ary_arg, blk_f_args, nil, nil) # TODO: support splat "do |a, *b, c|"
        block = Block.new(self, blk_f_ary_arg, blk_f_args, @block_body.lenv.next_boxes)
        blk_ty = Source.new(Type::Proc.new(genv, block))
      elsif @block_pass
        blk_ty = @block_pass.install(genv)
      end

      a_args = ActualArguments.new(positional_args, @splat_flags, keyword_args, blk_ty)
      box = @changes.add_method_call_box(genv, recv, @mid, a_args, !@recv)

      if @block_body && @block_body.lenv.break_vtx
        ret = Vertex.new(self)
        @changes.add_edge(genv, box.ret, ret)
        @changes.add_edge(genv, @block_body.lenv.break_vtx, ret)
        ret
      else
        box.ret
      end
    end

modified_vars(tbl, vars) click to toggle source

    # File typeprof-0.30.1/lib/typeprof/core/ast/call.rb, line 158
    def modified_vars(tbl, vars)
      subnodes.each do |key, subnode|
        next unless subnode
        if key == :block_body
          subnode.modified_vars(tbl - self.block_tbl, vars)
        elsif subnode.is_a?(AST::Node)
          subnode.modified_vars(tbl, vars)
        else
          subnode.each {|n| n.modified_vars(tbl, vars) }
        end
      end
    end

retrieve_at(pos) { |self| ... } click to toggle source

    # File typeprof-0.30.1/lib/typeprof/core/ast/call.rb, line 150
    def retrieve_at(pos, &blk)
      yield self if @mid_code_range && @mid_code_range.include?(pos)
      each_subnode do |subnode|
        next unless subnode
        subnode.retrieve_at(pos, &blk)
      end
    end

subnodes(= { recv:, positional_args:, keyword_args:, block_body:, block_pass: }) click to toggle source

    # File typeprof-0.30.1/lib/typeprof/core/ast/call.rb, line 72
        def subnodes = { recv:, positional_args:, keyword_args:, block_body:, block_pass: }
        def attrs = { mid:, splat_flags:, block_tbl:, block_f_args:, yield: }

        def install0(genv)
          recv = @recv ? @recv.install(genv) : @yield ? @lenv.get_var(:"*given_block") : @lenv.get_var(:"*self")

          positional_args = @positional_args.map do |arg|
            arg.install(genv)
          end

          keyword_args = @keyword_args ? @keyword_args.install(genv) : nil

          if @block_body
            @lenv.locals.each {|var, vtx| @block_body.lenv.locals[var] = vtx }
            @block_tbl.each {|var| @block_body.lenv.locals[var] = Source.new(genv.nil_type) }
            @block_body.lenv.locals[:"*self"] = @block_body.lenv.cref.get_self(genv)

            blk_f_args = []
            if @block_f_args
              @block_f_args.each do |arg|
                blk_f_args << @block_body.lenv.new_var(arg, self)
              end
            end

            @lenv.locals.each do |var, vtx|
              @block_body.lenv.set_var(var, vtx)
            end
            vars = []
            @block_body.modified_vars(@lenv.locals.keys - @block_tbl, vars)
            vars.uniq!
            vars.each do |var|
              vtx = @lenv.get_var(var)
              nvtx = vtx.new_vertex(genv, self)
              @lenv.set_var(var, nvtx)
              @block_body.lenv.set_var(var, nvtx)
            end

            e_ret = @block_body.lenv.locals[:"*expected_block_ret"] = Vertex.new(self)
            @block_body.install(genv)
            @block_body.lenv.add_next_box(@changes.add_escape_box(genv, @block_body.ret, e_ret))

            vars.each do |var|
              @changes.add_edge(genv, @block_body.lenv.get_var(var), @lenv.get_var(var))
            end

            blk_f_ary_arg = Vertex.new(self)
            @changes.add_masgn_box(genv, blk_f_ary_arg, blk_f_args, nil, nil) # TODO: support splat "do |a, *b, c|"
            block = Block.new(self, blk_f_ary_arg, blk_f_args, @block_body.lenv.next_boxes)
            blk_ty = Source.new(Type::Proc.new(genv, block))
          elsif @block_pass
            blk_ty = @block_pass.install(genv)
          end

          a_args = ActualArguments.new(positional_args, @splat_flags, keyword_args, blk_ty)
          box = @changes.add_method_call_box(genv, recv, @mid, a_args, !@recv)

          if @block_body && @block_body.lenv.break_vtx
            ret = Vertex.new(self)
            @changes.add_edge(genv, box.ret, ret)
            @changes.add_edge(genv, @block_body.lenv.break_vtx, ret)
            ret
          else
            box.ret
          end
        end

        def block_last_stmt_code_range
          if @block_body
            if @block_body.is_a?(AST::StatementsNode)
              @block_body.stmts.last.code_range
            else
              @block_body.code_range
            end
          else
            nil
          end
        end

        def retrieve_at(pos, &blk)
          yield self if @mid_code_range && @mid_code_range.include?(pos)
          each_subnode do |subnode|
            next unless subnode
            subnode.retrieve_at(pos, &blk)
          end
        end

        def modified_vars(tbl, vars)
          subnodes.each do |key, subnode|
            next unless subnode
            if key == :block_body
              subnode.modified_vars(tbl - self.block_tbl, vars)
            elsif subnode.is_a?(AST::Node)
              subnode.modified_vars(tbl, vars)
            else
              subnode.each {|n| n.modified_vars(tbl, vars) }
            end
          end
        end
      end

      class CallNode < CallBaseNode
        def initialize(raw_node, lenv)
          recv = raw_node.receiver ? AST.create_node(raw_node.receiver, lenv) : nil
          mid = raw_node.name
          mid_code_range = TypeProf::CodeRange.from_node(raw_node.message_loc) if raw_node.message_loc
          raw_args = raw_node.arguments
          raw_block = raw_node.block
          super(raw_node, recv, mid, mid_code_range, raw_args, nil, raw_block, lenv)
        end
      end

      class SuperNode < CallBaseNode
        def initialize(raw_node,  lenv)
          raw_args = raw_node.arguments
          raw_block = raw_node.block
          super(raw_node, nil, :"*super", nil, raw_args, nil, raw_block, lenv)
        end
      end

      class ForwardingSuperNode < CallBaseNode
        def initialize(raw_node,  lenv)
          raw_args = nil # TODO: forward args properly
          raw_block = raw_node.block
          super(raw_node, nil, :"*super", nil, raw_args, nil, raw_block, lenv)
        end
      end

      class YieldNode < CallBaseNode
        def initialize(raw_node, lenv)
          raw_args = raw_node.arguments
          super(raw_node, nil, :call, nil, raw_args, nil, nil, lenv)
        end
      end

      class OperatorNode < CallBaseNode
        def initialize(raw_node, recv, lenv)
          mid = raw_node.binary_operator
          mid_code_range = TypeProf::CodeRange.from_node(raw_node.binary_operator_loc)
          last_arg = AST.create_node(raw_node.value, lenv)
          super(raw_node, recv, mid, mid_code_range, nil, last_arg, nil, lenv)
        end
      end

      class IndexReadNode < CallBaseNode
        def initialize(raw_node, lenv)
          recv = AST.create_node(raw_node.receiver, lenv)
          mid = :[]
          mid_code_range = nil
          raw_args = raw_node.arguments
          super(raw_node, recv, mid, mid_code_range, raw_args, nil, nil, lenv)
        end
      end

      class IndexWriteNode < CallBaseNode
        def initialize(raw_node, rhs, lenv)
          recv = AST.create_node(raw_node.receiver, lenv)
          mid = :[]=
          mid_code_range = nil
          raw_args = raw_node.arguments
          @rhs = rhs
          super(raw_node, recv, mid, mid_code_range, raw_args, rhs, nil, lenv)
        end

        attr_reader :rhs
      end

      class CallReadNode < CallBaseNode
        def initialize(raw_node, lenv)
          recv = AST.create_node(raw_node.receiver, lenv)
          mid = raw_node.read_name
          mid_code_range = TypeProf::CodeRange.from_node(raw_node.message_loc)
          super(raw_node, recv, mid, mid_code_range, nil, nil, nil, lenv)
        end
      end

      class CallWriteNode < CallBaseNode
        def initialize(raw_node, rhs, lenv)
          recv = AST.create_node(raw_node.receiver, lenv)
          mid = raw_node.is_a?(Prism::CallTargetNode) ? raw_node.name : raw_node.write_name
          mid_code_range = TypeProf::CodeRange.from_node(raw_node.message_loc)
          @rhs = rhs
          super(raw_node, recv, mid, mid_code_range, nil, rhs, nil, lenv)
        end

        attr_reader :rhs
      end
    end