% Features
% --------

% * List elements are parsed in the same familiar way that TeX macro
%   arguments are parsed.  Thus:
%
%   * Any brace-balanced token sequence can be treated as a list.
%   * Leading/trailing spaces and spaces between elements are ignored.
%   * Lists do not need to contain separators or terminators.

% * The macros have powerful features to support flexible use.
%
%   * Templates are used for handling the results of the macros, as
%     well as for handling each list element in \dolist.  For example,
%     the token sequence
%
%       \listcase{{head of list}{tail}{of}{list}}{nil case}{\foo{#2{#1}}}
%
%     has the same effect as
%
%       \foo{{tail}{of}{list}{head of list}}
%
%     because #1 gets replaced by "head of list" and #2 gets replaced
%     by "{tail}{of}{list}".
%
%   * \dolist has support for maintaining 7 loop variables,
%     accessing the values from the previous iteration via #2 through
%     #8, and passing values to the next iteration via \DLNext.  For
%     example, the token sequence
%
%       \dolist{{abc}{def}{ghi}}{{initial}}
%         {previous value: #2; current item: #1. \DLNext{{#1}}}
%         {last value: #2.}
%
%     has the same effect as:
%
%       previous value: initial; current item: abc.
%       previous value: abc; current item: def.
%       previous value: def; current item: ghi.
%       last value: ghi.
%     
%     This supports powerful list transformations.  For example,
%     define the following macro:
%
%       \newcommand{\ReverseList}[2]
%         {\dolist{#1}{}{\DLNext{{{##1}##2}}}{#2}}
%     
%     Then we can observe these effects:
%
%       \ReverseList{{1}{2}{3}}{\foo{#1}} -> \foo{{3}{2}{1}}
%       \ReverseList{palindrome}{#1} -> {e}{m}{o}{r}{d}{n}{i}{l}{a}{p}
%
%     (Thus revealing that "palindrome" is not a palindrome.)
%     This works because #1 in the continuation gets replaced by the
%     accumulated reversed value.  In fact, the following macro
%     definition is equivalent:
%
%       \newcommand{\ReverseList}[1]
%         {\dolist{#1}{}{\DLNext{{{##1}##2}}}}
%
%     As another example, we can define a macro to put commas or
%     spaces in numbers every three places to the left of the decimal
%     mark:
%
%       \newcommand{\InsertThousandsMarks}[2]
%         {% #1 is THOUSANDS_SEPARATOR
%          % #2 is NUMBER
%          % Remaining input prefix: CONTINUATION (which may mention #1)
%          \dolist{#2}{}
%            {% ##1 is DIGIT
%             % ##2 is digits before decimal mark in form 1 234 567 890
%             % ##3 is digits before decimal mark in form 12 345 678 90
%             % ##4 is digits before decimal mark in form 123 456 789 0
%             % ##5 is decimal mark and everything after it
%             \ifthenelse{\equal{##5}{}\and
%                         \(\equal{##1}{0}\or\equal{##1}{1}\or
%                           \equal{##1}{2}\or\equal{##1}{3}\or
%                           \equal{##1}{4}\or\equal{##1}{5}\or
%                           \equal{##1}{6}\or\equal{##1}{7}\or
%                           \equal{##1}{8}\or\equal{##1}{9}\)}
%               {\ifthenelse{\equal{##2}{}}
%                  % Don't put separators before first digit.
%                  {\DLNext{{##1}{##1}{##1}}}
%                  % We've seen some digits, add separator to ##4.
%                  {\DLNext{{##3##1}{##4##1}{##2#1##1}}}}
%               % We've seen the decimal mark.
%               {\DLNext{{##2}{##3}{##4}{##5##1}}}}
%            {\usetemplate{{##2##5}}}}
%
%     With this macro, we have these results:
%
%          \InsertThousandsMarks{,}{7419876.4235}{The result: [#1]}
%       -> The result: [7,419,876.4235]

% * Missing drawbacks:
%
%   * None of the macros execute their arguments inside a group.
%   * Nested invocations work correctly.
%   * No registers are used.
%   * Macros that need it have been defined with \DeclareRobustCommand.

% Lists
% -----

% Any brace-balanced sequence of tokens (including annoying tokens
% such as "#", \iffalse, \else, \fi, etc.) is a valid list.

% The elements of a list can be determined as follows.  Any initial
% space tokens (anything that would be skipped by TeX when looking for
% an undelimited macro parameter) are ignored.  If that is all the
% list contains, then the list is empty and has zero elements.
% Otherwise, the head (first element) of the list is the argument that
% would be found by TeX when looking for an undelimited macro
% parameter with the list being the next input and the tail is the
% input that would be left over.

% This means that if the list is of the form "{XXX}YYY'' where XXX is
% brace-balanced, then the head is XXX and the tail is YYY.  It is
% generally wisest to write a list in the following form with braces
% around each element:
%
%   {ELEM_1}{ELEM_2}...{ELEM_n}
%
% Leading/trailing spaces and spaces in between the elements are okay.

% Known Problems
% --------------

% * LaTeX's implementation (or probably, any possible implementation)
% of optional arguments has the result that a list of length 1 used as
% an optional argument will have any braces around its sole element
% stripped off.  If that element consists of more than one token, then
% the element's contents will be treated as a list, which is almost
% certainly the wrong thing to do and will cause havoc.  The way
% around this problem is to always wrap lists with an extra pair of
% braces when passing them as optional arguments.  A macro taking an
% optional list argument will then be responsible for removing the
% extra braces.

% * Algorithms using \listcase which do something for each element of
% a list will have time complexity that is at least quadratic in the
% length of the lists.  There seems to be no way to make \listcase any
% more efficient.  If an algorithm needs to work with long lists, it
% is better to structure it using \dolist instead.

% Implementation Dependencies
% ---------------------------

% The implementation depends on this LaTeX internal macro:
%
%   \@gobble
%
% As this macro is undocumented, future LaTeX implementations might
% not supply a macro with the same name and compatible behavior, in
% which case this implementation will fail.

% Design Issues
% -------------

% In TeX, Whenever the token sequence matching a parameter is of the
% shape {<balanced-tokens>} where <balanced-tokens> is some sequence
% of tokens which is balanced w.r.t. braces, then the actual argument
% becomes just the <balanced-tokens> subsequence.  There is no way to
% test whether this has happened that will work in all circumstances.

% In the implementation of \listcase, we would like to match against a
% list of the form "{ELEM_1}{ELEM_2}...{ELEM_n}" and separately
% extract the head "{ELEM_1}" and the tail "{ELEM_2}...{ELEM_n}".  The
% problem is when the list is two elements long, the tail is just
% "{ELEM_2}" and if the tail token sequence matches an argument, then
% the braces will be stripped off.

% We get around this problem by extracting the tail from the list
% separately, after having determined that the list is not empty.  If
% #1 contains the list, then the tail can be extracted via:
%
%   \expandafter{\@gobble#1}
%
% This makes sure the tail is always surrounded by an extra pair of
% braces, so that when the tail is a list of length 1 and the
% expansion of the above is used as an argument, the braces around the
% tail's sole element are protected.

% Historical note: A way to get around this which was used in an
% earlier implementation is to have #2 match the entire list, #3 match
% the head (losing its braces), and #4 match the tail.  We then test
% if "#2" and "{#3}#4" are the same, allowing us to give special
% treatment to the case when the tail loses the braces around its only
% element.  The problem with this approach is that testing if "#2" and
% "{#3}#4" are the same requires putting them in the body of macro
% definitions, which can fail when the list contains "#" tokens.  Plus
% it is more expensive.

% Notation for Describing Substitutions
% -------------------------------------
%
% If X is some sequence of tokens that contains some number (possibly
% zero) of occurrences of the token # followed by a token from the set
% {1, 2, ..., n} where 0 <= n <= 9, and Y_1, Y_2, ..., Y_n are token
% sequences, then X(Y_1,...,Y_n) stands for the token sequence
% resulting from transforming X by replacing all occurrences of #i by
% Y_i for 1 <= i <= n.

% ----------------------------------------------------------------------

\RequirePackage{jbw-prog-util}
\newcommand{\jbwl@PackageName}{jbw-list}

% ----------------------------------------------------------------------

\DeclareRobustCommand{\listcase}[1]
  %
  % Invoke as follows:
  %
  %   \listcase{LIST}{NIL_CASE}{CONS_CASE}
  %
  % CONS_CASE is allowed to contain #1 and #2 (which will usually have
  % to be written as ##1 and ##2 in the invocation).
  %
  % The behavior is as follows:
  %
  %   \listcase{}          {NIL_CASE}{CONS_CASE} -> NIL_CASE
  %   \listcase{{HEAD}TAIL}{NIL_CASE}{CONS_CASE} -> CONS_CASE(HEAD,TAIL)
  % 
  {% #1 is LIST
   % Remaining input prefix: {NIL_CASE}{CONS_CASE}
   \ParseArgs
     {#1\jbwl@Mark\jbwl@Mark*\jbwl@Mark{#1}}
     {##1##2\jbwl@Mark##3##4\jbwl@Mark##5##6##7}
     {% If LIST is empty:
      %   ##1 is \jbwl@Mark
      %   ##2 is empty
      %   ##3 is *
      %   ##4 is empty
      % If LIST is POSSIBLY_WRAPPED_HEAD TAIL
      %   ##1 is HEAD
      %   ##2 is junk (POSSIBLY_STRIPPED_TAIL)
      %   ##3 is \jbwl@Mark
      %   ##4 is *
      % ##5 is LIST
      % ##6 is NIL_CASE
      % ##7 is CONS_CASE
      %
      % It is important that ##4 is guaranteed not to contain \ifXXX,
      % \else, \fi, or !.  If ##4 is not empty, then the second ! will
      % actually be part of the "then" branch of the \if, but that's okay
      % because in that case the "else" branch is taken.
      \IfChar{!##4!}
        {% LIST is empty.
         ##6}
        {% LIST is non-empty.
         \ExpandFirst{{\@gobble##5}{##1}}
           {% ####1 is TAIL
            % ####2 is HEAD
            \usetemplate{{####2}{####1}}}%
              % indented arg of \usetemplate, though not of \ExpandFirst
              {##7}}}}
% **********************************************************************
\DeclareRobustCommand{\OLDlistcase}[1]
  %
  % Invoke as follows:
  %
  %   \listcase{LIST}{NIL_CASE}{CONS_CASE}
  %
  % CONS_CASE is allowed to contain #1 and #2 (which will usually have
  % to be written as ##1 and ##2 in the invocation).
  %
  % The behavior is as follows:
  %
  %   \listcase{}          {NIL_CASE}{CONS_CASE} -> NIL_CASE
  %   \listcase{{HEAD}TAIL}{NIL_CASE}{CONS_CASE} -> CONS_CASE(HEAD,TAIL)
  % 
  {% #1 is LIST
   % Remaining input prefix: {NIL_CASE}{CONS_CASE}
   \jbwl@ListCaseAuxA#1\jbwl@Mark\jbwl@Mark*\jbwl@Mark{#1}}
\def\jbwl@ListCaseAuxA#1#2\jbwl@Mark#3#4\jbwl@Mark#5#6#7%
  {% If LIST is empty:
   %   #1 is \jbwl@Mark
   %   #2 is empty
   %   #3 is *
   %   #4 is empty
   % If LIST is POSSIBLY_WRAPPED_HEAD TAIL
   %   #1 is HEAD
   %   #2 is junk (POSSIBLY_STRIPPED_TAIL)
   %   #3 is \jbwl@Mark
   %   #4 is *
   % #5 is LIST
   % #6 is NIL_CASE
   % #7 is CONS_CASE
   %
   % It is important that #4 is guaranteed not to contain \ifXXX,
   % \else, \fi, or !.  If #4 is not empty, then the second ! will
   % actually be part of the "then" branch of the \if, but that's okay
   % because in that case the "else" branch is taken.
   \IfChar{!#4!}
     {% LIST is empty.
      #6}
     {% LIST is non-empty.
      \ExpandFirst{{\@gobble#5}{#1}}
        {% ##1 is TAIL
         % ##2 is HEAD
         \usetemplate{{##2}{##1}}}%
           % indented because arg of \usetemplate, though not of \ExpandFirst
           {#7}}}
%**********************************************************************
% \def\OLDjbwl@ListCaseAuxA#1#2\jbwl@Mark#3#4\jbwl@Mark{%
%   % If LIST is empty:
%   %   #1 is \jbwl@Mark
%   %   #2 is empty
%   %   #3 is *
%   %   #4 is empty
%   % If LIST is POSSIBLY_WRAPPED_HEAD TAIL
%   %   #1 is HEAD
%   %   #2 is junk (POSSIBLY_STRIPPED_TAIL)
%   %   #3 is \jbwl@Mark
%   %   #4 is *
%   % Remaining input prefix: {LIST}{NIL_CASE}{CONS_CASE}
%   %
%   % It is important for the next line that #4 is guaranteed not to
%   % contain \ifXXX, \else, or \fi.
%   \if!#4!%
%     % LIST is empty.
%     % This will have the effect of: NIL_CASE
%     \expandafter\jbwl@ThirdOfFour
%   \else
%     % LIST is non-empty.
%     \expandafter\jbwl@ListCaseAuxB
%   \fi
%   {#1}}
% \newcommand{\jbwl@ThirdOfFour}[4]{#3}
% \newcommand{\jbwl@ListCaseAuxB}[2]
%   {% #1 is HEAD
%    % #2 is LIST
%    % Remaining input prefix: {NIL_CASE}{CONS_CASE}
%    \expandafter\jbwl@ListCaseAuxC\expandafter{\@gobble#2}{#1}}
% \newcommand{\jbwl@ListCaseAuxC}[3]
%   {% #1 is TAIL
%    % #2 is HEAD
%    % #3 is junk (NIL_CASE)
%    % Remaining input prefix: {CONS_CASE}
%    \usetemplate{{#2}{#1}}}

% ----------------------------------------------------------------------

\DeclareRobustCommand{\ziplist}
  %
  % Invoke as follows:
  %
  %   \ziplist{LIST_1}{LIST_2}{CONTINUATION}
  %
  % LIST_1 and LIST_2 must be valid lists.
  % Let LIST_1 be: {ELEM_1_1} ... {ELEM_1_n}
  % Let LIST_2 be: {ELEM_2_1} ... {ELEM_2_m}
  % Let p = min(n,m).
  % For 1 <= i <= p, let ELEM_3_i be: {ELEM_1_i}{ELEM_2_i} 
  % Let LIST_3 be: {ELEM_3_1} ... {ELEM_3_p}
  % 
  % CONTINUATION is allowed to contain the token #1 (which will
  % usually have to be written as ##1 in the invocation).
  % 
  % The behavior is as follows:
  %
  %   \ziplist{LIST_1}{LIST_2}{CONTINUATION} -> CONTINUATION(LIST_3)
  %
  {% Remaining input prefix: {LIST_1}{LIST_2}{CONTINUATION}
   % Start the loop with an empty accumulator.
   \jbwl@ZipListLoop{}}
\newcommand{\jbwl@ZipListLoop}[3]
  % #1 is RESULT (the accumulated zipped list)
  % #2 is LIST_1
  % #3 is LIST_2
  % Remaining input prefix: {CONTINUATION}
  {\listcase{#2}% Test whether LIST_1 is empty.
     {\usetemplate{{#1}}}% If LIST_1 is empty, pass result to CONTINUATION.
     {% ##1 is HEAD_1
      % ##2 is TAIL_1
      \listcase{#3}% Test whether LIST_2 is empty.
        {\usetemplate{{#1}}}% If LIST_2 is empty, pass result to CONTINUATION.
        {% ####1 is HEAD_2
         % ####2 is TAIL_2
         % Append pair {{HEAD_1}{HEAD_2}} to end of result.
         % Process the list tails recursively.
         \jbwl@ZipListLoop{#1{{##1}{####1}}}{##2}{####2}}}}

% ----------------------------------------------------------------------

\DeclareRobustCommand{\dolist}[3]
  %
  % Invoke as:
  %
  %   \dolist{LIST}{VALUES}{ELEM_HANDLER}{CONTINUATION}
  %
  % LIST is {ELEM_1}...{ELEM_m}  where m >= 0
  % VALUES is {VAL_2}...{VAL_n}    where 1 <= n <= 8
  % ELEM_HANDLER may contain #1, ..., #8
  % CONTINUATION may contain #1, ..., #8
  % VAL_i is nothing for i in {n+1, ..., 8}
  % 
  % There is support for 7 loop values.  The values from the previous
  % iteration (or from the invocation in the case of the first
  % iteration) are accessed in ELEM_HANDLER and CONTINUATION as #2,
  % ... #8.  In CONTINUATION, the value for #2 is also available as
  % #1.  Values are passed to the next iteration (or the continuation)
  % via \DLNext and \DLLast.
  %
  % The action goes as follows.
  %
  % 1. If m = 0, i.e., LIST is empty, then do:
  %
  %      CONTINUATION(VAL_2,VAL_2,...,VAL_8)
  %
  % 2. Otherwise, do the following, which we will call *:
  %
  %      ELEM_HANDLER(ELEM_1,VAL_2,...,VAL_8)
  %
  %    The subsequent action depends on what * does.
  %    
  %    A. If * ends with \DLNext{VALUES}, then do (the equivalent of):
  %
  %         \dolist{{ELEM_2}...{ELEM_m}}{VALUES}{ELEM_HANDLER}{CONTINUATION}
  %
  %    B. If * ends with \DLLast{VALUES}, then do (the equivalent of):
  %
  %         \dolist{}{VALUES}{ELEM_HANDLER}{CONTINUATION}
  %
  %    C. If * ends without invoking \DLNext or \DLLast, then act as
  %       if it ended with \DLNext{}.
  %
  %    D. If * looks at any input following it, all hell will break
  %       loose.  The execution of * must not do this.
  %
  % Here are some examples.  A simple usage is
  %
  %   \dolist{{A}{B}{C}}{}{#1!}{}
  %
  % which when executed does:
  %
  %   A!B!C!
  % 
  % A more complicated usage is
  %
  %   \dolist{{B}{C}{D}}{{A}}{(#1,#2)\DLNext{{#1}}}{ last letter: #2}
  %
  % which when executed does:
  %
  %   (B,A)(C,B)(D,C) last letter: D
  %
  {% #1 is LIST
   % #2 is VALUES
   % #3 is ELEM_HANDLER
   % Remaining input prefix: {CONTINUATION}
   \DLNext{#2}\jbwl@MarkA{#3}#1\jbwl@MarkB}
%
% STATE_LAYOUT is CODE\jbwl@MarkA{ELEM_HANDLER}LIST\jbwl@MarkB{CONTINUATION}
% 
\newcommand{\jbwl@MarkA}
  {% If this is executed, then we pretend the last thing ELEM_HANDLER
   % did was \DLNext{}.
   \DLNext{}\jbwl@MarkA}
% The definition of \jbwl@MarkB ensures that no other token will be
% considered the same as \jbwl@MarkB by \ifx.  It is small (two
% tokens), so it can be compared quickly.  If it is ever executed or
% expanded in an \edef, an error will result.
\newcommand{\jbwl@MarkB}{\jbwl@MarkBError:}
\newcommand{\jbwl@MarkBError}[1]
  {% #1 is :          (the bogus extra token added to force expansion death)
   \PackageError{\jbwl@PackageName}
     {Something horrible has happened: jbwl@MarkB control sequence used!}
     {No additional help.}}
\newcommand{\jbwl@CheckMarkA}[1]
  {% #1 is CONTROL_SEQUENCE
   % Die if CONTROL_SEQUENCE is not \ifx-equal to \jbwl@MarkA.
   \ifx\jbwl@MarkA#1\else\jbwl@CheckMarkAError\fi}
% The error message is in separate macro to make expansion of
% \jbwl@CheckMarkA go faster in the normal case.
\newcommand{\jbwl@CheckMarkAError}
  {\PackageError{\jbwl@PackageName}
     {Something horrible has happened: jbwl@MarkA control sequence
      not in expected place!}
     {No additional help.}}
\newcommand{\DLNext}[1]
  {% #1 is VALUES
   % If LIST non-empty, remaining input prefix is:
   %   \jbwl@MarkA{ELEM_HANDLER}{HEAD}TAIL\jbwl@MarkB{CONTINUATION}
   % If LIST empty:
   %   \jbwl@MarkA{ELEM_HANDLER}\jbwl@MarkB{CONTINUATION}
   %\TraceOn
   \Grab{\jbwl@Tok}
     {\jbwl@CheckMarkA{\jbwl@Tok}%
      \ParseArgs{{#1}}{##1##2##3}
        {% ##1 is VALUES
         % ##2 is ELEM_HANDLER
         % If LIST non-empty:
         %   ##3 is HEAD
         %   Remaining input prefix is TAIL\jbwl@MarkB{CONTINUATION}
         % If LIST empty:
         %   ##3 is \jbwl@MarkB
         %   Remaining input prefix is TAIL\jbwl@MarkB{CONTINUATION}
         % We are going to place ##3 back on the input.  We
         % only picked it up to get rid of any leading spaces so we
         % can then test whether it is \jbwl@MarkB.  We have to test
         % it carefully because HEAD can contain any token.
         \Peek{\jbwl@Tok}
           {\IfX{\jbwl@Tok\jbwl@MarkB}
              {\EatTokens{2}
                 {\jbwl@DoListInvokeContinuation{##1}}}
              {\ParseArgs{{##1}{##2}{##3}}{####1####2####3####4\jbwl@MarkC}
                 {% ####1 is VALUES
                  % ####2 is ELEM_HANDLER
                  % ####3 is HEAD
                  % ####4 is junk
                  \usetemplate{{####3}####1}{####2}%
                  \jbwl@MarkA{####2}}}}%
         ##3\jbwl@MarkC}}}
%**********************************************************************
\newcommand{\OLDDLNext}[4]
  {% #1 is VALUES
   % #2 is \jbwl@MarkA
   % #3 is ELEM_HANDLER
   % If LIST non-empty:
   %   #4 is HEAD
   %   Remaining input prefix: TAIL\jbwl@MarkB{CONTINUATION}
   % If LIST empty:
   %   #4 is \jbwl@MarkB
   %   Remaining input prefix: {CONTINUATION}
   \jbwl@CheckMarkA{#2}%
   % We have to do this careful checking of whether #4 is \jbwl@MarkB
   % because if #4 is HEAD, it can contain \ifXXX, \else, and \fi
   % tokens which could screw up \iffalse ... \else skipping.
   % Fortunately, #4 is guaranteed to be brace-balanced, so we can
   % skip it as an argument.
   \futurelet\jbwl@MarkBTemp\jbwl@NextInt#4\jbwl@MarkC{#1}{#3}{#4}}
\def\jbwl@NextInt#1\jbwl@MarkC
  {% If LIST non-empty:
   %   \jbwl@MarkBTemp is \let-equal to the first token of HEAD
   %   #1 is junk (HEAD, but may have had braces stripped, so can't use it)
   %   Remaining input prefix:
   %     {VALUES}{ELEM_HANDLER}{HEAD}TAIL\jbwl@MarkB{CONTINUATION}
   % If LIST empty:
   %   \jbwl@MarkBTemp is \let-equal to \jbwl@MarkB
   %   #1 is junk (\jbwl@MarkB)
   %   Remaining input prefix: 
   %     {VALUES}{ELEM_HANDLER}{\jbwl@MarkB}{CONTINUATION}
   \ifx\jbwl@MarkB\jbwl@MarkBTemp
     \expandafter\jbwl@DoListDone
   \else
     \expandafter\jbwl@DoListMore
   \fi}
\newcommand{\jbwl@DoListDone}[3]
  {% #1 is VALUES
   % #2 is junk (ELEM_HANDLER)
   % #4 is junk (\jbwl@MarkB)
   % Remaining input prefix: {CONTINUATION}
   \jbwl@DoListInvokeContinuation{#1}}
\newcommand{\jbwl@DoListMore}[3]
  {% #1 is VALUES
   % #2 is ELEM_HANDLER
   % #3 is HEAD
   % Remaining input prefix: TAIL\jbwl@MarkB{CONTINUATION}
   % This restores the STATE_LAYOUT documented above.
   \usetemplate{{#3}#1}{#2}\jbwl@MarkA{#2}}
\def\DLLast#1#2#3#4\jbwl@MarkB{%
   % #1 is VALUES
   % #2 is \jbwl@MarkA
   % #3 is junk (ELEM_HANDLER)
   % #4 is junk (LIST)
   % Remaining input prefix: {CONTINUATION}
   \jbwl@CheckMarkA{#2}%
   \jbwl@DoListInvokeContinuation{#1}}
\newcommand{\jbwl@DoListInvokeContinuation}[1]
  {% #1 is VALUES is {VAL_2}...{VAL_n} where 1 <= n <= 8
   % Remaining input prefix: {CONTINUATION}
   % VAL_i is nothing for i in {n+1, ..., 8}
   % This will invoke CONTINUATION(VAL_2,VAL_2,...,VAL_8)
   % Note that VAL_2 becomes both #1 and #2 in CONTINUATION.
   \expandafter
   % The {} on the next line is in case #1 is empty.
   \usetemplate\expandafter{\jbwl@DuplicateArg#1{}}}
\newcommand{\jbwl@DuplicateArg}[1]{{#1}{#1}}

% Local variables:
% tex-main-file: "jbw-list-test.tex"
% end:
