require ‘open_ehr/assumed_library_types’ require ‘open_ehr/rm/data_types/quantity’

module OpenEHR

module Parser
  grammar SharedToken

    rule any_identifier
      type_identifier '' {
        def value
          type_identifier.value
        end
      }
    / V_ATTRIBUTE_IDENTIFIER '' {
        def value
          V_ATTRIBUTE_IDENTIFIER.value
        end
      }
    end

    rule type_identifier
      '(' id:V_GENERIC_TYPE_IDENTIFIER ')' white_space {
        def value
          id.value
        end
      }
    / id:V_GENERIC_TYPE_IDENTIFIER white_space {
        def value
          id.value
        end
      }
    / '(' id:V_TYPE_IDENTIFIER ')' white_space {
        def value
          id.value
        end
      }
    / id:V_TYPE_IDENTIFIER white_space {
        def value
          id.value
        end
      }
    end

    rule boolean_value
      SYM_TRUE {
        def value
          true
        end
        }
    / SYM_FALSE {
        def value
          false
        end
      }
    end

    rule boolean_list_value
      boolean_value (',' white_space more_bool:(boolean_value ''))+ {
        def value
          booelans.map {|b| b.value} 
        end

        def booleans
          [boolean_value] + more_bool.elements.map { |b| b.boolean_value }
        end
      }
    / boolean_value white_space SYM_LIST_CONTINUE {
        def value
          [boolean_value.value]
        end
      }
    end

    rule integer_value
      [+-]? V_INTEGER '' {
        def value
          text_value.to_i
        end
      }
    end

    rule integer_list_value
      integer_value more_i:(',' white_space integer_value)+ {
        def value
          integers.map { |i| i.value }
        end

        def integers
          [integer_value] + more_i.elements.map { |i| i.integer_value }
        end
      }
    / integer_value ',' white_space SYM_LIST_CONTINUE {
        def value
          [integer_value.value]
        end
      }
    end

    rule integer_interval_value
      SYM_INTERVAL_DELIM SYM_GT lo:integer_value SYM_ELLIPSIS SYM_LT up:integer_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => false,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GT lo:integer_value SYM_ELLIPSIS up:integer_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => false,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM lo:integer_value SYM_ELLIPSIS SYM_LT up:integer_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => true,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM lo:integer_value SYM_ELLIPSIS up:integer_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => true,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM SYM_LT up:integer_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :upper => up.value,
                :lower_unbounded => true,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_LE up:integer_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :upper => up.value,
                :lower_unbounded => true,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GT lo:integer_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :lower => lo.value,
                :uppper_unbounded => true,
                :lower_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GE iv:integer_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :lower => iv.value,
                :upper_unbounded => true,
                :lower_included => true)
        end
      }
    / SYM_INTERVAL_DELIM val:integer_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :lower => val.value,
                :upper => val.value,
                :upper_included => true,
                :lower_included => true)
        end
      }
    end

    rule real_value
      ('+' / '-')? V_REAL {
        def value
          text_value.to_f
        end
      }
    end

    rule real_list_value
      real_value  more_i:(',' white_space real_value)* {
        def value
          reals.map { |i| i.value }
        end

        def reals
          [real_value] + more_i.elements.map { |i| i.real_value }
        end
      }
    / real_value ',' white_space SYM_LIST_CONTINUE {
        def value
          [real_value.value]
        end
      }
    end

    rule real_interval_value
      SYM_INTERVAL_DELIM SYM_GT lo:real_value SYM_ELLIPSIS SYM_LT up:real_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => false,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GT lo:real_value SYM_ELLIPSIS up:real_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => false,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM lo:real_value SYM_ELLIPSIS SYM_LT up:real_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => true,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM lo:real_value SYM_ELLIPSIS up:real_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => true,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM SYM_LT up:real_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :upper => up.value,
                :lower_unbounded => true,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_LE up:real_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :upper => up.value,
                :lower_unbounded => true,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GT lo:real_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :lower => lo.value,
                :uppper_unbounded => true,
                :lower_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GE lo:real_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :lower => lo.value,
                :upper_unbounded => true,
                :lower_included => true)
        end
      }
    / SYM_INTERVAL_DELIM val:real_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :lower => val.value,
                :upper => val.value,
                :upper_included => true,
                :lower_included => true)
        end
      }
    end

    rule character_value
      V_CHAR '' {
         def value
           text_value
         end
      }
    end

    rule character_list_value
      character_value (',' white_space more_chars:(character_value))+ {
        def value
          characters.map {|c| c.value }
        end

        def characters
          [character_value] + more_chars.elements.map {|c| c.character_value}
        end
      }
    / character_value ',' SYM_LIST_CONTINUE {
        def value
          [character_value.value]
        end
      }
    end

    rule string_value
      str:V_STRING '' {
        def value
          str.value
        end
      }
    end

    rule string_list_value
      first:string_value second:(',' white_space string_value)+ {
        def value
          strings.map {|s| s.value}
        end

        def strings
          [first] + second.elements.map {|s| s.string_value}
        end
      }
    / str:V_STRING ',' white_space SYM_LIST_CONTINUE {
        def value
          [str.value]
        end
      }
    end

    rule date_value
      ed:V_ISO8601_EXTENDED_DATE '' {
        def value
          ::OpenEHR::RM::DataTypes::Quantity::DateTime::DvDate.new(
            :value => ed.text_value)
        end
      }
    end

    rule date_list_value
      date_value more_dates:(',' white_space date_value)+ {
        def value
          dates.map {|d| d.value}
        end

        def dates
          [date_value] + more_dates.elements.map {|d| d.date_value}
        end
      }
    / date_value ',' white_space SYM_LIST_CONTINUE {
        def value
          [date_value.value]
        end
      }
    end

    rule date_interval_value
      SYM_INTERVAL_DELIM SYM_GT lo:date_value SYM_ELLIPSIS SYM_LT up:date_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => false,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GT lo:date_value SYM_ELLIPSIS up:date_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => false,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM lo:date_value SYM_ELLIPSIS SYM_LT up:date_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => true,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM lo:date_value SYM_ELLIPSIS up:date_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => true,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM SYM_LT up:date_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :upper => up.value,
                :lower_unbounded => true,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_LE up:date_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :upper => up.value,
                :lower_unbounded => true,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GT lo:date_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :lower => lo.value,
                :uppper_unbounded => true,
                :lower_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GE val:date_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :lower => val.value,
                :upper_unbounded => true,
                :lower_included => true)
        end
      }
    / SYM_INTERVAL_DELIM val:date_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :lower => val.value,
                :upper => val.value,
                :upper_included => true,
                :lower_included => true)
        end
      }
    end

    rule time_value
      ti:V_ISO8601_EXTENDED_TIME '' {
        def value
          ::OpenEHR::RM::DataTypes::Quantity::DateTime::DvTime.new(
            :value => ti.text_value)
        end
      }
    end

    rule time_list_value
      time_value more_t:(',' white_space time_value)+ {
        def value
          times.map {|t| t.value}
        end

        def times
          [time_value] + more_t.elements.map {|t| t.time_value}
        end
      }
    / time_value ',' white_space SYM_LIST_CONTINUE {
        def value
          [time_value.value]
        end
      }
    end

    rule time_interval_value
      SYM_INTERVAL_DELIM SYM_GT lo:time_value SYM_ELLIPSIS SYM_LT up:time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => false,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GT lo:time_value SYM_ELLIPSIS up:time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => false,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM lo:time_value SYM_ELLIPSIS SYM_LT up:time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => true,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM lo:time_value SYM_ELLIPSIS up:time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => true,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM SYM_LT up:time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :upper => up.value,
                :lower_unbounded => true,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_LE up:time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :upper => up.value,
                :lower_unbounded => true,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GT lo:time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :lower => lo.value,
                :uppper_unbounded => true,
                :lower_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GE tv:time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :lower => tv.value,
                :upper_unbounded => true,
                :lower_included => true)
        end
      }
    / SYM_INTERVAL_DELIM val:time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :lower => val.value,
                :upper => val.value,
                :upper_included => true,
                :lower_included => true)
        end
      }
    end

    rule date_time_value
      dt:V_ISO8601_EXTENDED_DATE_TIME '' {
        def value
          ::OpenEHR::RM::DataTypes::Quantity::DateTime::DvDateTime.new(
            :value => dt.text_value)
        end
      }
    end

    rule date_time_list_value
      date_time_value (',' more_dt:date_time_value)+ {
        def value
          date_times.map {|t| t.value}
        end

        def date_times
          [date_time_value] + more_dt.elements.map {|dt| dt.date_time_value}
        end
      }
    / date_time_value ',' SYM_LIST_CONTINUE {
        def value
          [date_time_value.value]
        end
      }
    end

    rule date_time_interval_value
      SYM_INTERVAL_DELIM SYM_GT lo:date_time_value SYM_ELLIPSIS SYM_LT up:date_time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => false,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GT lo:date_time_value SYM_ELLIPSIS up:date_time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => false,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM lo:date_time_value SYM_ELLIPSIS SYM_LT up:date_time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => true,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM lo:date_time_value SYM_ELLIPSIS up:date_time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => true,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM SYM_LT up:date_time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :upper => up.value,
                :lower_unbounded => true,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_LE up:date_time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :upper => up.value,
                :lower_unbounded => true,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GT lo:date_time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :lower => lo.value,
                :uppper_unbounded => true,
                :lower_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GE dt:date_time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :lower => dt.value,
                :upper_unbounded => true,
                :lower_included => true)
        end
      }
    / SYM_INTERVAL_DELIM val:date_time_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :lower => val.value,
                :upper => val.value,
                :upper_included => true,
                :lower_included => true)
        end
      }
    end

    rule duration_value
      du:V_ISO8601_DURATION '' {
        def value
          ::OpenEHR::RM::DataTypes::Quantity::DateTime::DvDuration.new(
            :value => du.text_value)
        end
      }
    end

    rule duration_list_value
      duration_value more_d:(',' duration_value)+ {
        def value
          durations.map {|d| d.value}
        end

        def durations
          [duration_value] + more_d.elements.map {|d| d.duration_value}
        end
      }
    / duration_value ',' SYM_LIST_CONTINUE {
        def value
          [duration_value.value]
        end
      }
    end

    rule duration_interval_value
      SYM_INTERVAL_DELIM SYM_GT lo:duration_value SYM_ELLIPSIS SYM_LT up:duration_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => false,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GT lo:duration_value SYM_ELLIPSIS up:duration_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => false,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM lo:duration_value SYM_ELLIPSIS SYM_LT up:duration_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => true,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM lo:duration_value SYM_ELLIPSIS up:duration_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(:lower => lo.value,
                :upper => up.value,
                :lower_included => true,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM SYM_LT up:duration_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :upper => up.value,
                :lower_unbounded => true,
                :upper_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_LE up:duration_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :upper => up.value,
                :lower_unbounded => true,
                :upper_included => true)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GT lo:duration_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :lower => lo.value,
                :uppper_unbounded => true,
                :lower_included => false)
        end
      }
    / SYM_INTERVAL_DELIM SYM_GE val:duration_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :lower => val.value,
                :upper_unbounded => true,
                :lower_included => true)
        end
      }
    / SYM_INTERVAL_DELIM val:duration_value SYM_INTERVAL_DELIM {
        def value
          OpenEHR::AssumedLibraryTypes::Interval.new(
                :upper => val.value,
                :lower => val.value,
                :upper_included => true,
                :lower_included => true)
        end
      }
    end

    rule ALPHANUM
      [a-zA-Z0-9]
    end

    rule IDCHAR
      [a-zA-Z0-9_]
    end

    rule NAMECHAR
      [a-zA-Z0-9\._\-]
    end

    rule NAMECHAR_SPACE
      [a-zA-Z0-9\._\- ]
    end

    rule NAMECHAR_PAREN
      [a-zA-Z0-9\._\-\(\)]
    end

    rule NAMESTR
      [a-zA-Z] [a-zA-Z0-9_]+
    end

    rule space
      COMMENT* white_space
    end

    rule COMMENT
      white_space '--' [^\n]* "\n"
    end

    rule white_space
      [ \t\r\n]*
    end

    rule Minus_code
      '-'
    end

    rule Plus_Code
      '+'
    end

    rule Star_code
      '*'
    end

    rule Slash_code
      '/'
    end

    rule Carret_code
      '^'
    end

    rule Dot_code
      '.'
    end

    rule Semicolon_code
      ';'
    end

    rule Colon_code
      ':'
    end

    rule Comma_code
      ','
    end

    rule Expclamation_code
      '!'
    end

    rule Left_parenthesis_code
      '('
    end

    rule Right_parenthesis_code
      ')'
    end

    rule Dollar_code
      '$'
    end

    rule SYM_DT_UNKNOWN
      '??'
    end

    rule Question_mark_code
      '?'
    end

    rule SYM_INTERVAL_DELIM
      '|'
    end

    rule Left_bracket_code
      '[' space
    end

    rule Right_bracket_codde
      ']'
    end

    rule SYM_EQ
      '=' white_space
    end

    rule SYM_GE
      ('=>' / '>=') white_space
    end

    rule SYM_LE
      ('<=' / '=>') white_space
    end

    rule SYM_LT
      '<' white_space
    end

    rule SYM_GT
      '>' white_space
    end

    rule SYM_START_DBLOCK
      '<' space
    end

    rule SYM_END_DBLOCK
      '>' space
    end

    rule SYM_START_CBLOCK
      '{' space
    end

    rule SYM_END_CBLOCK
      '}'
    end

    rule SYM_ELLIPSIS
      '..'
    end

    rule SYM_LIST_CONTINUE
      '...'
    end

    rule SYM_INFINITY
      [Ii] [Nn] [Ff] [Ii] [Nn] [Ii] [Tt] [Yy] space
    end

    rule SYM_ARCHETYPE
      [Aa] [Rr] [Cc] [Hh] [Ee] [Tt] [Yy] [Pp] [Ee] space
    end

    rule SYM_MATCHES
      ([Mm] [Aa] [Tt] [Cc] [Hh] [Ee] [Ss] / [Ii] [Ss] '_' [Ii] [Nn]) white_space
    end

    rule SYM_THEN
      [Tt] [Hh] [Ee] [Nn] space
    end

    rule SYM_ELSE
      [Ee] [Ll] [Ss] [Ee] space
    end

    rule SYM_AND
      [Aa] [Nn] [Dd] space
    end

    rule SYM_OR
      [Oo] [Rr] space
    end

    rule SYM_XOR
      [Xx] [Oo] [Rr] space
    end

    rule SYM_NOT
      [Nn] [Oo] [Tt] space
    end

    rule SYM_IMPLIES
      [Ii] [Mm] [Pp] [Ll] [Ii] [Ee] [Ss] space
    end

    rule SYM_TRUE
      [Tt] [Rr] [Uu] [Ee] space
    end

    rule SYM_FALSE
      [Ff] [Aa] [Ll] [Ss] [Ee] space
    end

    rule SYM_FORALL
      [Ff] [Oo] [Rr] '_' [Aa] [Ll] [Ll] space
    end

    rule SYM_EXISTS
      [Ee] [Xx] [Ii] [Ss] [Tt] [Ss] space
    end

    rule SYM_EXISTENCE
      [Ee] [Xx] [Ii] [Ss] [Tt] [Ee] [Nn] [Cc] [Ee] space
    end

    rule SYM_OCCURRENCES
      [Oo] [Cc] [Cc] [Uu] [Rr] [Rr] [Ee] [Nn] [Cc] [Ee] [Ss] white_space
    end

    rule SYM_CARDINALITY
      [Cc] [Aa] [Rr] [Dd] [Ii] [Nn] [Aa] [Ll] [Ii] [Tt] [Yy] white_space
    end

    rule SYM_ORDERED
      [Oo] [Rr] [Dd] [Ee] [Rr] [Ee] [Dd] white_space
    end

    rule SYM_UNORDERD
      [Uu] [Nn] [Oo] [Rr] [Dd] [Ee] [Rr] [Ee] [Dd] white_space
    end

    rule SYM_UNIQUE
      [Uu] [Nn] [Ii] [Qq] [Uu] [Ee] space
    end

    rule SYM_INFINITY
      [Ii] [Nn] [Ff] [Ii] [Nn] [Ii] [Tt] [Yy] space
    end

    rule SYM_USE_NODE
      [Uu] [Ss] [Ee] '_' [Nn] [Oo] [Dd] [Ee] space
    end

    rule SYM_ALLOW_ARCHETYPE
      ([Aa] [Ll] [Ll] [Oo] [Ww] /  [Uu] [Ss] [Ee]) '_' [Aa] [Rr] [Cc] [Hh] [Ee] [Tt] [Yy] [Pp] [Ee] space
    end

    rule SYM_INCLUDE
      [Ii] [Nn] [Cc] [Ll] [Uu] [Dd] [Ee] space
    end

    rule SYM_EXCLUDE
      [Ee] [Xx] [Cc] [Ll] [Uu] [Dd] [Ee] space
    end

    rule SYM_TEMPLATE_COMPONENT
      [Tt] [Ee] [Mm] [Pp] [Ll] [Aa] [Tt] [Ee] ' _' [Cc] [Oo] [Mm] [Pp] [Oo] [Nn] [Ee] [Nn] [Tt] space
    end

    rule SYM_TEMPLATE
      [Tt] [Ee] [Mm] [Pp] [Ll] [Aa] [Tt] [Ee] space
    end

    rule SYM_OPERATIONAL_TEMPLATE
      [Oo] [Pp] [Ee] [Rr] [Aa] [Tt] [Ii] [Oo] [Nn] [Aa] [Ll] '_' [Tt] [Ee] [Mm] [Pp] [Ll] [Aa] [Tt] [Ee] space
    end

    rule SYM_ADL_VERSION
      [Aa] [Dd] [Ll] '_' [Vv] [Ee] [Rr] [Ss] [Ii] [Oo] [Nn] space
    end

    rule SYM_IS_CONTROLLED
      [Cc] [Oo] [Nn] [Tt] [Rr] [Oo] [Ll] [Ll] [Ee] [Dd] space
    end

    rule SYM_IS_GENERATED
      [Gg] [Ee] [Nn] [Ee] [Rr] [Aa] [Tt] [Ee] [Dd] space
    end

    rule SYM_SPECIALIZE
      [Ss] [Pp] [Ee] [Cc] [Ii] [Aa] [Ll] [Ii] [SsZz] [Ee] space
    end    

    rule SYM_CONCEPT
      [Cc] [Oo] [Nn] [Cc] [Ee] [Pp] [Tt] space
    end

    rule SYM_LANGUAGE
      [Ll] [Aa] [Nn] [Gg] [Uu] [Aa] [Gg] [Ee] space
    end

    rule SYM_DESCRIPTION
      [Dd] [Ee] [Ss] [Cc] [Rr] [Ii] [Pp] [Tt] [Ii] [Oo] [Nn] space
    end

    rule SYM_DEFINITION
      [Dd] [Ee] [Ff] [Ii] [Nn] [Ii] [Tt] [Ii] [Oo] [Nn] space
    end

    rule SYM_INVARIANT
      [Ii] [Nn] [Vv] [Aa] [Rr] [Ii] [Aa] [Nn] [Tt] space
    end

    rule SYM_ONTOLOGY
      [Oo] [Nn] [Tt] [Oo] [Ll] [Oo] [Gg] [Yy] space
    end

    rule SYM_ANNOTATIONS
      [Aa] [Nn] [Nn] [Oo] [Tt] [Aa] [Tt] [Ii] [Oo] [Nn] [Ss] space
    end

    rule V_VERSION_STRING
      [0-9]+ '.' [0-9]+ ('.' [0-9]+)* {
        def value
          text_value
        end
      }
    end

    rule V_ARCHETYPE_ID
      NAMESTR ('-' NAMESTR) 2..2 '.' NAMESTR ('-' NAMESTR)* '.v' [1-9] [0-9]* {
        def value
          text_value
        end
      }
    end

    rule V_IDENTIFIER
      [a-zA-Z] [a-zA-Z0-9_]* {
        def value
          text_value
        end
      }
    end

    rule V_URI
      [a-z]+ '://' [^<>|\\{}^~"\[\] ]* { 
        def value
          text_value
        end
      }
    end

    rule V_QUALIFIED_TERM_CODE_REF
      '[' ti:(NAMECHAR_PAREN+) '::' cs:(NAMECHAR+) ']' {
        def value
          term_id = OpenEHR::RM::Support::Identification::TerminologyID.new(
            :value => ti.text_value)
          OpenEHR::RM::DataTypes::Text::CodePhrase.new(
            :terminology_id => term_id, :code_string => cs.text_value)
        end
      }
    end

    rule ERR_V_QUALIFIED_TERM_CODE_REF
      '[' er:(NAMECHAR_PAREN+ '::' NAMECHAR_SPACE+) ']' {
        def value
          er.text_value
        end
      }
    end

    rule V_LOCAL_TERM_CODE_REF
      '[' lt:(ALPHANUM NAMECHAR*) ']' {
        def value
          lt.text_value
        end
      }
    end

    rule V_LOCAL_CODE
      'a' [ct] [0-9\.]+ {
        def value
          text_value
        end
      }
    end

    rule V_TERM_CODE
      '[' code:([a-zA-Z0-9()._\-]+) '::' white_space {
        def value
          ::OpenEHR::RM::Support::Identification::TerminologyID.new(
            :value => code.text_value)
        end
      }
    end

    rule V_ISO8601_EXTENDED_DATE_TIME
      ([0-9] 4..4 '-' [0-1] [0-9] '-' [0-3] [0-9] 'T' [0-2] [0-9] ':' [0-6] [0-9] ':' [0-6] [0-9] (',' [0-9]+)? ('Z' / [+-] [0-9] 4..4)? ) / ([0-9] 4..4 '-' [0-1] [0-9] '-' [0-3] [0-9] 'T' [0-2] [0-9] ':' [0-6] [0-9] ('Z' / [+-] [0-9] 4..4)?) / ([0-9] 4..4 '-' [0-1] [0-9] '-' [0-3] [0-9] 'T' [0-2] [0-9] ('Z' / [+-] [0-9] 4..4)?)
    end

    rule V_ISO8601_EXTENDED_TIME
      [0-2] [0-9] ':' [0-6] [0-9] ':' [0-6] [0-9] (',' [0-9]+)? ('Z' / [+-] [0-9] 4..4)? / [0-2] [0-9] ':' [0-6] [0-9] ('Z' / [+-] [0-9] 4..4)?
    end

    rule V_ISO8601_EXTENDED_DATE
      [0-9] 4..4 '-' [0-1] [0-9] '-' [0-3] [0-9] / [0-9] 4..4 '-' [0-1] [0-9]
    end

    rule V_ISO8601_DURATION
      'P' ([0-9]+ [yY])? ([0-9]+ [mM])? ([0-9]+ [wW])? ([0-9]+ [dD])? 'T' ([0-9]+ [hH]) ([0-9]+ [mM])? ([0-9]+ ('.' [0-9]+)? [sS])?
    / 'P' ([0-9]+ [yY])? ([0-9]+ [mM])? ([0-9]+ [wW])? ([0-9]+ [dD])? 'T' ([0-9]+ [hH])? ([0-9]+ [mM]) ([0-9]+ ('.' [0-9]+)? [sS])?
    / 'P' ([0-9]+ [yY])? ([0-9]+ [mM])? ([0-9]+ [wW])? ([0-9]+ [dD])? 'T' ([0-9]+ [hH])? ([0-9]+ [mM])? ([0-9]+ ('.' [0-9]+)? [sS])?
    / 'P' ([0-9]+ [yY]) ([0-9]+ [mM])? ([0-9]+ [wW])? ([0-9]+ [dD])?
    / 'P' ([0-9]+ [yY])? ([0-9]+ [mM]) ([0-9]+ [wW])? ([0-9]+ [dD])? 
    / 'P' ([0-9]+ [yY])? ([0-9]+ [mM])? ([0-9]+ [wW]) ([0-9]+ [dD])?
    / 'P' ([0-9]+ [yY])? ([0-9]+ [mM])? ([0-9]+ [wW])? ([0-9]+ [dD])
    end

    rule V_ISO8601_DATE_CONSTRAINT_PATTERN
      [yY] [yY] [yY] [yY] '-' [mM?X] [mM?X] '-' [dD?X] [dD?X]    
    end

    rule V_ISO8601_TIME_CONSTRAINT_PATTERN
      [hH] [hH] ':' [mM?X] [mM?X] ':' [sS?X] [sS?X]
    end

    rule V_ISO8601_DATE_TIME_CONSTRAINT_PATTERN
      [yY] [yY] [yY] [yY] '-' [mM?X] [mM?X] '-' [dD?X] [dD?X] [Tt ] [hH?X] [hH?X] ':' [mM?X] [mM?X] ':' [sS?X] [sS?X]
    end

    rule V_ISO8601_DURATION_CONSTRAINT_PATTERN
      'P' [yY]? [mM]? [wW]? [dD]? 'T' [hH] [mM]? [sS]?
    / 'P' [yY]? [mM]? [wW]? [dD]? 'T' [hH]? [mM] [sS]?
    / 'P' [yY]? [mM]? [wW]? [dD]? 'T' [hH]? [mM]? [sS]
    / 'P' [yY] [mM]? [wW]? [dD]?
    / 'P' [yY]? [mM] [wW]? [dD]?
    / 'P' [yY]? [mM]? [wW] [dD]?
    / 'P' [yY]? [mM]? [wW]? [dD]
    end

    rule V_TYPE_IDENTIFIER
      [A-Z] IDCHAR* {
        def value
          text_value
        end
      }
    end

    rule V_GENERIC_TYPE_IDENTIFIER
      [A-Z] IDCHAR* '<' [a-zA-Z0-9,_]+ '>' {  # <>
        def value
          text_value
        end
      }
    end

    rule V_ATTRIBUTE_IDENTIFIER
      [a-z] IDCHAR* {
        def value
          text_value
        end
      }
    end

    rule V_INTEGER
      [0-9]+ [eE] [+-]? [0-9] {
        def value
          text_value.to_i
        end
      }       
    / [1-9] [0-9]+ {
        def value
          text_value.to_i
        end
      }       
    / [0-9] {
        def value
          text_value.to_i
        end
      }       
    end

    rule V_REAL
      [0-9]+ '.' [0-9]+ [eE] [+-]? [0-9]+ / [1-9] [0-9]+ '.' [0-9]+ / [0-9] '.' [0-9]+ {
        def value
          text_value.to_f
        end
      }
    end

    rule V_CHAR
      [^\\\n\"] {
        def value
          text_value
        end
      }
    end

    rule V_STRING
      '"' str:(('\"' / !'"' .)*) '"' {
        def value
          str.text_value.tr_s('\\\\', '\\')
        end
      }
    end
  end
end

end