module ActiveFacts module CQL grammar Concepts rule concept entity_type / data_type / named_fact_type / anonymous_fact_type end rule entity_type s name:id s sup:(basetype / subtype) ec:entity_conditions? ';' s { def value [ name.text_value, [ :entity_type, sup.supers, sup.identifier, ec.empty? ? nil : ec.conditions ] ] end } end rule subtype subtype_prefix supertype_list ident:identification? { def supers; supertype_list.value; end def identifier; ident.empty? ? nil : ident.value; end } end rule supertype_list primary:id s alternate_supertypes:( ',' s !identified_by name:id s )* { def value [primary.text_value]+alternate_supertypes.elements.map{|sup| sup.name.text_value} end } end rule basetype is s identification { def supers; [] end def identifier; identification.value; end } end rule identification # REVISIT: Consider distinguishing "-Id" from just "Id", and not prepending the entity type name if no "-" identified_by its s id s # Reference Mode { def value; {:mode => id.text_value }; end } / identified_by role_list { def value; {:roles => role_list.roles }; end } end # Identified by roles... also used for constraints, beware rule role_list head:role_player s tail:( ( and S / ',' s ) role:role_player s )* { def roles [head.value] + tail.elements.map{|i| i.role.value} end } end # We can't tell which word is an adjective and which is a concept here. # The concept might be forward-referenced, but not if adjectives are used. # REVISIT: This accepts double-adjective expressions (three words) but they don't work elsewhere rule lead_adj role_player_id '-' end rule trail_adj '-' role_player_id end rule role_player l:lead_adj? tail:(s role_player_id)+ s t:trail_adj? { def value (l.empty? ? [] : [l.role_player_id.text_value]) + tail.elements.map{|e| e.role_player_id.text_value } + (t.empty? ? [] : [t.role_player_id.text_value]) end } end rule role_player_id !(role_list_sep / quantifier) id end rule role_list_sep (where / and / 'occurs') end rule reference_mode # REVISIT: Adopt ORM2-style reference mode patterns here '(' s '.' s mode_name:id s ')' s end rule entity_conditions (':' / where) s c:conditions? { def conditions c.empty? ? [] : c.condition_list end } end end end end