URI-reference = URI / relative-ref

URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] :
  {Authority, Path} = _YY3,
  Query = case _YY4 of
            [[$?, Query1]] -> Query1;
            [] -> undefined end,
  Fragment = case _YY5 of
               [[$#, Fragment1]] -> Fragment1;
               [] -> undefined end,
  #ex_uri{scheme = _YY1,
          authority = Authority,
          path = Path,
          q = Query,
          fragment = Fragment}.

relative-ref = relative-part [ "?" query ] [ "#" fragment ] :
  {Authority, Path} = _YY1,
  Query = case _YY2 of
            [[$?, Query1]] -> Query1;
            [] -> undefined end,
  Fragment = case _YY3 of
               [[$#, Fragment1]] -> Fragment1;
               [] -> undefined end,
  #ex_uri_ref{authority = Authority,
              path = Path,
              q = Query,
              fragment = Fragment}.

relative-part = "//" authority path-abempty
              / path-absolute
              / path-noscheme
              / path-empty :
  case _YY of
    ["//", Authority, Path] -> {Authority, Path};
    Path -> {undefined, Path} end.

absolute-URI = scheme ":" hier-part [ "?" query ] :
  {Authority, Path} = _YY3,
  Query = case _YY4 of
            [[$?, Query1]] -> Query1;
            [] -> undefined end,
  #ex_uri{scheme = _YY1, authority = Authority, path = Path, q = Query}.

scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) :
  [_YY1 | _YY2].

hier-part = "//" authority path-abempty
          / path-absolute
          / path-rootless
          / path-empty :
  case _YY of
    ["//", Authority, Path] -> {Authority, Path};
    Path -> {undefined, Path} end.

authority = [ userinfo "@" ] host [ ":" port ] :
  UserInfo = case _YY1 of
               [] -> undefined;
               [[UserInfo1, $@]] -> UserInfo1 end,
  Port = case _YY3 of
           [] -> undefined;
           [[$:, Port1]] -> Port1 end,
  #ex_uri_authority{userinfo = UserInfo, host = _YY2, port = Port}.

userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) :
  lists:flatten(_YY).

host = IP-literal / IPv4address / reg-name :
  lists:flatten(_YY).

IP-literal = "[" ( IPv6address / IPvFuture ) "]"

IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )

IPv6address =                            6( h16 ":" ) ls32
            /                       "::" 5( h16 ":" ) ls32
            / [               h16 ] "::" 4( h16 ":" ) ls32
            / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
            / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
            / [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
            / [ *4( h16 ":" ) h16 ] "::"              ls32
            / [ *5( h16 ":" ) h16 ] "::"              h16
            / [ *6( h16 ":" ) h16 ] "::"

h16 = 1*4HEXDIG

ls32 = ( h16 ":" h16 ) / IPv4address

IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet

dec-octet = DIGIT
            / %x31-39 DIGIT
            / "1" 2DIGIT
            / "2" %x30-34 DIGIT
            / "25" %x30-35

port = *DIGIT :
  list_to_integer(_YY).

reg-name = *( unreserved / pct-encoded / sub-delims )

path = path-abempty
     / path-absolute
     / path-noscheme
     / path-rootless
     / path-empty

path-abempty = *( "/" segment ) :
  lists:flatten(_YY).

path-absolute = "/" [ segment-nz *( "/" segment ) ] :
  lists:flatten(_YY).

path-noscheme = segment-nz-nc *( "/" segment ) :
  lists:flatten(_YY).

path-rootless = segment-nz *( "/" segment ) :
  lists:flatten(_YY).

path-empty = 0pchar

segment = *pchar

segment-nz = 1*pchar

segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )

query = *( pchar / "/" / "?" ) :
  lists:flatten(_YY).

fragment = *( pchar / "/" / "?" ) :
  lists:flatten(_YY).

pchar = unreserved / pct-encoded / sub-delims / ":" / "@"

pct-encoded = "%" HEXDIG HEXDIG

unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"

gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"

sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
