def match_internal(pat_element, test_element, visited, check_later)
return true if visited[test_element]
visited[test_element] = true
unless pat_element.class == test_element.class
match_failed(nil, "wrong class: #{pat_element.class} vs #{test_element.class}")
return false
end
all_structural_features(pat_element).each do |f|
pat_values = pat_element.getGeneric(f.name)
pat_values = [ pat_values ] unless pat_values.is_a?(Array)
test_values = test_element.getGeneric(f.name)
test_values = [ test_values] unless test_values.is_a?(Array)
if pat_values.size == 1 && pat_values.first.is_a?(Bindable) && pat_values.first._many?
unless match_many_bindable(pat_values.first, test_values)
return false
end
else
unless pat_values.size == test_values.size
match_failed(f, "wrong size #{pat_values.size} vs. #{test_values.size}")
return false
end
pat_values.each_with_index do |pv,i|
tv = test_values[i]
if pv.is_a?(Lazy)
check_later << CheckLater.new(f, pv, tv)
elsif pv.is_a?(Bindable)
if pv._bound?
unless pv._value == tv
match_failed(f, "value does not match bound value #{pv._value.class}:#{pv._value.object_id} vs. #{tv.class}:#{tv.object_id}")
return false
end
else
pv._bind(tv)
end
else
if f.is_a?(RGen::ECore::EAttribute)
unless pv == tv
match_failed(f, "wrong attribute value")
return false
end
else
if pv.is_a?(Proxy)
unless pv._target.object_id == tv.object_id
match_failed(f, "wrong target object")
return false
end
else
unless both_nil_or_match(pv, tv, visited, check_later)
return false
end
end
end
end
end
end
end
true
end