telephone-uri        = "tel:" telephone-subscriber

telephone-subscriber = global-number / local-number

global-number        = global-number-digits *par !!!
  [number|_] = string_values
  _ = values
  _ = rule
  {:ok, %{state | global: true, number: :lists.flatten(number)}}
!!!

local-number         = local-number-digits *par context *par !!!
  [number|_] = string_values
  _ = values
  _ = rule
  {:ok, %{state | local: true, number: :lists.flatten(number)}}
!!!

par                  = parameter / extension / isdn-subaddress

isdn-subaddress      = ";isub=" 1*paramchar !!!
  [_, isub] = string_values
  _ = values
  _ = rule
  {:ok, %{state | isub: isub}}
!!!

extension            = ";ext=" 1*phonedigit !!!
  [_, ext] = string_values
  _ = values
  _ = rule
  {:ok, %{state | ext: ext}}
!!!

context              = ";phone-context=" descriptor !!!
  _ = values
  _ = rule
  [_, context] = string_values
  {:ok, %{state | context: context}}
!!!

descriptor           = domainname / global-number-digits !!!
  _ = values
  _ = rule
  [descriptor] = string_values
  {:ok, %{state | descriptor: :lists.flatten(descriptor)}}
!!!

global-number-digits = "+" *phonedigit DIGIT *phonedigit
local-number-digits  = *phonedigit-hex (HEXDIG / "*" / "#") *phonedigit-hex
domainname           = *( domainlabel "." ) toplabel [ "." ]
domainlabel          = alphanum / alphanum *( alphanum / "-" ) alphanum
toplabel             = ALPHA / ALPHA *( alphanum / "-" ) alphanum

parameter            = ";" pname ["=" pvalue ] !!!
  _ = values
  _ = rule
  {name, value} = case string_values do
    [_, name, []] -> {:lists.flatten(name), nil}
    [_, name, value] ->
      value = tl(:lists.flatten(value))
      {:lists.flatten(name), value}
  end
  {:ok, %{state |params: Map.put(state.params, name, value)}}
!!!

pname                = 1*( alphanum / "-" )
pvalue               = 1*paramchar
paramchar            = param-unreserved / unreserved / pct-encoded
unreserved           = alphanum / mark
mark                 = "-" / "_" / "." / "!" / "~" / "*" / "'" / "(" / ")"
pct-encoded          = "%" HEXDIG HEXDIG
param-unreserved     = "[" / "]" / "/" / ":" / "&" / "+" / "$"
phonedigit           = DIGIT / visual-separator
phonedigit-hex       = HEXDIG / "*" / "#" / visual-separator
visual-separator     = "-" / "." / "(" / ")"
alphanum             = ALPHA / DIGIT
reserved             = ";" / "/" / "?" / ":" / "@" / "&" / "=" / "+" / "$" / ","
uric                 = reserved / unreserved / pct-encoded
ALPHA                =  %x41-5A / %x61-7A   ; A-Z / a-z
BIT                  =  "0" / "1"
CHAR                 =  %x01-7F ; any 7-bit US-ASCII character, excluding NUL
CR                   =  %x0D ; carriage return
CRLF                 =  CR LF ; Internet standard newline
CTL                  =  %x00-1F / %x7F ; controls
DIGIT                =  %x30-39 ; 0-9
DQUOTE               =  %x22 ; " (Double Quote)
HEXDIG               =  DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
HTAB                 =  %x09 ; horizontal tab
LF                   =  %x0A ; linefeed
LWSP                 =  *(WSP / CRLF WSP) ; linear white space (past newline)
OCTET                =  %x00-FF ; 8 bits of data
SP                   =  %x20
VCHAR                =  %x21-7E ; visible (printing) characters
WSP                  =  SP / HTAB ; white space
