# # ActiveFacts CQL Parser. # Parse rules relating to Concept definitions. # # Copyright (c) 2009 Clifford Heath. Read the LICENSE file. # module ActiveFacts module CQL grammar Concepts rule concept value_type / entity_type / named_fact_type / anonymous_fact_type end rule entity_type s term_definition_name sup:(basetype / subtype) &{|e| input.context.entity_type(e[1].value); true } mapping_pragmas ec:entity_conditions? ';' s { def defined_type [ :entity_type, sup.supers, sup.identifier, mapping_pragmas.value, (ec.empty? ? nil : ec.conditions) ] end def value [ term_definition_name.value, defined_type ] end } end rule basetype is s # independency? identification { def supers; [] end def identifier; identification.value; end } end rule subtype subtype_prefix # independency? supertype_list ident:identification? { def supers; supertype_list.value; end def identifier; ident.empty? ? nil : ident.value; end } end # REVISIT: This doesn't work, and I don't know why. rule independency ('independent' S / 'separate' S / 'partitioned' S) end rule supertype_list primary:id s alternate_supertypes:( ',' s !identified_by name:id s )* { def value [primary.value]+alternate_supertypes.elements.map{|sup| sup.name.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 value_type_parameters r:(restriction enforcement)? # Reference Mode; restriction may be needed for the ValueType { def value { :mode => id.value, :restriction => (r.text_value.empty? ? nil : r.restriction.ranges), :enforcement => (r.text_value.empty? ? nil : r.enforcement.value), :parameters => value_type_parameters.values } 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.value]) + tail.elements.map{|e| e.role_player_id.value } + (t.empty? ? [] : [t.role_player_id.value]) end } end rule role_player_id !(role_list_sep / quantifier) id { def value; id.value; end } 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 mapping_pragmas '[' s h:mapping_pragma t:(s ',' s mapping_pragma)* s ']' s { def value; [h.value] + t.elements.map{|e| e.mapping_pragma.value}; end } / '' { def value; []; end } end rule mapping_pragma (independent / separate / partitioned / personal / feminine / masculine) { def value; text_value; end } end rule entity_conditions (':' / where) s c:conditions? { def conditions c.empty? ? [] : c.condition_list end } end end end end