require ‘shared_token_grammar’ require ‘dadl’

module OpenEHR

module Parser
  grammar DADLGrammar

    include SharedToken

    rule V_DADL_TEXT
      attr_vals space {
        def value
          attr_vals.value
        end
      }
    / complex_object_block space {
        def value
          complex_object_block.value
        end
      }
    end

    rule attr_vals
      first:attr_val second:(';'? space attr_val space)* {
        def value
          attrs.inject({ }) {|val, a| val.update a.value}
        end

        def attrs
          [first] + second.elements.map {|e| e.attr_val}
        end
      }
    end

    rule attr_val
      attr_id SYM_EQ object_block {
        def value
          {attr_id.value =>  object_block.value}
        end
      }
    end

    rule attr_id
      id:V_ATTRIBUTE_IDENTIFIER white_space {
        def value
          id.value
        end
      }
    end

    rule object_block
      complex_object_block space {
        def value
          complex_object_block.value
        end
      }
    / primitive_object_block space {
        def value
          primitive_object_block.value
        end
      }
    end

    rule complex_object_block
      single_attr_object_block '' {
        def value
          single_attr_object_block.value
        end
      }
    / multiple_attr_object_block '' {
        def value
          multiple_attr_object_block.value
        end
      }
    end

    rule multiple_attr_object_block
      type_identifier? untyped_multiple_attr_object_block {
        def value
          untyped_multiple_attr_object_block.value
        end
      }
    end

    rule untyped_multiple_attr_object_block
      multiple_attr_object_block_head keyed_objects SYM_END_DBLOCK {
        def value
          keyed_objects.value
        end
      }
    end

    rule multiple_attr_object_block_head
      SYM_START_DBLOCK
    end

    rule keyed_objects
      keyed_object+  {
        def value
          elements.inject({ }) {|val, e| val.update e.value}
        end
      }
    end

    rule keyed_object
      object_key SYM_EQ object_block {
        def value
          {object_key.value => object_block.value}
        end
      }
    end

    rule object_key
      '[' simple_value ']' white_space {
         def value
           simple_value.value
         end
      }
    end

    rule single_attr_object_block
      type_identifier? untyped_single_attr_object_block {
        def value
          untyped_single_attr_object_block.value
        end
      }
    end

    rule untyped_single_attr_object_block
      single_attr_object_complex_head attr_vals SYM_END_DBLOCK {
         def value
           elements[1].value
         end
      }
    / single_attr_object_complex_head SYM_END_DBLOCK {
        def value
          nil
        end
      }
    end

    rule single_attr_object_complex_head
      SYM_START_DBLOCK
    end

    rule primitive_object_block
      type_identifier? untyped_primitive_object_block {
        def value
          untyped_primitive_object_block.value
        end
      }
    end

    rule untyped_primitive_object_block
      SYM_START_DBLOCK primitive_object_value SYM_END_DBLOCK {
        def value
          primitive_object_value.value
        end
      }
    end

    rule primitive_object_value
      term_code_list_value '' {
        def value
          term_code_list_value.value
        end
      }
    / term_code '' {
        def value
          term_code.value
        end
      }
    / simple_list_value '' {
        def value
          simple_list_value.value
        end
      }
    / simple_interval_value '' {
        def value
          simple_interval_value.value
        end
      }
    / simple_value '' {
        def value
          simple_value.value
        end
      }
    end

    rule simple_value
      integer_value '' {
        def value
          integer_value.value
        end
      }
    / real_value '' {
        def value
          real_value.value
        end
      }
    / boolean_value '' {
        def value
          boolean_value.value
        end
      }
    / uri_value '' {
        def value
          uri_value.value
        end
      }
    / date_value '' {
        def value
          date_value.value
        end
      }
    / time_value '' {
        def value
          time_value.value
        end
      }
    / date_time_value '' {
        def value
          date_time_value.value
        end
      }
    / duration_value '' {
        def value
          duration_value.value
        end
      }
    / string_value '' {
        def value
          string_value.value
        end
      }
    / character_value '' {
        def value
          character_value.value
        end
      }
    end

    rule simple_list_value
      integer_list_value '' {
        def value
          integer_list_value.value
        end
      }
    / real_list_value '' {
        def value
          real_list_value.value
        end
      }
    / boolean_list_value '' {
        def value
          boolean_list_value.value
        end
      }
    / character_list_value '' {
        def value
          character_list_value.value
        end
      }
    / date_list_value '' {
        def value
          date_list_value.value
        end
      }
    / time_list_value '' {
        def value
          time_list_value.value
        end
      }
    / date_time_list_value '' {
        def value
          date_time_list_value.value
        end
      }
    / duration_list_value '' {
        def value
          duration_list_value.value
        end
      }
    / string_list_value '' {
        def value
          string_list_value.value
        end
      }
    end

    rule simple_interval_value
      integer_interval_value '' {
        def value
          integer_interval_value.value
        end
      }
    / real_interval_value '' {
        def value
          real_interval_value.value
        end
      }
    / date_interval_value '' {
        def value
          date_interval_value.value
        end
      }
    / time_interval_value '' {
        def value
          time_interval_value.value
        end
      }
    / date_time_interval_value '' {
        def value
          date_time_interval_value.value
        end
      }
    / duration_interval_value '' {
        def value
          duration_interval_value.value
        end
      }
    end

    rule term_code
      vtref:V_QUALIFIED_TERM_CODE_REF '' {
        def value
          vtref.value
        end
      }
    end

    rule term_code_list_value
      first:term_code more:(',' term_code)+ {
        def value
          term_codes.map {|t| t.value}
        end

        def term_codes
          [first] + more.elements.map {|e| e.term_code}
        end
      }
    / term_code ',' SYM_LIST_CONTINUE {
        def value
          [term_code.value]
        end
      }
    end

    rule uri_value
      uri:V_URI '' {
        def value
          uri.value
        end
      }
    end
  end
end

end