require 'lib/semantic_types'
module Semantic
AttrEdgeStruct = Struct.new( 'AttrEdgeStruct', :dependencies, :result, :func )
class AttrEdge < AttrEdgeStruct
def is_executable?
( dependencies.detect { |d| d.class == AttrKey } ).nil?
end
def exec_func
func.call( dependencies )
end
def AttrEdge.create( parent_token, child_tokens, attr_fn )
tokens = [ parent_token ].concat( child_tokens )
dependencies = attr_fn.args.map do |ref|
if ref.attr_idx == AttrIndexText
tokens[ ref.node_idx ].data
else
AttrKey.new( tokens[ ref.node_idx ].object_id, ref.attr_idx )
end
end
result = AttrKey.new( tokens[ attr_fn.target.node_idx ].object_id, attr_fn.target.attr_idx )
return AttrEdge.new( dependencies, result, attr_fn.func )
end
def substitute_deps attr_hash
dependencies.map! do |arg|
if arg.class == AttrKey
attr = attr_hash.fetch( arg, nil )
attr.nil? ? arg : attr
else
arg
end
end
end
end
class Edges < Array
def reduce_batch( attr_hash )
Edges.reduce_batch( self, attr_hash )
end
def Edges.reduce_batch( edges, attr_hash )
edges.each { |e| e.substitute_deps( attr_hash ) }
new_hash = {}
loop do
removal = []
edges.each do |e|
e.substitute_deps( new_hash )
next unless e.is_executable?
new_hash[ e.result ] = e.exec_func
removal << e
end
break if removal.empty?
removal.each { |e| edges.delete e }
end
new_hash
end
end
end