class Bud::PushApplyMethod
A push-based dataflow element that applies a method to a lattice value
Constants
- SOURCE_TYPES
Public Class Methods
new(bud_instance, recv, meth, args, blk)
click to toggle source
Calls superclass method
Bud::LatticePushElement::new
# File lib/bud/lattice-core.rb, line 282 def initialize(bud_instance, recv, meth, args, blk) super(bud_instance) @recv = recv @meth = meth @blk = blk @args = args.dup @is_morph = Bud::Lattice.global_morphs.include? @meth @recv_is_scanner = @recv.kind_of? Bud::LatticeScanner recv.wire_to(self, :output) bud_instance.push_elems[[self.object_id, recv, meth, blk]] = self # Arguments that are normal Ruby values are assumed to remain invariant as # rule evaluation progresses; hence, we just pass along those values when # invoking the function. Arguments that are derived from lattices or # collections might change; hence, we need to wire up the push dataflow to # have the current values of the function's arguments passed to this node. # Map from input node to a list of indexes; the indexes identify the # positions in the args array that should be filled with the node's value @input_sources = {} # Similarly, map from input node to a cached value -- this is the last value # we've seen from this input. If the input gave us a delta, we merge # together all the deltas we've seen and cache the resulting value. XXX: In # the common case that the input is a scanner over a lattice wrapper, this # means we do redundant work merging together deltas. @input_caches = {} # Inputs for which we haven't seen a value yet. @waiting_for_input = Set.new @recv_cache = nil @seen_recv = false @args.each_with_index do |a, i| if SOURCE_TYPES.any?{|s| a.kind_of? s} if a.kind_of? Bud::LatticeWrapper a = a.to_push_elem end a.wire_to(self, :output) @input_sources[a] ||= [] @input_sources[a] << i @waiting_for_input << a @args[i] = nil # Substitute actual value before calling method end end @seen_all_inputs = @waiting_for_input.empty? end
Public Instance Methods
insert(v, source)
click to toggle source
# File lib/bud/lattice-core.rb, line 332 def insert(v, source) if source == @recv if @seen_recv # Update the cached value for the method receiver. Note that if we're # applying a method directly to a LatticeScanner (i.e., method applied # to lattice wrapper), we can avoid maintaining a separate cache and # instead use the wrapper's current value. if @recv_is_scanner @recv_cache = @recv.collection.current_value else @recv_cache = @recv_cache.merge(v) end else @recv_cache = v end @seen_recv = true if @seen_all_inputs if @is_morph recv_val = v else recv_val = @recv_cache end res = recv_val.send(@meth, *@args, &@blk) push_out(res) end else arg_indexes = @input_sources[source] raise Bud::Error, "unknown input #{source}" if arg_indexes.nil? arg_val = v unless @is_morph if @input_caches[source] arg_val = @input_caches[source].merge(arg_val) end end arg_indexes.each do |i| @args[i] = arg_val end unless @seen_all_inputs @waiting_for_input.delete(source) @seen_all_inputs = @waiting_for_input.empty? end if @seen_all_inputs && @seen_recv res = @recv_cache.send(@meth, *@args, &@blk) push_out(res) end if @input_caches.has_key? source @input_caches[source] = @input_caches[source].merge(v) else @input_caches[source] = v end arg_indexes.each do |i| @args[i] = @input_caches[source] end end end
inspect()
click to toggle source
# File lib/bud/lattice-core.rb, line 391 def inspect "#{super} [#{@meth}]" end