require 'shared_token_grammar' require 'open_ehr/assumed_library_types' require 'open_ehr/am/archetype/constraint_model' require 'cadl_node' module OpenEHR module Parser grammar CADL # include OpenEHR::Parser::CADL rule V_CADL_TEXT c_complex_object '' { def value c_complex_object.value end } / assertions '' { def value assertions.value end } end rule c_complex_object head:c_complex_object_head SYM_MATCHES SYM_START_CBLOCK body:c_complex_object_body SYM_END_CBLOCK { def value(node = ArchetypeNode.new) args = head.value args[:occurrences] ||= OpenEHR::AssumedLibraryTypes::Interval.new( :lower => 1, :upper => 1) node.id = args[:node_id] if node.root? args[:path] = '/' else args[:path] = node.path + '[' + args[:node_id] + ']' end args.update body.value(node) OpenEHR::AM::Archetype::ConstraintModel::CComplexObject.new(args) end } / c_complex_object_head '' { def value(node = ArchetypeNode.new) args = c_complex_object_head.value args[:occurrences] ||= OpenEHR::AssumedLibraryTypes::Interval.new( :lower => 1, :upper => 1) if node.root? node.path = '/' else node.id = args[:node_id] p args[:rm_type_name] node.path += '[' + args[:node_id] + ']' end OpenEHR::AM::Archetype::ConstraintModel::CComplexObject.new(args) end } end rule c_complex_object_head c_complex_object_id c_occurrences { def value c_complex_object_id.value.update c_occurrences.value c_complex_object_id.value end } / c_complex_object_id '' { def value c_complex_object_id.value end } end rule c_complex_object_id ti:type_identifier lo:V_LOCAL_TERM_CODE_REF space { def value {:rm_type_name => ti.value, :node_id => lo.value} end } / ti:type_identifier space { def value {:rm_type_name => ti.value} end } end rule c_complex_object_body c_any '' { def value(node) {:any_allowed? => true} end } / c_attributes '' { def value(node = nil) {:attributes => c_attributes.value(node), :any_allowed? => false} end } end rule c_object c_complex_object '' { def value(node) c_complex_object.value(node) end } / archetype_slot '' { def value(node) archetype_slot.value(node) end } / archetype_internal_ref '' { def value(node = nil) archetype_internal_ref.value(node) end } / constraint_ref '' { def value(node = nil) constraint_ref.value end } / c_primitive_object '' { def value(node = nil) c_primitive_object.value end } / V_C_DOMAIN_TYPE '' { def value(node = nil) p elemetns end } # / ERR_V_C_DOMAIN_TYPE end rule archetype_internal_ref SYM_USE_NODE type_identifier c_occurrences object_path space { def value(node) OpenEHR::AM::Archetype::ConstraintModel::ArchetypeInternalRef.new( :rm_type_name => type_identifier.value, :occurrences => c_occurrences.value, :path => node.path, :target_path => object_path.value) end } / SYM_USE_NODE type_identifier object_path space { def value(node = nil) OpenEHR::AM::Archetype::ConstraintModel::ArchetypeInternalRef.new( :rm_type_name => type_identifier.value, :occurrences => OpenEHR::AssumedLibraryTypes::Interval.new( :lower => 1, :upper => 1), :path => node.path, :target_path => object_path.value) end } end rule archetype_slot c_archetype_slot_head SYM_MATCHES SYM_START_CBLOCK c_includes c_excludes SYM_END_CBLOCK { def value(node = nil) args = c_archetype_slot_head.value args[:includes] = c_includes.value args[:excludes] = c_excludes.value args[:path] = node.path OpenEHR::AM::Archetype::ConstraintModel::ArchetypeSlot.new(args) end } / c_archetype_slot_head SYM_MATCHES SYM_START_CBLOCK c_includes SYM_END_CBLOCK { def value(node = nil) args = c_archetype_slot_head.value args[:includes] = c_includes.value args[:path] = node.path OpenEHR::AM::Archetype::ConstraintModel::ArchetypeSlot.new(args) end } / c_archetype_slot_head SYM_MATCHES SYM_START_CBLOCK c_excludes SYM_END_CBLOCK { def value(node = nil) args = c_archetype_slot_head.value args[:excludes] = c_excludes.value args[:path] = node.path OpenEHR::AM::Archetype::ConstraintModel::ArchetypeSlot.new(args) end } end rule c_archetype_slot_head c_archetype_slot_id white_space c_occurrences { def value args = c_archetype_slot_id.value args[:occurrences] = c_occurrences.value args end } / c_archetype_slot_id white_space { def value c_archetype_slot_id.value end } end rule c_archetype_slot_id SYM_ALLOW_ARCHETYPE type_identifier V_LOCAL_TERM_CODE_REF { def value {:rm_type_name => type_identifier.value, :node_id => V_LOCAL_TERM_CODE_REF.value} end } / SYM_ALLOW_ARCHETYPE type_identifier { def value {:rm_type_name => type_identifier.value} end } end rule c_primitive_object c_primitive '' { def value c_primitive.value end } end rule c_primitive c_integer '' { def value c_integer.value end } / c_real '' { def value c_real.value end } / c_date '' { def value c_date.value end } / c_time '' { def value c_time.value end } / c_date_time '' { def value c_date_time.value end } / c_duration '' { def value c_duration.value end } / c_string '' { def value c_string.value end } / c_boolean '' { def value c_boolean.value end } end rule c_any '*' space end rule c_attributes c_attribute more_attr:(c_attribute white_space)* { def value(node) attributes.map {|c| c.value(node)} end def attributes [c_attribute] + more_attr.elements.map {|e| e.c_attribute} end } end rule c_attribute c_attr_head c_attr_body { def value(node) val = c_attr_head.value(node) child_node = ArchetypeNode.new(node) child_node.path = val.path val.children = c_attr_body.value(child_node) val end } end rule c_attr_head id:(V_ATTRIBUTE_IDENTIFIER) white_space c_existence c_cardinality { def value(node) path = (node.root? ? '/' : (node.path + "[#{node.id}]" + '/')) + id.value OpenEHR::AM::Archetype::ConstraintModel::CMultipleAttribute.new( :rm_attribute_name => id.value, :path => path, :existence => c_existence.value, :cardinality => c_cardinality.value) end } / id:V_ATTRIBUTE_IDENTIFIER white_space c_existence { def value(node) path = (node.root? ? '/' : (node.path + "[#{node.id}]" + '/')) + id.value OpenEHR::AM::Archetype::ConstraintModel::CSingleAttribute.new( :rm_attribute_name => id.value, :path => path, :existence => c_existence.value) end } / id:(V_ATTRIBUTE_IDENTIFIER) white_space c_cardinality { def value(node) path = (node.root? ? '/' : (node.path + "[#{node.id}]" + '/')) + id.value OpenEHR::AM::Archetype::ConstraintModel::CMultipleAttribute.new( :rm_attribute_name => id.value, :path => path, :cardinality => c_cardinality.value) end } / id:(V_ATTRIBUTE_IDENTIFIER) white_space { def value(node) path = (node.root? ? '/' : (node.path + "[#{node.id}]" + '/')) + id.value OpenEHR::AM::Archetype::ConstraintModel::CSingleAttribute.new( :rm_attribute_name => id.value, :path => path) end } end rule c_attr_body SYM_MATCHES SYM_START_CBLOCK c_attr_values SYM_END_CBLOCK { def value(node) c_attr_values.value(node) end } end rule c_attr_values c_any '' { def value(node) c_any.value end } / c_object more_co:(c_object '')* { def value(node) c_objects.map {|c| c.value(node)} end def c_objects [c_object] + more_co.elements.map {|e| e.c_object } end } end rule c_includes SYM_INCLUDE assertions { def value assertions.value end } end rule c_excludes SYM_EXCLUDE assertions { def value assertions.value end } end rule c_existence SYM_EXISTENCE SYM_MATCHES SYM_START_CBLOCK existence_spec SYM_END_CBLOCK { def value existence_spec.value end } end rule existence_spec lo:V_INTEGER SYM_ELLIPSIS up:V_INTEGER { def value OpenEHR::AssumedTypesLibrary::Interval.new(:lower => lo.value, :upper => up.value) end } / V_INTEGER '' { def value OpenEHR::AssumedTypesLibrary::Interval.new(:lower => V_INTEGER.value, :upper => V_INTEGER.value) end } end rule c_cardinality SYM_CARDINALITY SYM_MATCHES SYM_START_CBLOCK cardinality_spec SYM_END_CBLOCK { def value cardinality_spec.value end } end rule cardinality_spec occurrence_spec ';' white_space SYM_ORDERED ';' white_space SYM_UNIQUE { def value OpenEHR::AM::Archetype::ConstraintModel::Cardinality.new( :interval => occurrence_spec.value, :is_unique => true, :is_orderd => true) end } / occurrence_spec ';' white_space SYM_ORDERED { def value OpenEHR::AM::Archetype::ConstraintModel::Cardinality.new( :interval => occurrence_spec.value, :is_orderd => true) end } / occurrence_spec ';' white_space SYM_UNORDERD ';' white_space SYM_UNIQUE { def value OpenEHR::AM::Archetype::ConstraintModel::Cardinality.new( :interval => occurrence_spec.value, :is_unique => true, :is_orderd => false) end } / occurrence_spec ';' white_space SYM_UNORDERD { def value OpenEHR::AM::Archetype::ConstraintModel::Cardinality.new( :interval => occurrence_spec.value, :is_orderd => false) end } / occurrence_spec SYM_UNIQUE ';' white_space SYM_ORDERED { def value OpenEHR::AM::Archetype::ConstraintModel::Cardinality.new( :interval => occurrence_spec.value, :is_unique => true, :is_orderd => true) end } / occurrence_spec SYM_UNIQUE ';' white_space SYM_UNORDERD { def value OpenEHR::AM::Archetype::ConstraintModel::Cardinality.new( :interval => occurrence_spec.value, :is_unique => true, :is_ordered => false) end } / occurrence_spec SYM_UNIQUE { def value OpenEHR::AM::Archetype::ConstraintModel::Cardinality.new( :interval => occurrence_spec.value, :is_unique => true) end } end rule c_occurrences SYM_OCCURRENCES SYM_MATCHES SYM_START_CBLOCK occurrence_spec SYM_END_CBLOCK { def value occurrence_spec.value end } end rule occurrence_spec st:(V_INTEGER) SYM_ELLIPSIS ed:cardinality_limit_value { def value if ed.value == '*' interval = OpenEHR::AssumedLibraryTypes::Interval.new( :lower => st.value, :upper_unbounded => true) else interval = OpenEHR::AssumedLibraryTypes::Interval.new( :lower => st.value, :upper => ed.value) end end } / cardinality_limit_value '' { def value OpenEHR::AssumedLibraryTypes::Interval.new( :lower => cardinality_limit_value.value, :upper => cardinality_limit_value.value) end } end rule cardinality_limit_value integer_value { def value text_value.to_i end } / '*' { def value '*' end } end rule c_integer_spec cardinality_limit_value '' { def value cardinality_limit_value.value end } / integer_list_value '' { def value integer_list_value.value end } / integer_interval_value '' { def value integer_interval_value.value end } / occurrence_spec { def value occurrence_spec.value end } end rule c_integer c_integer_spec (';' integer_value)? end rule c_real_spec real_value / real_list_value / real_interval_value end rule c_real c_real_spec (';' real_value)? end rule c_date_constraint V_ISO8601_DATE_CONSTRAINT_PATTERN / date_value / date_interval_value end rule c_date c_date_constraint (';' date_value)? end rule c_time_constraint V_ISO8601_TIME_CONSTRAINT_PATTERN / time_value / time_interval_value end rule c_time c_time_constraint (';' time_value)? end rule c_date_time_constraint V_ISO8601_DATE_TIME_CONSTRAINT_PATTERN / date_time_value / date_time_interval_value end rule c_date_time c_date_time_constraint / c_date_time_constraint ';' date_time_value end rule c_duration_constraint duration_pattern ('/' duration_interval_pattern)? / duration_value / duration_interval_value end rule duration_pattern V_ISO8601_TIME_CONSTRAINT_PATTERN end rule c_duration c_duration_constraint (';' duration_value)? end rule c_string_spec string_list_value ',' SYM_LIST_CONTINUE { def value OpenEHR::AM::Archetype::ConstraintModel::Primitive::CString.new( :list => string_list_value.value) end } / string_list_value '' { def value OpenEHR::AM::Archetype::ConstraintModel::Primitive::CString.new( :list => string_list_value.value, :type => 'Boolean') end } / pat:V_REGEXP '' { def value OpenEHR::AM::Archetype::ConstraintModel::Primitive::CString.new( :pattern => pat.value, :type => 'Boolean') end } / str:V_STRING '' { def value OpenEHR::AM::Archetype::ConstraintModel::Primitive::CString.new( :list => [str.value]) end } end rule c_string c_string_spec (';' string_value)? { def value c_string_spec.value end } end rule c_boolean_spec SYM_TRUE (',' SYM_FALSE)? { } / SYM_FALSE (',' SYM_TRUE)? end rule c_boolean c_boolean_spec ';' boolean_value { def value c_boolean_spec.value end } / c_boolean_spec '' { def value c_boolean_spec.value end } end rule constraint_ref V_LOCAL_TERM_CODE_REF '' { def value V_LOCAL_TERM_CODE_REF.value end } end rule V_REGEXP (('=' / '!') '~')? (('/' ('\/' / !'/' .)* '/') / ('^' (!'^' .)* '^') ) { def value text_value end } end rule V_C_DOMAIN_TYPE '('? [A-Z] IDCHAR* ')'? [ \n]* '<' [^>]* '>' end # assertion block rule V_ASSERTION_TEXT assertions '' { def value assertions.value end } end rule assertions assertion more_a:(assertion '')* { def value assertions.map {|a| a.value} end def assertions [assertion] + more_a.elements.map {|a| a.assertion} end } end rule assertion id:(any_identifier ':')? boolean_expression space { def value if (id && !id.empty?) OpenEHR::AM::Archetype::Assertion::Assertion.new( :tag => id.value, :expression => boolean_expression.value) else OpenEHR::AM::Archetype::Assertion::Assertion.new( :expression => boolean_expression.value) end end } end rule boolean_expression boolean_node '' { def value boolean_node.value end } end rule boolean_node SYM_EXISTS absolute_path { def value {:operator => OpenEHR::AM::Archetype::Assertion::OperatorKind::OP_EXISTS, :path => absolute_path.value } end } / relative_path white_space SYM_MATCHES SYM_START_CBLOCK c_primitive SYM_END_CBLOCK { def value OpenEHR::AM::Archetype::Assertion::ExprLeaf.new( :item => c_primitive.value, :type => c_primitive.value.type, :path => relative_path.value, :reference_type => 'constraint') end } / SYM_NOT boolean_leaf { def value boolean_leaf.value end } / arithmetic_expression (SYM_EQ / SYM_NE / SYM_LT / SYM_GT / SYM_LE / SYM_GE) arithmetic_expression { def value p elements end } / boolean_leaf ((SYM_AND / SYM_OR / SYM_XOR / SYM_IMPLIES) boolean_leaf)? { def value p elements end } end rule boolean_leaf '(' boolean_expression ')' { def value boolean_expression.value end } / SYM_TRUE { def value true end } / SYM_FALSE { def value false end } end rule arithmetic_expression arithmetic_node '' { def value arithmetic_node.value end } end rule arithmetic_node arithmetic_leaf (('+' / '-' / '*' / '/' / '^') arithmetic_leaf)* end rule arithmetic_leaf '(' arithmetic_expression ')' { def value arithmetic_expression.value end } / integer_value '' { def value integer_value.value end } / real_value '' { def value real_value.value end } / absolute_path '' { def value absolute_path.value end } end # path block rule object_path movable_path / absolute_path / relative_path end rule movable_path SYM_MOVABLE_LEADER relative_path { def value text_value end } end rule absolute_path '/' relative_path? { def value text_value end } end rule relative_path path_segment ('/' path_segment)* { def value text_value end } end rule path_segment V_ATTRIBUTE_IDENTIFIER V_LOCAL_TERM_CODE_REF? { def value text_value end } end rule SYM_MOVABLE_LEADER '//' end end end end