Class: AttrNameRewriter

Inherits:
SexpProcessor
  • Object
show all
Defined in:
lib/bud/rewrite.rb

Overview

Rewrite named-column refs to positional refs

Instance Method Summary (collapse)

Constructor Details

- (AttrNameRewriter) initialize(bud_instance)

:nodoc: all



459
460
461
462
463
464
465
466
# File 'lib/bud/rewrite.rb', line 459

def initialize(bud_instance)
  super()
  self.require_empty = false
  self.expected = Sexp
  @iterhash ||= {}
  @collnames = []
  @bud_instance = bud_instance
end

Instance Method Details

- (Object) gather_collection_names(exp)



517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
# File 'lib/bud/rewrite.rb', line 517

def gather_collection_names(exp)
  # We expect a reference to a collection name to look like a function call
  # (nil receiver) with no arguments.
  if exp.sexp_type == :call and exp[1].nil? and exp.length == 3
    @collnames << exp[2]
  elsif exp.sexp_type == :call and exp[2] == :rename
    namelit = exp[3]
    @collnames << namelit[1]
  elsif exp.sexp_type == :call and [:group, :argagg].include?(exp[2])
    # For grouping and argagg expressions, only look at the receiver (the
    # collection we're grouping on); otherwise, we might mistakenly think some
    # of the arguments to the grouping operation are collection names.
    gather_collection_names(exp[1])
  else
    exp.each { |e| gather_collection_names(e) if e.class <= Sexp }
  end
end

- (Object) process_call(exp)



535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
# File 'lib/bud/rewrite.rb', line 535

def process_call(exp)
  call, recv, op, *args = exp

  if recv.class == Sexp and recv.sexp_type == :lvar and @iterhash[recv[1]]
    if @bud_instance.respond_to?(@iterhash[recv[1]])
      if @bud_instance.send(@iterhash[recv[1]]).class <= Bud::BudCollection
        cols = @bud_instance.send(@iterhash[recv[1]]).cols
        if op != :[] and @bud_instance.send(@iterhash[recv[1]]).respond_to?(op)
          # if the op is an attribute name in the schema, col_idx is its index
          col_idx = cols.index(op) unless cols.nil?
          unless col_idx.nil?
            op = :[]
            args = [s(:lit, col_idx)]
          end
        end
      end
      return s(call, recv, op, *args)
    end
  end
  return s(call, process(recv), op, *(args.map{|a| process(a)}))
end

- (Object) process_iter(exp)

some icky special-case parsing to find mapping between collection names and iter vars



470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
# File 'lib/bud/rewrite.rb', line 470

def process_iter(exp)
  if exp[1] and exp[1][0] == :call
    return exp unless exp[2]
    gather_collection_names(exp[1])
    meth_name = exp[1][2]

    # now find iter vars and match up
    if exp[2][0] == :args and @collnames.size == 1 # single-table iter
      if @iterhash[exp[2][1]]
        raise Bud::CompileError, "redefinition of block variable \"#{exp[2][1]}\" not allowed"
      end

      # XXX: The BudChannel#payloads method assigns the correct schema to
      # tuples that pass through it (i.e., it omits the location specifier);
      # hence we don't want to apply the location rewrite to the code block
      # that is passed to payloads(). This is a dirty hack.
      unless meth_name == :payloads
        @iterhash[exp[2][1]] = @collnames[0]
      end
    elsif exp[2][0] == :args and not @collnames.empty? # join iter with lefts/rights
      case meth_name
      when :lefts
        @iterhash[exp[2][1]] = @collnames[0]
      when :rights
        @iterhash[exp[2][1]] = @collnames[1]
      when :reduce
        unless @collnames.length == 1
          raise Bud::CompileError, "reduce should only have one associated collection, but has #{@collnames.inspect}"
        end
        @iterhash[exp[2][1]] = @collnames[0]
      else
        # join
        if @iterhash[exp[2][1]]
          raise Bud::CompileError, "redefinition of block variable \"#{exp[2][1]}\" not allowed"
        end

        @collnames.each_with_index do |c,i|
          next unless exp[2][i+1]
          @iterhash[exp[2][i+1]] = c
        end
      end
    end
  end
  (1..(exp.length-1)).each {|i| exp[i] = process(exp[i])}
  exp
end