lib/hl7/path_parser.ex

defmodule HL7.PathParser do
  import NimbleParsec

  numeric_index = integer(min: 1)
  index = choice([numeric_index, string("*")])

  bracketed_num =
    ignore(string("["))
    |> concat(index)
    |> ignore(string("]"))

  defaulted_num = choice([bracketed_num, empty()])

  dot = ignore(string("."))
  dash = ignore(string("-"))

  bang = string("!") |> replace(true) |> tag(:truncate)

  field = optional(dash) |> concat(index) |> tag(:field)

  alpha = ascii_string([?A..?Z], 1)
  alpha_num = choice([ascii_string([?0..?9], 1), alpha])

  segment_id =
    alpha
    |> concat(alpha_num)
    |> concat(alpha_num)
    |> reduce({Enum, :join, [""]})
    |> tag(:segment)

  segment_num = defaulted_num |> tag(:segment_number)

  segment_header = optional(segment_id |> concat(segment_num))

  repeat_num = defaulted_num |> tag(:repetition)

  component = index |> tag(:component)

  subcomponent = index |> tag(:subcomponent)

  component_part =
    dot
    |> concat(component)
    |> optional(concat(dot, subcomponent))

  defparsec(
    :parse,
    segment_header
    |> optional(field)
    |> optional(repeat_num)
    |> optional(component_part)
    |> optional(bang)
    |> eos()
  )
end