% \iffalse meta-comment
%
% File: siunitx-compound.dtx Copyright (C) 2018-2021,2023-2025 Joseph Wright
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file
%
%    https://www.latex-project.org/lppl.txt
%
% This file is part of the "siunitx bundle" (The Work in LPPL)
% and all files in that bundle must be distributed together.
%
% The released version of this bundle is available from CTAN.
%
% -----------------------------------------------------------------------
%
% The development version of the bundle can be found at
%
%    https://github.com/josephwright/siunitx
%
% for those people who are interested.
%
% -----------------------------------------------------------------------
%
%<*driver>
\documentclass{l3doc}
% Additional commands needed in this source
\ProvideDocumentCommand\email{m}{\href{mailto:#1}{\nolinkurl{#1}}}
\ProvideDocumentCommand\foreign{m}{\textit{#1}}
% The next line is needed so that \GetFileInfo will be able to pick up
% version data
\usepackage{siunitx}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \GetFileInfo{siunitx.sty}
%
% \title{^^A
%   \pkg{siunitx-compound} -- Compound numbers and quantities^^A
%   \thanks{This file describes \fileversion,
%     last revised \filedate.}^^A
% }
%
% \author{^^A
%  Joseph Wright^^A
%  \thanks{^^A
%    E-mail:
%    \email{joseph@texdev.net}^^A
%   }^^A
% }
%
% \date{Released \filedate}
%
% \maketitle
%
% \begin{documentation}
%
% \begin{function}{\siunitx_compound_number:n}
%   \begin{syntax}
%     \cs{siunitx_compound_number:n} \Arg{entries}
%   \end{syntax}
%   Prints a set of numbers in the \meta{entries}, each of which should
%   be given as a \meta{balanced text}. Unlike \cs{siunitx_number_list:nn}, this
%   function may semantically take any form.
% \end{function}
%
% \begin{function}{\siunitx_compound_quantity:nn}
%   \begin{syntax}
%     \cs{siunitx_compound_quantity:nn} \Arg{entries} \Arg{unit}
%   \end{syntax}
%   Prints a set of quantities in the \meta{entries}, each of which should
%   be given as a \meta{balanced text}. Unlike \cs{siunitx_quantity_list:nn},
%   this function may semantically take any form.
% \end{function}
%
% \begin{function}{\siunitx_number_list:nn}
%   \begin{syntax}
%     \cs{siunitx_number_list:nn} \Arg{entries}
%   \end{syntax}
%   Prints the list of numbers in the \meta{entries}, each of which should
%   be given as a \meta{balanced text}.
% \end{function}
%
% \begin{function}{\siunitx_quantity_list:nn}
%   \begin{syntax}
%     \cs{siunitx_quantity_list:nn} \Arg{entries} \Arg{unit}
%   \end{syntax}
%   Prints the list of quantities in the \meta{entries}, each of which should
%   be given as a \meta{balanced text}.
% \end{function}
%
% \begin{function}{\siunitx_number_product:n}
%   \begin{syntax}
%     \cs{siunitx_number_product:n} \Arg{entries}
%   \end{syntax}
%   Prints the series of numbers in the \meta{entries}, each of which should
%   be given as a \meta{balanced text}.
% \end{function}
%
% \begin{function}{\siunitx_quantity_product:nn}
%   \begin{syntax}
%     \cs{siunitx_number_product:n} \Arg{entries} \Arg{unit}
%   \end{syntax}
%   Prints the series of quantities in the \meta{entries}, each of which should
%   be given as a \meta{balanced text}.
% \end{function}
%
% \begin{function}{\siunitx_number_range:nn}
%   \begin{syntax}
%     \cs{siunitx_number_range:nn} \Arg{start} \Arg{end}
%   \end{syntax}
%   Prints the range of numbers from the \meta{start} to the \meta{end}.
% \end{function}
%
% \begin{function}{\siunitx_quantity_range:nnn}
%   \begin{syntax}
%     \cs{siunitx_number_range:nn} \Arg{start} \Arg{end} \Arg{unit}
%   \end{syntax}
%   Prints the range of quantities from the \meta{start} to the \meta{end}.
% \end{function}
%
% \begin{variable}
%   {
%     \l_siunitx_list_separator_pair_tl,
%     \l_siunitx_list_separator_tl,
%     \l_siunitx_list_separator_final_tl
%   }
%   Separators for lists of numbers and quantities.
% \end{variable}
%
% \begin{variable}{\l_siunitx_range_phrase_tl}
%   Phrase (or similar) used between limits of a range.
% \end{variable}
%
% \begin{function}{compound-boundary-mode}
%   \begin{syntax}
%     |compound-boundary-mode| = |number|\verb"|"|text|
%   \end{syntax}
%   Choice which determines whether the material at the start and
%   end of a compound quantity are typeset a |number| or as |text|;
%   the latter is the standard setting.
% \end{function}
%
% \begin{function}{compound-close-boundary, compound-open-boundary}
%   \begin{syntax}
%     |compound-close-boundary| = \meta{tokens}\\
%     |compound-open-boundary|  = \meta{tokens}
%   \end{syntax}
%   Literals which are inserted at the opening and closing boundary of a 
%   compound quantity; they are not used when the number of items is one. The
%   standard settings set these empty.
% \end{function}
%
% \begin{function}{compound-close-bracket, compound-open-bracket}
%   \begin{syntax}
%     |compound-close-bracket| = \meta{token} \\
%     |compound-open-bracket|  = \meta{token}
%   \end{syntax}
%   Literals containing the tokens inserted at the start and end of a compound
%   value when |compounds-units| is set to |bracket|. The standard settings are
%   |(| and |)|.
% \end{function}
%
% \begin{function}{compound-exponents}
%   \begin{syntax}
%     |compound-exponents| = |combine|\verb"|"|combine-bracket|\verb"|"|individual|
%   \end{syntax}
% \end{function}
%
% \begin{function}{compound-final-separator}
%   \begin{syntax}
%     |compound-final-separator| = \meta{text}
%   \end{syntax}
% \end{function}
%
% \begin{function}{compound-independent-prefix}
%   \begin{syntax}
%     |compound-independent-prefix| = |true|\verb"|"|false|
%   \end{syntax}
%   Switch which determines whether unit prefixes are calculated
%   independently when units are repeated. The standard setting is
%   |false|.
% \end{function}
%
% \begin{function}{compound-pair-separator}
%   \begin{syntax}
%     |compound-pair-separator| = \meta{text}
%   \end{syntax}
% \end{function}
%
% \begin{function}{compound-separator}
%   \begin{syntax}
%     |compound-separator| = \meta{text}
%   \end{syntax}
% \end{function}
%
% \begin{function}{compound-separator-mode}
%   \begin{syntax}
%     |compound-separator-mode| = |number|\verb"|"|text|
%   \end{syntax}
%   Choice which determines whether the separators between components
%   of compound quantity are typeset a |number| or as |text|;
%   the latter is the standard setting.
% \end{function}
%
% \begin{function}{compound-units}
%   \begin{syntax}
%     |compound-units| = |bracket|\verb"|"|repeat|\verb"|"|single|
%   \end{syntax}
% \end{function}
%
% \begin{function}{list-close-bracket, list-open-bracket}
%   \begin{syntax}
%     |list-close-bracket| = \meta{token} \\
%     |list-open-bracket|  = \meta{token}
%   \end{syntax}
%   Literals containing the tokens inserted at the start and end of a list when
%   |list-units| is set to |bracket|. The standard settings are |(| and |)|.
% \end{function}
%
% \begin{function}{list-exponents}
%   \begin{syntax}
%     |list-exponents| = |combine|\verb"|"|combine-bracket|\verb"|"|individual|
%   \end{syntax}
% \end{function}
%
% \begin{function}{list-final-separator}
%   \begin{syntax}
%     |list-final-separator| = \meta{text}
%   \end{syntax}
% \end{function}
%
% \begin{function}{list-independent-prefix}
%   \begin{syntax}
%     |list-independent-prefix| = |true|\verb"|"|false|
%   \end{syntax}
%   Switch which determines whether unit prefixes are calculated
%   independently when units are repeated. The standard setting is
%   |false|.
% \end{function}
%
% \begin{function}{list-pair-separator}
%   \begin{syntax}
%     |list-pair-separator| = \meta{text}
%   \end{syntax}
% \end{function}
%
% \begin{function}{list-separator}
%   \begin{syntax}
%     |list-separator| = \meta{text}
%   \end{syntax}
% \end{function}
%
% \begin{function}{list-units}
%   \begin{syntax}
%     |list-units| = |bracket|\verb"|"|repeat|\verb"|"|single|
%   \end{syntax}
% \end{function}
%
% \begin{function}{product-close-bracket, product-open-bracket}
%   \begin{syntax}
%     |product-close-bracket| = \meta{token} \\
%     |product-open-bracket|  = \meta{token}
%   \end{syntax}
%   Literals containing the tokens inserted at the start and end of a product
%   when |product-units| is set to |bracket|. The standard settings are |(|
%   and |)|.
% \end{function}
%
% \begin{function}{product-exponents}
%   \begin{syntax}
%     |product-exponents| = |combine|\verb"|"|combine-bracket|\verb"|"|individual|
%   \end{syntax}
% \end{function}
%
% \begin{function}{product-independent-prefix}
%   \begin{syntax}
%     |product-independent-prefix| = |true|\verb"|"|false|
%   \end{syntax}
%   Switch which determines whether unit prefixes are calculated
%   independently when units are repeated. The standard setting is
%   |false|.
% \end{function}
%
% \begin{function}{product-mode}
%   \begin{syntax}
%     |product-mode| = |phrase|\verb"|"|choice|
%   \end{syntax}
% \end{function}
%
% \begin{function}{product-phrase}
%   \begin{syntax}
%     |product-phrase| = \meta{text}
%   \end{syntax}
% \end{function}
%
% \begin{function}{product-symbol}
%   \begin{syntax}
%     |product-symbol| = \meta{symbol}
%   \end{syntax}
% \end{function}
%
% \begin{function}{range-exponents}
%   \begin{syntax}
%     |range-exponents| = |combine|\verb"|"|combine-bracket|\verb"|"|individual|
%   \end{syntax}
% \end{function}
%
% \begin{function}{range-close-bracket, range-open-bracket}
%   \begin{syntax}
%     |range-close-bracket| = \meta{token} \\
%     |range-open-bracket|  = \meta{token}
%   \end{syntax}
%   Literals containing the tokens inserted at the start and end of a range when
%   |range-units| is set to |bracket|. The standard settings are |(| and |)|.
% \end{function}
%
% \begin{function}{range-independent-prefix}
%   \begin{syntax}
%     |range-independent-prefix| = |true|\verb"|"|false|
%   \end{syntax}
%   Switch which determines whether unit prefixes are calculated
%   independently when units are repeated. The standard setting is
%   |false|.
% \end{function}
%
% \begin{function}{range-open-phrase}
%   \begin{syntax}
%     |range-open-phrase| = \meta{text}
%   \end{syntax}
%   Literal containing the material to be inserted at the start of a range.
%   The standard setting is empty.
% \end{function}
%
% \begin{function}{range-phrase}
%   \begin{syntax}
%     |range-phrase| = \meta{text}
%   \end{syntax}
%   Literal containing the material to be inserted between the start and end
%   of a range. The standard setting contains the word \texttt{to} inside the
%   \cs{text} command, along with appropriate spacing commands to allow this
%   material to work in both math and text typesetting modes.
% \end{function}
%
% \begin{function}{range-units}
%   \begin{syntax}
%     |range-units| = |bracket|\verb"|"|repeat|\verb"|"|single|
%   \end{syntax}
% \end{function}
%
% \end{documentation}
%
% \begin{implementation}
%
% Start the \pkg{DocStrip} guards.
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
%
% \section{\pkg{siunitx-compound} implementation}
%
%    \begin{macrocode}
\cs_generate_variant:Nn \seq_use:Nnnn { NVVV }
%    \end{macrocode}
%
% \subsection{General mechanism}
%
% Identify the internal prefix.
%    \begin{macrocode}
%<@@=siunitx_compound>
%    \end{macrocode}
%
% Typesetting lists, ranges and products of numbers or quantities has shared
% features which mean they are best handled using a common mechanism. The aim
% therefore is to abstract out enough of the process such that output-specific
% aspects can be left to separate processes.
%
% \begin{variable}{\l_@@_tmp_fp, \l_@@_tmp_seq, \l_@@_tmp_tl}
%   Scratch space.
%    \begin{macrocode}
\fp_new:N \l_@@_tmp_fp
\seq_new:N \l_@@_tmp_seq
\tl_new:N \l_@@_tmp_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_first_tl}
%   The first number in the list in internal format.
%    \begin{macrocode}
\tl_new:N \l_@@_first_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_exp_tl}
%   For storing the combined exponent, if present.
%    \begin{macrocode}
\tl_new:N \l_@@_exp_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_start_tl, \l_@@_end_tl}
%   Data on the end-of-list.
%    \begin{macrocode}
\tl_new:N \l_@@_start_tl
\tl_new:N \l_@@_end_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_count_int}
%   Data on the length-of-list.
%    \begin{macrocode}
\int_new:N \l_@@_count_int
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_unit_bool, \l_@@_unit_tl}
%    \begin{macrocode}
\bool_new:N \l_@@_unit_bool
\tl_new:N \l_@@_unit_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {
%     \l_@@_boundary_text_bool  ,
%     \l_@@_boundary_close_tl   ,
%     \l_@@_bracket_close_tl    ,
%     \l_@@_independent_bool    ,
%     \l_@@_separator_final_tl  ,
%     \l_@@_separator_pair_tl   ,
%     \l_@@_boundary_open_tl    ,
%     \l_@@_bracket_open_tl     ,
%     \l_@@_separator_tl        ,
%     \l_@@_separator_text_bool ,
%     \l_@@_exp_bracket_bool    ,
%     \l_@@_exp_combine_bool    ,
%     \l_@@_unit_bracket_bool   ,
%     \l_@@_unit_power_bool     ,
%     \l_@@_unit_repeat_bool    ,
%   }
%   List options.
%    \begin{macrocode}
\bool_new:N \l_@@_boundary_text_bool
\bool_new:N \l_@@_exp_bracket_bool
\bool_new:N \l_@@_exp_combine_bool
\bool_new:N \l_@@_separator_text_bool
\bool_new:N \l_@@_unit_bracket_bool
\bool_new:N \l_@@_unit_power_bool
\bool_new:N \l_@@_unit_repeat_bool
\keys_define:nn { siunitx }
  {
    compound-boundary-mode .choice: ,
    compound-boundary-mode / number .code:n =
      { \bool_set_false:N \l_@@_boundary_text_bool } ,
    compound-boundary-mode / text .code:n =
      { \bool_set_true:N \l_@@_boundary_text_bool } ,
    compound-close-boundary .tl_set:N =
      \l_@@_boundary_close_tl ,
    compound-close-bracket .tl_set:N =
      \l_@@_bracket_close_tl ,
    compound-exponents .choice: ,
    compound-exponents / combine .code:n =
      {
        \bool_set_false:N \l_@@_exp_bracket_bool
        \bool_set_true:N \l_@@_exp_combine_bool
      } ,
    compound-exponents / combine-bracket .code:n =
      {
        \bool_set_true:N \l_@@_exp_bracket_bool
        \bool_set_true:N \l_@@_exp_combine_bool
      } ,
    compound-exponents / individual .code:n =
      {
        \bool_set_false:N \l_@@_exp_bracket_bool
        \bool_set_false:N \l_@@_exp_combine_bool
      } ,
    compound-final-separator .tl_set:N =
      \l_@@_separator_final_tl ,
    compound-independent-prefix .bool_set:N =
      \l_@@_independent_bool , 
    compound-pair-separator .tl_set:N =
      \l_@@_separator_pair_tl ,
    compound-open-boundary .tl_set:N =
      \l_@@_boundary_open_tl ,
    compound-open-bracket .tl_set:N =
      \l_@@_bracket_open_tl ,
    compound-separator .tl_set:N =
      \l_@@_separator_tl ,
    compound-separator-mode .choice: ,
    compound-separator-mode / number .code:n =
      { \bool_set_false:N \l_@@_separator_text_bool } ,
    compound-separator-mode / text .code:n =
      { \bool_set_true:N \l_@@_separator_text_bool } ,
    compound-units .choice: ,
    compound-units / bracket .code:n =
      {
        \bool_set_true:N  \l_@@_unit_bracket_bool
        \bool_set_false:N \l_@@_unit_power_bool
        \bool_set_false:N \l_@@_unit_repeat_bool
      } ,
    compound-units / bracket-power .code:n =
      {
        \bool_set_true:N  \l_@@_unit_bracket_bool
        \bool_set_true:N  \l_@@_unit_power_bool
        \bool_set_false:N \l_@@_unit_repeat_bool
      } ,
    compound-units / power .code:n =
      {
        \bool_set_false:N \l_@@_unit_bracket_bool
        \bool_set_true:N  \l_@@_unit_power_bool
        \bool_set_false:N \l_@@_unit_repeat_bool
      } ,
    compound-units / repeat .code:n   =
      {
        \bool_set_false:N \l_@@_unit_bracket_bool
        \bool_set_false:N \l_@@_unit_power_bool
        \bool_set_true:N  \l_@@_unit_repeat_bool
      } ,
    compound-units / single .code:n   =
      {
        \bool_set_false:N \l_@@_unit_bracket_bool
        \bool_set_false:N \l_@@_unit_power_bool
        \bool_set_false:N \l_@@_unit_repeat_bool
      }  
  }
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\siunitx_compound_number:n}
% \begin{macro}{\@@_format:n}
% \begin{macro}{\@@_format:nn}
% \begin{macro}{\@@_format:nnn, \@@_format:een}
%   Printing a generic set starts with the question of whether we want to
%   extract exponents. If we do, then there is the work to do with extraction.
%   Either way, the printing is handed off to a common function. We do a quick
%   count up-front to avoid excess work when there is not actually a list.
%    \begin{macrocode}
\cs_new_protected:Npn \siunitx_compound_number:n #1
  {
    \group_begin:
      \bool_set_false:N \l_@@_unit_bool
      \@@_format:nn {#1} { }
      \@@_print:N \siunitx_print_number:e
    \group_end:
  }
\cs_new_protected:Npn \@@_format:nn #1#2
  {
    \seq_clear:N \l_@@_tmp_seq
    \bool_if:NTF \l_siunitx_number_parse_bool
      {
        \@@_format:een
          { \tl_head:n {#1} }
          { \tl_tail:n {#1} }
          {#2}
      }
      { \tl_map_function:nN {#1} \@@_unparsed:n }
  }
%    \end{macrocode}
%   Formatting at a low level needs to know about units and numbers: we have to
%   exchange data between the two. Most of the business of handling the units
%   is left to a dedicated auxiliary.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format:nnn #1#2#3
  {
    \tl_if_blank:nTF {#1}
      {
        \tl_if_blank:nF {#2}
          { \@@_format:nn {#2} {#3} }
      }
      { \@@_format_aux:nnn {#1} {#2} {#3} }
  }
\cs_generate_variant:Nn \@@_format:nnn { ee }
\cs_new_protected:Npn \@@_format_aux:nnn #1#2#3
  {
    \siunitx_number_parse:nN {#1} \l_@@_tmp_tl
    \bool_if:NTF \l_@@_unit_bool
      { \@@_format_units:nn {#2} {#3} }
      { \siunitx_number_process:NN \l_@@_tmp_tl \l_@@_first_tl }
    \bool_lazy_and:nnTF
      { \l_@@_exp_combine_bool }
      { \int_compare_p:nNn { \tl_count:n {#2} } > 0 }
      { \@@_extract_exponents: }
      {
        \bool_if:NTF \l_@@_unit_bool
          {
            \tl_set:Nx \l_@@_tmp_tl
              { \siunitx_number_output:NN \l_@@_first_tl \q_nil }
            \tl_set:Nx \l_@@_tmp_tl
              { \@@_uncert_bracket:N \l_@@_tmp_tl }
          }
          {
            \tl_set:Nx \l_@@_tmp_tl
              { \siunitx_number_output:N \l_@@_first_tl }
          }
        \seq_put_right:NV \l_@@_tmp_seq \l_@@_tmp_tl
      }
    \tl_map_function:nN {#2} \@@_parsed:n
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_extract_exponents:}
% \begin{macro}{\@@_extract_exponents_auxi:w}
% \begin{macro}{\@@_extract_exponents_auxii:nw}
% \begin{macro}{\@@_extract_exponents_auxiii:nnnnnnn}
%   Extracting exponents means dealing with the first entry as a special case.
%   After that, apply fixed processing to all other entries, tidying up using
%   the number formatter.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_extract_exponents:
  {
    \tl_set:Nx \l_@@_tmp_tl
      { \siunitx_number_output:NN \l_@@_first_tl \q_nil }
    \exp_after:wN \@@_extract_exponents_auxi:w
      \l_@@_tmp_tl \q_stop
  }
\cs_new_protected:Npn \@@_extract_exponents_auxi:w
  #1 \q_nil #2 \q_nil #3 \q_nil #4 \q_nil #5 \q_nil #6 \q_nil #7 \q_nil #8
  \q_nil #9 \q_stop
  {
    \@@_extract_exponents_auxii:nw {#1#2#3#4#5#6#7#8} #9 \q_stop
  }
\cs_new_protected:Npn \@@_extract_exponents_auxii:nw
  #1#2 \q_nil #3 \q_nil #4 \q_stop
  {
    \seq_put_right:Nn \l_@@_tmp_seq { #1#2 }
    \tl_set:Nn \l_@@_exp_tl { #3#4 }
    \exp_after:wN \@@_extract_exponents_auxiii:nnnnnnn
      \l_@@_first_tl
  }
\cs_new_protected:Npn \@@_extract_exponents_auxiii:nnnnnnn
  #1#2#3#4#5#6#7
  {
    \keys_set:nn { siunitx }
      {
        drop-exponent  = true  ,
        exponent-mode  = fixed ,
        fixed-exponent = #6 0 #7
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_parsed:n, \@@_parsed_aux:n, \@@_unparsed:n}
%   The simple cases for parsing (or not) all entries.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parsed:n #1
  {
    \tl_if_blank:nF {#1}
      { \@@_parsed_aux:n {#1} }
  }
\cs_new_protected:Npn \@@_parsed_aux:n #1
  {
    \bool_if:NTF \l_@@_unit_bool
      {
        \siunitx_number_parse:nN {#1} \l_@@_tmp_tl
        \siunitx_number_process:NN \l_@@_tmp_tl \l_@@_tmp_tl
        \tl_set:Nx \l_@@_tmp_tl
          { \siunitx_number_output:NN \l_@@_tmp_tl \q_nil }
        \tl_set:Nx \l_@@_tmp_tl
          { \@@_uncert_bracket:N \l_@@_tmp_tl }
      }
      { \siunitx_number_format:nN {#1} \l_@@_tmp_tl }
    \seq_put_right:NV \l_@@_tmp_seq \l_@@_tmp_tl
  }
\cs_new_protected:Npn \@@_unparsed:n #1
  {
    \tl_if_blank:nF {#1}
      { \seq_put_right:Nn \l_@@_tmp_seq { \ensuremath {#1} } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_format_units:nn}
% \begin{macro}
%   {
%     \@@_format_combine-exponent:n ,
%     \@@_format_extract-exponent:n ,
%     \@@_format_input:n
%   }
% \begin{macro}
%   {
%     \@@_format_combine-exponent:nn ,
%     \@@_format_extract-exponent:nn
%   }
% \begin{macro}
%   {
%     \@@_format_combine-exponent_aux:n ,
%     \@@_format_extract-exponent_aux:n
%   }
% \begin{macro}{\@@_extract_exp:nN, \@@_extract_exp:VN}
% \begin{macro}{\@@_extract_exp:nnnnnnnN}
%   Actually formatting the units is much the same as is done in
%   the quantities module, except that we have to cover the multiplication
%   cases too: gets a bit repetitive. Notice that when combining exponents,
%   there is no adjustment to the original exponent: we purely need to
%   extract it.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_format_units:nn #1#2
  {
    \bool_if:NTF \l_@@_unit_power_bool
      {
        \use:c { @@_format_ \l_siunitx_quantity_prefix_mode_tl :nn }
          {#2} { \tl_count:n {#1} + 1 }
      }
      {
        \use:c { @@_format_ \l_siunitx_quantity_prefix_mode_tl :n } {#2}
      }
  }
\cs_new_protected:cpx { @@_format_combine-exponent:n } #1
  {
    \exp_not:c { @@_format_combine-exponent_aux:n }
      {
        \exp_not:N \siunitx_unit_format_combine_exponent:nnN
          {#1}
      }
  }
\cs_new_protected:cpx { @@_format_combine-exponent:nn } #1#2
  {
    \exp_not:c { @@_format_combine-exponent_aux:n }
      {
        \exp_not:N \siunitx_unit_format_multiply_combine_exponent:nnnN
          {#1} {#2}
      }
  }
\cs_new_protected:cpn { @@_format_combine-exponent_aux:n } #1
  {
    \bool_set_true:N \l_@@_exp_combine_bool
    \siunitx_number_process:NN \l_@@_tmp_tl \l_@@_first_tl
    \@@_extract_exp:VN
      \l_@@_first_tl \l_@@_tmp_fp
    #1 \l_@@_tmp_fp \l_@@_unit_tl
  }
\cs_new_protected:cpx { @@_format_extract-exponent:n } #1
  {
    \exp_not:c { @@_format_extract-exponent_aux:n }
      { \exp_not:N \siunitx_unit_format_extract_prefixes:nNN {#1} }
  }
\cs_new_protected:cpx { @@_format_extract-exponent:nn } #1#2
  {
    \exp_not:c { @@_format_extract-exponent_aux:n }
      {
        \exp_not:N \siunitx_unit_format_multiply_extract_prefixes:nnNN
          {#1} {#2}
      }
  }
\cs_new_protected:cpn { @@_format_extract-exponent_aux:n } #1
  {
    #1 \l_@@_unit_tl \l_@@_tmp_fp
    \tl_set:Nx \l_@@_tmp_tl
      { \siunitx_number_adjust_exponent:Nn \l_@@_tmp_tl \l_@@_tmp_fp }
    \siunitx_number_process:NN \l_@@_tmp_tl \l_@@_first_tl
    \bool_set_true:N \l_@@_exp_combine_bool
  }
\cs_new_protected:Npn \@@_format_input:n #1
  {
    \siunitx_number_process:NN \l_@@_tmp_tl \l_@@_first_tl
    \siunitx_unit_format:nN {#1} \l_@@_unit_tl
  }
\cs_new_protected:Npn \@@_format_input:nn #1#2
  {
    \siunitx_number_process:NN \l_@@_tmp_tl \l_@@_first_tl
    \siunitx_unit_format_multiply:nnN {#1} {#2} \l_@@_unit_tl
  }
\cs_new_protected:Npn \@@_extract_exp:nN #1#2
  { \@@_extract_exp:nnnnnnnN #1 #2 }
\cs_generate_variant:Nn \@@_extract_exp:nN  { V }
\cs_new_protected:Npn \@@_extract_exp:nnnnnnnN #1#2#3#4#5#6#7#8
  { \fp_set:Nn #8 { #6 0 #7 } }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \siunitx_compound_quantity:nn ,
%     \@@_quantity_auxi:nn          ,
%     \@@_quantity_auxii:nn
%   }
%   For quantities, life is more complex as there are interactions between the
%   options for exponents and units. The \cs{c_empty_tl} suppresses any
%   leading \texttt{1} if the unit starts \cs{per}; the \pkg{siunitx-print}
%   module will skip any printing in this case.
%    \begin{macrocode}
\cs_new_protected:Npn \siunitx_compound_quantity:nn #1#2
  {
    \group_begin:
      \bool_lazy_all:nTF
        {
          { \l_@@_independent_bool }
          {
            \str_if_eq_p:Vn
              \l_siunitx_quantity_prefix_mode_tl
              { combine-exponent }
          }
          { \int_compare_p:nNn { \tl_count:n {#1} } > 1 }
        }
        { \@@_quantity_auxi:nn }
        { \@@_quantity_auxii:nn }
          {#1} {#2}
    \group_end:
  }
%    \end{macrocode}
%   The rather special case where all units are printed independently:
%   we just convert to a simple sequence then print.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_quantity_auxi:nn #1#2
  {
    \@@_print_boundary:V \l_@@_boundary_open_tl
    \seq_clear:N \l_@@_tmp_seq
    \tl_map_inline:nn {#1}
      {
        \seq_put_right:Nn \l_@@_tmp_seq
          { \siunitx_quantity:nn {##1} {#2} }
      }
    \seq_use:Nnnn \l_@@_tmp_seq
      { \@@_print_separator:V \l_@@_separator_pair_tl }
      { \@@_print_separator:V \l_@@_separator_tl }
      { \@@_print_separator:V \l_@@_separator_final_tl }
    \@@_print_boundary:V \l_@@_boundary_close_tl
  }
%    \end{macrocode}
%   The business end for all other cases.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_quantity_auxii:nn #1#2
  {
    \bool_if:NT \l_@@_unit_bracket_bool
      { \bool_set_true:N \l_@@_exp_bracket_bool }
    \bool_if:NT \l_@@_unit_repeat_bool
      { \bool_set_false:N \l_@@_exp_combine_bool }
    \bool_lazy_or:nnT
      { \l_@@_unit_bracket_bool }
      { ! \l_@@_unit_repeat_bool }
      { \bool_set_false:N \l_siunitx_number_bracket_ambiguous_bool }
    \bool_set_true:N \l_@@_unit_bool
    \@@_format:nn {#1} {#2}
    \bool_if:NF \l_siunitx_number_parse_bool
      { \siunitx_unit_format:nN {#2} \l_@@_unit_tl }
    \str_if_eq:VnT \l_siunitx_quantity_prefix_mode_tl { combine-exponent }
      { \tl_clear:N \l_@@_exp_tl }
    \bool_if:NTF \l_@@_unit_repeat_bool
      { \@@_print:N \@@_print_quantity:e }
      {
        \bool_lazy_and:nnTF
          { \l_@@_unit_bracket_bool }
          { \tl_if_empty_p:N \l_@@_exp_tl }
          {
            \siunitx_print_number:V \l_@@_bracket_open_tl
            \@@_print:N \siunitx_print_number:e
            \siunitx_print_number:V \l_@@_bracket_close_tl
          }
          { \@@_print:N \siunitx_print_number:e }
        \@@_print_quantity:n { \c_empty_tl }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_print:N}
% \begin{macro}{\@@_print:nnN, \@@_print:nVN, \@@_print:eeN}
% \begin{macro}{\@@_print:nnnN, \@@_print:ennN}
% \begin{macro}{\@@_print_aux:n}
% \begin{macro}{\@@_print_aux:nn}
% \begin{macro}{\@@_print_quantity:n, \@@_print_quantity:e}
% \begin{macro}
%   {
%     \@@_print_boundary:n, \@@_print_boundary:V,
%     \@@_print_separator:n, \@@_print_separator:V
%   }
%   We now need to know how many entries there are: the reason we don't use
%   \cs{seq_use:Nnnn} is that we want to be able to insert
%   \cs{siunitx_print_\dots:n} in a controlled way.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_print:N #1
  {
    \bool_lazy_and:nnTF
      { \l_@@_exp_bracket_bool }
      { ! \tl_if_empty_p:N \l_@@_exp_tl }
      {
        \@@_print:eeN
          { \exp_not:V \l_@@_bracket_open_tl }
          {
            \exp_not:V \l_@@_bracket_close_tl
            \exp_not:V \l_@@_exp_tl
          }
          #1
      }
      { \@@_print:nVN { } \l_@@_exp_tl #1 }
  }
\cs_new_protected:Npn \@@_print:nnN #1#2#3
  {
    \@@_print:ennN
      { \seq_count:N \l_@@_tmp_seq } {#1} {#2} #3
  }
\cs_generate_variant:Nn \@@_print:nnN { nV , ee }
%    \end{macrocode}
%   A rather long auxiliary as we want a way to have the brackets/exponent
%   available. The actual flow is simple enough: see how many entries there are
%   and print as required. To keep everything generic, we have some slightly
%   tricky saving of data to allow everything to go to the mapping.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_print:nnnN #1#2#3#4
  {
    \int_case:nnF {#1}
      {
        { 0 } { }
        { 1 }
          {
            #4
              { \seq_item:Nn \l_@@_tmp_seq { 1 } }
          }
        { 2 }
          {
            \@@_print_boundary:V \l_@@_boundary_open_tl
            #4
              {
                \exp_not:n {#2}
                \seq_item:Nn \l_@@_tmp_seq { 1 }
              }
            \@@_print_separator:V \l_@@_separator_pair_tl
            #4
              {
                \seq_item:Nn \l_@@_tmp_seq { 2 }
                \exp_not:n {#3}
              }
            \@@_print_boundary:V \l_@@_boundary_close_tl
          }
      }
      {
        \int_set:Nn \l_@@_count_int {#1}
        \tl_set:Nn \l_@@_start_tl {#2}
        \tl_set:Nn \l_@@_end_tl {#3}
        \cs_set_eq:NN \@@_print_aux:n #4
        \@@_print_boundary:V \l_@@_boundary_open_tl
        \seq_map_indexed_function:NN
          \l_@@_tmp_seq
          \@@_print_aux:nn
        \@@_print_boundary:V \l_@@_boundary_close_tl
      }
  }
\cs_generate_variant:Nn \@@_print:nnnN { e }
\cs_new_protected:Npn \@@_print_aux:n #1 { }
\cs_new_protected:Npn \@@_print_aux:nn #1#2
  {
    \int_case:nnF {#1}
      {
        { 1 }
          {
            \@@_print_aux:n
              {
                \exp_not:V \l_@@_start_tl
                \exp_not:n {#2}
              }
            \@@_print_separator:V \l_@@_separator_tl
          }
        { \l_@@_count_int - 1 }
          {
            \@@_print_aux:n { \exp_not:n {#2} }
            \@@_print_separator:V \l_@@_separator_final_tl
          }
        { \l_@@_count_int }
          {
            \@@_print_aux:n
              {
                \exp_not:n {#2}
                \exp_not:V \l_@@_end_tl
              }
          }
      }
      {
        \@@_print_aux:n { \exp_not:n {#2} }
        \@@_print_separator:V \l_@@_separator_tl
      }
  }
\cs_new_protected:Npn \@@_print_quantity:n #1
  { \siunitx_quantity_print:nV {#1} \l_@@_unit_tl }
\cs_generate_variant:Nn  \@@_print_quantity:n { e }
\cs_new_protected:Npn \@@_print_boundary:n #1
  {
    \tl_if_blank:nF {#1}
      {
        \bool_if:NTF \l_@@_boundary_text_bool
          { #1 }
          { \siunitx_print_number:n {#1} }
      }
  }
\cs_generate_variant:Nn \@@_print_boundary:n { V }
\cs_new_protected:Npn \@@_print_separator:n #1
  {
    \bool_if:NTF \l_@@_separator_text_bool
      { #1 }
      { \siunitx_print_number:n {#1} }
  }
\cs_generate_variant:Nn \@@_print_separator:n { V }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[EXP]{\@@_uncert_bracket:N}
% \begin{macro}[EXP]{\@@_uncert_bracket:w}
% \begin{macro}[EXP]{\@@_uncert_bracket:nnw}
%   Check for the case where there is a separate uncertainty but not exponent,
%   when we are handling units.
%    \begin{macrocode}
\cs_new:Npn \@@_uncert_bracket:N #1
  { \exp_after:wN \@@_uncert_bracket:w #1 \q_stop }
\cs_new:Npn \@@_uncert_bracket:w
  #1 \q_nil #2 \q_nil #3 \q_nil #4 \q_nil #5 \q_nil #6 \q_nil #7 \q_nil
  #8 \q_nil #9 \q_stop
  { \@@_uncert_bracket:nnw {#1#2#3#4#5#6} {#7#8} #9 \q_stop }
\cs_new:Npn \@@_uncert_bracket:nnw #1#2 #3 \q_nil #4 \q_nil #5 \q_stop
  {
    \bool_lazy_any:nTF
      {
        { ! \l_@@_unit_repeat_bool }
        { \tl_if_blank_p:n {#2#3} }
        { ! \tl_if_blank_p:n {#5} }
      }
      { \exp_not:n {#1#2#3#4#5} }
      {
        \exp_not:V \l_@@_bracket_open_tl
        \exp_not:n {#1#2#3}
        \exp_not:V \l_@@_bracket_close_tl
        \exp_not:n {#4#5}
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Lists}
%
% Identify the internal prefix.
%    \begin{macrocode}
%<@@=siunitx_list>
%    \end{macrocode}
%
% \begin{variable}
%   {
%     \l_@@_bracket_close_tl             ,
%     \l_@@_independent_bool             ,
%     \l_siunitx_list_separator_tl       ,
%     \l_siunitx_list_separator_final_tl ,
%     \l_@@_bracket_open_tl              ,
%     \l_siunitx_list_separator_pair_tl  ,
%     \l_@@_exp_tl                       ,
%     \l_@@_units_tl
%   }
%   Options for products.
%    \begin{macrocode}
\tl_new:N \l_@@_exp_tl
\tl_new:N \l_@@_units_tl
\keys_define:nn { siunitx }
  {
    list-close-bracket .tl_set:N =
      \l_@@_bracket_close_tl ,
    list-exponents .choices:nn =
      { combine , combine-bracket , individual }
      { \tl_set_eq:NN \l_@@_exp_tl \l_keys_choice_tl } ,
    list-final-separator .tl_set:N = \l_siunitx_list_separator_final_tl ,
    list-independent-prefix .bool_set:N =
      \l_@@_independent_bool ,
    list-open-bracket .tl_set:N =
      \l_@@_bracket_open_tl ,
    list-pair-separator .tl_set:N = \l_siunitx_list_separator_pair_tl ,
    list-separator .tl_set:N = \l_siunitx_list_separator_tl ,
    list-units .choices:nn =
      { bracket , independent , repeat , single }
      { \tl_set_eq:NN \l_@@_units_tl \l_keys_choice_tl }
  }
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\siunitx_number_list:nn}
% \begin{macro}{\siunitx_quantity_list:nn}
% \begin{macro}{\@@_aux:}
%   Simply recover the settings and use as a list.
%    \begin{macrocode}
\cs_new_protected:Npn \siunitx_number_list:nn #1
  {
    \group_begin:
      \@@_aux:
      \siunitx_compound_number:n {#1}
    \group_end:
  }
\cs_new_protected:Npn \siunitx_quantity_list:nn #1#2
  {
    \group_begin:
      \@@_aux:
      \siunitx_compound_quantity:nn {#1} {#2}
    \group_end:
  }
\cs_new_protected:Npn \@@_aux:
  {
    \keys_set:nx { siunitx }
      {
        compound-close-bracket       =
          { \exp_not:V \l_@@_bracket_close_tl } ,
        compound-close-boundary       = ,
        compound-exponents            = \l_@@_exp_tl ,
        compound-final-separator      =
          { \exp_not:V \l_siunitx_list_separator_final_tl } ,
        compound-independent-prefix =
          \bool_if:NTF \l_@@_independent_bool { true } { false } ,
        compound-open-boundary        = ,
        compound-open-bracket         =
          { \exp_not:V \l_@@_bracket_open_tl } ,
        compound-pair-separator       =
          { \exp_not:V \l_siunitx_list_separator_pair_tl } ,
        compound-separator            =
          { \exp_not:V \l_siunitx_list_separator_tl } ,
        compound-separator-mode       = text ,
        compound-units                = \l_@@_units_tl
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Products}
%
% Identify the internal prefix.
%    \begin{macrocode}
%<@@=siunitx_product>
%    \end{macrocode}
%
% \begin{variable}
%   {
%     \l_@@_bracket_close_tl ,
%     \l_@@_exp_tl           ,
%     \l_@@_independent_bool ,
%     \l_@@_bracket_open_tl  ,
%     \l_@@_phrase_bool      ,
%     \l_@@_phrase_tl        ,
%     \l_@@_symbol_tl        ,
%     \l_@@_units_tl
%   }
%   Options for products.
%    \begin{macrocode}
\tl_new:N \l_@@_exp_tl
\bool_new:N \l_@@_phrase_bool
\tl_new:N \l_@@_units_tl
\keys_define:nn { siunitx }
  {
    product-close-bracket .tl_set:N =
      \l_@@_bracket_close_tl ,
    product-exponents .choices:nn =
      { combine , combine-bracket , individual }
      { \tl_set_eq:NN \l_@@_exp_tl \l_keys_choice_tl } ,
    product-independent-prefix .bool_set:N =
      \l_@@_independent_bool ,
    product-mode .choice: ,
    product-mode / phrase .code:n =
      { \bool_set_true:N \l_@@_phrase_bool } ,
    product-mode / symbol .code:n =
      { \bool_set_false:N \l_@@_phrase_bool } ,
    product-open-bracket .tl_set:N =
      \l_@@_bracket_open_tl ,
    product-phrase .tl_set:N = \l_@@_phrase_tl ,
    product-symbol .tl_set:N = \l_@@_symbol_tl ,
    product-units .choices:nn =
      { bracket , bracket-power , independent , power , repeat , single }
      { \tl_set_eq:NN \l_@@_units_tl \l_keys_choice_tl }
  }
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\siunitx_number_product:n}
% \begin{macro}{\siunitx_quantity_product:nn}
% \begin{macro}{\@@_aux:}
% \begin{macro}{\@@_aux:n, \@@_aux:e}
%   Simply recover the settings and use as a list.
%    \begin{macrocode}
\cs_new_protected:Npn \siunitx_number_product:n #1
  {
    \group_begin:
      \@@_aux:
      \siunitx_compound_number:n {#1}
    \group_end:
  }
\cs_new_protected:Npn \siunitx_quantity_product:nn #1#2
  {
    \group_begin:
      \@@_aux:
      \siunitx_compound_quantity:nn {#1} {#2}
    \group_end:
  }
\cs_new_protected:Npn \@@_aux:
  {
    \bool_if:NTF \l_@@_phrase_bool
      { \@@_aux:e { \exp_not:V \l_@@_phrase_tl } }
      { \@@_aux:e { { } \exp_not:V \l_@@_symbol_tl { } } }
  }
\cs_new_protected:Npn \@@_aux:n #1
  {
    \keys_set:nx { siunitx }
      {
        compound-close-boundary       = ,
        compound-close-bracket        =
          { \exp_not:V \l_@@_bracket_close_tl } ,
        compound-exponents            = \l_@@_exp_tl ,
        compound-final-separator      = { \exp_not:n {#1} } ,
        compound-independent-prefix =
          \bool_if:NTF \l_@@_independent_bool { true } { false } ,
        compound-open-boundary        = ,
        compound-open-bracket         =
          { \exp_not:V \l_@@_bracket_open_tl } ,
        compound-pair-separator       = { \exp_not:n {#1} } ,
        compound-separator            = { \exp_not:n {#1} } ,
        compound-separator-mode       =
          \bool_if:NTF \l_@@_phrase_bool { text } { number } ,
        compound-units                = \l_@@_units_tl
      }
  }
\cs_generate_variant:Nn \@@_aux:n { e }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Ranges}
%
% Identify the internal prefix.
%    \begin{macrocode}
%<@@=siunitx_range>
%    \end{macrocode}
%
% \begin{variable}
%   {
%     \l_@@_bracket_close_tl     ,
%     \l_@@_exp_tl               ,
%     \l_@@_independent_bool     ,
%     \l_@@_bracket_open_tl      ,
%     \l_@@_open_tl              ,
%     \l_siunitx_range_phrase_tl ,
%     \l_@@_units_tl
%   }
%   Options for products.
%    \begin{macrocode}
\tl_new:N \l_@@_exp_tl
\tl_new:N \l_@@_units_tl
\keys_define:nn { siunitx }
  {
    range-close-bracket .tl_set:N =
      \l_@@_bracket_close_tl ,
    range-exponents .choices:nn =
      { combine , combine-bracket , individual }
      { \tl_set_eq:NN \l_@@_exp_tl \l_keys_choice_tl } ,
    range-independent-prefix .bool_set:N =
      \l_@@_independent_bool ,
    range-open-bracket .tl_set:N =
      \l_@@_bracket_open_tl ,
    range-open-phrase .tl_set:N = \l_@@_open_tl ,
    range-phrase .tl_set:N = \l_siunitx_range_phrase_tl ,
    range-units .choices:nn =
      { bracket , independent , repeat , single }
      { \tl_set_eq:NN \l_@@_units_tl \l_keys_choice_tl }
  }
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\siunitx_number_range:nn}
% \begin{macro}{\siunitx_quantity_range:nnn}
% \begin{macro}{\@@_aux:}
%   Simply recover the settings and use as a list.
%    \begin{macrocode}
\cs_new_protected:Npn \siunitx_number_range:nn #1#2
  {
    \group_begin:
      \@@_aux:
      \siunitx_compound_number:n { {#1} {#2} }
    \group_end:
  }
\cs_new_protected:Npn \siunitx_quantity_range:nnn #1#2#3
  {
    \group_begin:
      \@@_aux:
      \siunitx_compound_quantity:nn { {#1} {#2} } {#3}
    \group_end:
  }
\cs_new_protected:Npn \@@_aux:
  {
    \keys_set:nx { siunitx }
      {
        compound-boundary-mode        = text ,
        compound-close-boundary       = ,
        compound-close-bracket        =
          { \exp_not:V \l_@@_bracket_close_tl } ,
        compound-exponents            = \l_@@_exp_tl ,
        compound-independent-prefix =
          \bool_if:NTF \l_@@_independent_bool { true } { false } ,
        compound-open-boundary        = { \exp_not:V \l_@@_open_tl } ,
        compound-open-bracket         =
          { \exp_not:V \l_@@_bracket_open_tl } ,
        compound-pair-separator       =
          { \exp_not:V \l_siunitx_range_phrase_tl } ,
        compound-separator-mode       = text ,
        compound-units                = \l_@@_units_tl
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Standard settings for module options}
%
% Some of these follow naturally from the point of definition
% (\foreign{e.g.}~boolean variables are always |false| to begin with),
% but for clarity everything is set here.
%    \begin{macrocode}
\keys_set:nn { siunitx }
  {
    compound-boundary-mode      = text          ,
    compound-close-boundary     =               , % (
    compound-close-bracket      = )             ,
    compound-exponents          = individual    ,
    compound-final-separator    =
      {
        \TextOrMath { \space } { \  }
        \text { and }
        \TextOrMath { \space } { \  }
      } ,
    compound-independent-prefix = false      ,
    compound-open-boundary      =            ,
    compound-open-bracket       = (          , % )
    compound-pair-separator     =
      {
        \TextOrMath { \space } { \  }
        \text { and }
        \TextOrMath { \space } { \  }
      } ,
    compound-separator          =
      { , \TextOrMath { \space } { \  } } ,
    compound-separator-mode     = text       ,
    compound-units              = repeat     , % (
    list-close-bracket          = )          ,
    list-exponents              = individual ,
    list-final-separator        =
      {
        \TextOrMath { \space } { \  }
        \text { and }
        \TextOrMath { \space } { \  }
      } ,
    list-independent-prefix     = false      ,
    list-open-bracket           = (          , % )
    list-pair-separator         =
      {
        \TextOrMath { \space } { \  }
        \text { and }
        \TextOrMath { \space } { \  }
      } ,
    list-separator              =
      { , \TextOrMath { \space } { \  } } ,
    list-units                  = repeat     , % (
    product-close-bracket       = )          ,
    product-exponents           = individual ,
    product-independent-prefix  = false      ,
    product-mode                = symbol     ,
    product-open-bracket        = (          , % )
    product-phrase              =
      {
        \TextOrMath { \space } { \  }
        \text { by }
        \TextOrMath { \space } { \  }
      } ,
    product-symbol             = \times      ,
    product-units              = repeat      , % (
    range-close-bracket        = )           ,
    range-exponents            = individual  ,
    range-independent-prefix   = false       ,
    range-open-bracket         = (           , % )
    range-open-phrase          =             ,
    range-phrase               =
      {
        \TextOrMath { \space } { \  }
        \text { to }
        \TextOrMath { \space } { \  }
      } ,
    range-units                = repeat
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
