lib/activefacts/cql/compiler/reading.rb in activefacts-0.8.8 vs lib/activefacts/cql/compiler/reading.rb in activefacts-0.8.9
- old
+ new
@@ -5,10 +5,13 @@
class Reading
attr_reader :phrases
attr_accessor :qualifiers, :context_note
attr_reader :fact_type, :reading, :role_sequence # These are the Metamodel objects
attr_reader :side_effects
+ attr_writer :fact_type # Assigned for a bare (existential) objectification fact
+ attr_accessor :fact # When binding fact instances the fact goes here
+ attr_accessor :objectified_as # The Reading::RoleRef which objectified this fact type
def initialize role_refs_and_words, qualifiers = [], context_note = nil
@phrases = role_refs_and_words
role_refs.each { |role_ref| role_ref.reading = self }
@qualifiers = qualifiers
@@ -25,10 +28,20 @@
@phrases.size == 1 and
@phrases[0].is_a?(RoleRef) and
!@phrases[0].literal
end
+ def display
+ "#{
+ @qualifiers && @qualifiers.size > 0 ? @qualifiers.inspect+' ' : nil
+ }#{
+ @phrases.map{|p| p.to_s }*" "
+ }#{
+ @context_note && ' '+@context_note.inspect
+ }"
+ end
+
def inspect
"#{@qualifiers && @qualifiers.size > 0 ? @qualifiers.inspect+' ' : nil}#{@phrases.map{|p|p.inspect}*" "}#{@context_note && ' '+@context_note.inspect}"
end
def identify_players_with_role_name context
@@ -46,11 +59,11 @@
role_ref.objectification_join.each{|reading| reading.identify_other_players(context)} if role_ref.objectification_join
end
end
def includes_literals
- role_refs.detect{|role_ref| role_ref.literal }
+ role_refs.detect{|role_ref| role_ref.literal || (ja = role_ref.objectification_join and ja.detect{|jr| jr.includes_literals })}
end
def bind_roles context
role_names = role_refs.map{ |role_ref| role_ref.role_name }.compact
@@ -83,10 +96,11 @@
# It returns nil if there is none, or a ReadingMatchSideEffects object if matched.
#
# As this match may not necessarily be used (depending on the side effects),
# no change is made to this Reading object - those will be done later.
def match_existing_fact_type context
+ raise "Internal error, reading already matched, should not match again" if @fact_type
rrs = role_refs
players = rrs.map{|rr| rr.player}
raise "Must identify players before matching fact types" if players.include? nil
raise "A fact type must involve at least one object type, but there are none in '#{inspect}'" if players.size == 0
@@ -95,17 +109,20 @@
debug :matching, "Looking for existing #{players.size}-ary fact types matching '#{inspect}'" do
debug :matching, "Players are '#{player_names.inspect}'"
# Match existing fact types in objectification joins first:
rrs.each do |role_ref|
- next unless objectification_join = role_ref.objectification_join && role_ref.objectification_join[0]
- objectified_fact_type =
- objectification_join.match_existing_fact_type(context)
- raise "Unrecognised fact type #{objectification_join.inspect} in #{self.class}" unless objectified_fact_type
- objectified_as = objectified_fact_type.entity_type
- raise "Fact type #{objectification_join.reading.expand} is not objectified as #{role_ref.inspect}" unless objectified_as || objectified_as != role_ref.player
- role_ref.objectification_of = objectified_fact_type
+ next unless joins = role_ref.objectification_join and !joins.empty?
+ role_ref.objectification_join.each do |oj|
+ ft = oj.match_existing_fact_type(context)
+ raise "Unrecognised fact type #{oj.display}" unless ft
+ if (ft && ft.entity_type == role_ref.player)
+ role_ref.objectification_of = ft
+ oj.objectified_as = role_ref
+ end
+ end
+ raise "#{role_ref.inspect} contains objectification joins that do not objectify it" unless role_ref.objectification_of
end
# For each role player, find the compatible types (the set of all subtypes and supertypes).
# For a player that's an objectification, we don't allow implicit supertype joins
player_related_types =
@@ -669,9 +686,19 @@
@literal && ' '+@literal.inspect }#{
@value_constraint && ' '+@value_constraint.inspect
}#{
@objectification_join ? "(where #{@objectification_join.inspect})" : ""
}>"
+ end
+
+ def to_s
+ "#{
+ @quantifier && @quantifier.inspect+' ' }#{
+ @leading_adjective && @leading_adjective.sub(/ |$/,'- ').sub(/ *$/,' ') }#{
+ @role_name || @term }#{
+ @trailing_adjective && ' '+@trailing_adjective.sub(/(.* |^)/, '\1-') }#{
+ @literal && ' '+@literal.inspect }#{
+ @value_constraint && ' '+@value_constraint.inspect }"
end
def <=>(other)
( 4*(@term <=> other.term) +
2*((@leading_adjective||'') <=> (other.leading_adjective||'')) +