Class: Rubinius::ToolSet.current::TS::AST::MultipleAssignment

Inherits:
Node
  • Object
show all
Defined in:
lib/rubinius/ast/variables.rb

Instance Attribute Summary collapse

Attributes inherited from Node

#line

Instance Method Summary collapse

Methods inherited from Node

#ascii_graph, #attributes, #children, match_arguments?, match_send?, #new_block_generator, #new_generator, #node_name, #or_bytecode, #pos, #set_child, transform, #transform, transform_comment, transform_kind, transform_kind=, transform_name, #value_defined, #visit, #walk

Constructor Details

#initialize(line, left, right, splat) ⇒ MultipleAssignment

Returns a new instance of MultipleAssignment.



546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
# File 'lib/rubinius/ast/variables.rb', line 546

def initialize(line, left, right, splat)
  @line = line
  @left = left
  @right = right
  @splat = nil
  @block = nil # support for |&b|
  @post = nil # in `a,*b,c`, c is in post.

  if splat.kind_of?(PostArg)
    @fixed = false
    @post = splat.rest
    splat = splat.into
  elsif right.kind_of?(ArrayLiteral)
    @fixed = right.body.size > 1
  else
    @fixed = false
  end

  if splat.kind_of? Node
    if @left
      if right
        @splat = SplatAssignment.new line, splat
      else
        @splat = SplatWrapped.new line, splat
      end
    elsif @fixed
      @splat = SplatArray.new line, splat, right.body.size
    elsif right.kind_of? SplatValue
      @splat = splat
    else
      @splat = SplatWrapped.new line, splat
    end
  elsif splat
    # We need a node for eg { |*| } and { |a, *| }
    size = @fixed ? right.body.size : 0
    @splat = EmptySplat.new line, size
  end
end

Instance Attribute Details

#blockObject

Returns the value of attribute block.



544
545
546
# File 'lib/rubinius/ast/variables.rb', line 544

def block
  @block
end

#leftObject

Returns the value of attribute left.



544
545
546
# File 'lib/rubinius/ast/variables.rb', line 544

def left
  @left
end

#postObject

Returns the value of attribute post.



544
545
546
# File 'lib/rubinius/ast/variables.rb', line 544

def post
  @post
end

#rightObject

Returns the value of attribute right.



544
545
546
# File 'lib/rubinius/ast/variables.rb', line 544

def right
  @right
end

#splatObject

Returns the value of attribute splat.



544
545
546
# File 'lib/rubinius/ast/variables.rb', line 544

def splat
  @splat
end

Instance Method Details

#bytecode(g, array_on_stack = false) ⇒ Object



650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
# File 'lib/rubinius/ast/variables.rb', line 650

def bytecode(g, array_on_stack=false)
  unless array_on_stack
    g.cast_array unless @right or (@splat and not @left)
  end

  declare_local_scope(g.state.scope)

  if @fixed
    pad_short(g) if @left and !@splat
    @right.body.each { |x| x.bytecode(g) }

    if @left
      make_retval(g)

      if @splat
        pad_short(g)
        make_array(g)
      end

      rotate(g)

      g.state.push_masgn
      @left.body.each do |x|
        x.bytecode(g)
        g.pop
      end
      g.state.pop_masgn

      pop_excess(g) unless @splat
    end
  else
    if @right
      if @right.kind_of? ArrayLiteral and @right.body.size == 1
        @right.body.first.bytecode(g)
        g.cast_multi_value
      else
        @right.bytecode(g)
      end

      g.cast_array unless @right.kind_of? ToArray
      g.dup # Use the array as the return value
    end

    if @left
      g.state.push_masgn
      @left.body.each do |x|
        g.shift_array
        g.cast_array if x.kind_of? MultipleAssignment and x.left
        x.bytecode(g)
        g.pop
      end
      g.state.pop_masgn
    end

    if @post
      g.state.push_masgn
      @post.body.each do |x|
        g.dup
        g.send :pop, 0
        g.cast_array if x.kind_of? MultipleAssignment and x.left
        x.bytecode(g)
        g.pop
      end
      g.state.pop_masgn
    end
  end

  if @splat
    g.state.push_masgn
    @splat.bytecode(g)

    # Use the array as the return value
    g.dup if @fixed and !@left

    g.state.pop_masgn
  end

  g.pop if @right and (!@fixed or @splat)
end

#declare_local_scope(scope) ⇒ Object



627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
# File 'lib/rubinius/ast/variables.rb', line 627

def declare_local_scope(scope)
  # Fix the scope for locals introduced by the left. We
  # do this before running the code for the right so that
  # right side sees the proper scoping of the locals on the left.

  if @left
    @left.body.each do |var|
      case var
      when LocalVariable
        scope.assign_local_reference var
      when MultipleAssignment
        var.declare_local_scope(scope)
      end
    end
  end

  if @splat and @splat.kind_of?(SplatAssignment)
    if @splat.value.kind_of?(LocalVariable)
      scope.assign_local_reference @splat.value
    end
  end
end

#defined(g) ⇒ Object



730
731
732
# File 'lib/rubinius/ast/variables.rb', line 730

def defined(g)
  g.push_literal "assignment"
end

#iter_argumentsObject



623
624
625
# File 'lib/rubinius/ast/variables.rb', line 623

def iter_arguments
  @iter_arguments = true
end

#make_array(g) ⇒ Object



598
599
600
601
# File 'lib/rubinius/ast/variables.rb', line 598

def make_array(g)
  size = @right.body.size - @left.body.size
  g.make_array size if size >= 0
end

#make_retval(g) ⇒ Object



603
604
605
606
607
608
609
610
611
612
# File 'lib/rubinius/ast/variables.rb', line 603

def make_retval(g)
  size = @right.body.size
  if @left and !@splat
    lhs = @left.body.size
    size = lhs if lhs > size
  end
  g.dup_many @right.body.size
  g.make_array @right.body.size
  g.move_down size
end

#pad_short(g) ⇒ Object



585
586
587
588
589
590
591
# File 'lib/rubinius/ast/variables.rb', line 585

def pad_short(g)
  short = @left.body.size - @right.body.size
  if short > 0
    short.times { g.push :nil }
    g.make_array 0 if @splat
  end
end

#pop_excess(g) ⇒ Object



593
594
595
596
# File 'lib/rubinius/ast/variables.rb', line 593

def pop_excess(g)
  excess = @right.body.size - @left.body.size
  excess.times { g.pop } if excess > 0
end

#rotate(g) ⇒ Object



614
615
616
617
618
619
620
621
# File 'lib/rubinius/ast/variables.rb', line 614

def rotate(g)
  if @splat
    size = @left.body.size + 1
  else
    size = @right.body.size
  end
  g.rotate size
end

#to_sexpObject



734
735
736
737
738
739
740
741
742
# File 'lib/rubinius/ast/variables.rb', line 734

def to_sexp
  left = @left ? @left.to_sexp : [:array]
  left << [:splat, @splat.to_sexp] if @splat
  left << @block.to_sexp if @block

  sexp = [:masgn, left]
  sexp << @right.to_sexp if @right
  sexp
end