    % - Generic macros
    % - Main command: |\UL_to_case:nn|
    % - Casecode tables
    %   - Generic setup
    %   - ULea: |\expandafter:nw|
    %   - ULec: |\UL_expand_csname:n|
    %   - ULexpandsome: |\expandsome|
    %   - ULnil: the default table
    %   - Math mode
    %   - Lower, Upper and Caesar
    % - Tests


    \catcode`\_=11\relax
    \catcode`\:=11\relax




    % ======================== Generic macros

    % A few standard commands to manipulate arguments
    \long\gdef\use_none:n#1{}
    \long\gdef\use_none:nn#1#2{}
    \long\gdef\use_i:nn#1#2{#1}
    \long\gdef\use_ii:nn#1#2{#2}
    \long\gdef\use_ii_i:nn#1#2{#2#1}
    \long\gdef\use_ii_iii_i:nnn#1#2#3{#2#3#1}
    \long\gdef\use_i_bbii:nn#1#2{#1{{#2}}}
    \long\gdef\use_bii_bi:nn#1#2{{#2}{#1}}

    % What expl3 calls "quarks", useful for |\ifx| comparisons.
    \gdef\q_stop{\q_stop}
    \gdef\q_mark{\q_mark}
    \gdef\q_nil{\q_nil}
    \long\gdef\use_none_until_q_stop:w#1\q_stop{}

    % Two tests 
    \long\gdef\UL_if_empty:nTF#1{%
      \expandafter\ifx\expandafter\q_nil\detokenize{#1}\q_nil%
      \expandafter\use_i:nn%
      \else%
      \expandafter\use_ii:nn%
      \fi}

    \expandafter\long\expandafter\gdef\expandafter\UL_if_detok_qmark:wTF%
    \expandafter#\expandafter1\detokenize{\q_mark}#2\q_stop{% 
      \UL_if_empty:nTF{#1}}

    % ======================== Main command: |\UL_to_case:nn|
    % Usage:       |\UL_to_case:nn{<table>}{<text>}|
    % Expands in:  2 steps.
    \long\gdef\UL_to_case:nn{\romannumeral\UL_to_case_aux:nn}
    \long\gdef\UL_to_case_aux:nn#1#2{-`\0%
      \UL_brace_check:nw{#1}#2{\q_mark} \q_stop\UL_to_case_end:n{}}%
    
    % Initially, I used |\q_mark{} \q_stop|: the braces and space are there
    % to avoid runaway arguments in |\UL_brace_check:nw| and 
    % |\UL_space_check:nw|, whose "w" arguments are delimited respectively
    % by an open brace, and by a space. I changed to |{\q_mark} \q_stop|:
    % then we only do the check for |\q_mark| in the case of a brace group, 
    % and not at every step.
    
    % |\UL_to_case_output:n| appends its argument to the argument of
    % |\UL_to_case_end:n|.
    \long\gdef\UL_to_case_output:n#1#2\UL_to_case_end:n#3{%
                                        #2\UL_to_case_end:n{#3#1}}
    \long\gdef\UL_to_case_end:n#1{ #1}
    % And |\UL_to_case_end:n| expands to 
    % - a space, which stops the expansion of |\romannumeral-`\0|,
    % - followed by its argument, which is the result we want.


    % First, we check whether the next token is a brace. 
    \long\gdef\UL_brace_check:nw#1#2#{%
      \UL_if_empty:nTF{#2}%
      {\UL_brace_yes:nn{#1}}%
      {\UL_space_check:nw{#1}#2}%
    }
    % If there is a brace, we might have reached {\q_mark}.
    \long\gdef\UL_brace_yes:nn#1#2{%
      \expandafter\UL_if_detok_qmark:wTF \detokenize{#2 \q_mark}\q_stop{% 
        \use_none_until_q_stop:w% 
      }{% 
        \csname UL_table_#1_braces\endcsname{#1}{#2}%
        \UL_brace_check:nw{#1}%
      }%
    }

    % Then check whether the next token is a space.
    \long\gdef\UL_space_check:nw#1#2 {%
      \UL_if_empty:nTF{#2}%
      {\UL_convert_token:nn{#1}{ }}%
      {\UL_convert_token:nn{#1}#2 }% we put the space back!
    }

    \long\gdef\UL_convert_token:nn#1#2{%
      \ifcsname UL_table_#1_\detokenize{#2}\endcsname%
      \expandafter\use_i:nn%
      \else%
      \expandafter\use_ii:nn%
      \fi% 
      {\csname UL_table_#1_\detokenize{#2}\endcsname}%
      {\csname UL_table_#1_default\endcsname{#2}}%
      \UL_brace_check:nw{#1}% Do the next token.
    }

    
    % ======================== Casecode tables.
    % ============ Generic setup.
    % Typical use:
    % - |\UL_setup:nnn{u}{a}{A}| to define |a| uppercased as |A|.
    % - |\UL_setup_cmd:nnpn{ULnil}{\NoCaseChange}#1{%
    %      \UL_to_case_output:n{#1}}|
    % Note that for the second, we have to grab all the arguments in one go.
    % Also note that the second should not be used until we define the ULec 
    % and ULea tables below.
    %
    % - |\UL_set_eq:nnnn{tableA}{tokenA}{tableB}{tokenB}| sets the entry
    % |tokenA| of the table |tableA| to be equal to the entry |tokenB| of the
    % table |tokenB|.
    % - |\UL_new_table:nn{tableA}{tableB}| creates a new table, |tableA|, 
    % which is a copy of |tableB|.

    \protected\long\gdef\UL_content_of_table_add:nn#1#2{%
      \long\expandafter\gdef\csname UL_table_#1%
      \expandafter\expandafter\expandafter\endcsname%
      \expandafter\expandafter\expandafter{%
        \csname UL_table_#1\endcsname{#2}}%
    }

    \protected\long\gdef\UL_setup:nnn#1#2#3{%
      \UL_content_of_table_add:nn{#1}{#2}%
      \expandafter\long\expandafter\gdef%
      \csname UL_table_#1_\detokenize{#2}\endcsname%
      {\UL_to_case_output:n{#3}}%
    }

    \protected\long\gdef\UL_setup_cmd:nnpn#1#2#3#{%
      \UL_content_of_table_add:nn{#1}{#2}%
      \UL_expand_csname:n{%
        \long\gdef\csname UL_table_#1_\detokenize{#2}\endcsname##1##2{%
          \expandafter:nw{\use_ii_i:nn{##1{##2}}}%
          \csname UL_table_#1_\detokenize{#2}_aux\endcsname}%
      }%
      \use_i_bbii:nn{\expandafter\long\expandafter\gdef%
        \csname UL_table_#1_\detokenize{#2}_aux\endcsname#3}%
    }

    \protected\long\gdef\UL_set_eq:nnnn#1#2#3#4{%
      \UL_content_of_table_add:nn{#1}{#2}%
      {\expandafter}\expandafter\global\expandafter\let%
      \csname UL_table_#1_\detokenize{#2}\expandafter\endcsname%
      \csname UL_table_#3_\detokenize{#4}\endcsname%
    }

    \long\gdef\UL_new_table:nn#1#2{%
      \ifcsname UL_table_#1\endcsname%
      \PackageError{ULcase}{Table \detokenize{#1} already defined!}{}%
      \fi%
      \long\expandafter\gdef\csname UL_table_#1\endcsname{}%
      %
      \def\UL_tmpA{#1}%
      \def\UL_tmpB{#2}%
      \expandafter\expandafter\expandafter\UL_new_table_aux:nnn%
      \csname UL_table_#2\endcsname{}%
    }
    \long\gdef\UL_new_table_aux:nnn#1{%
      \UL_if_empty:nTF{#1}{}{%
        \UL_set_eq:nnnn{\UL_tmpA}{#1}{\UL_tmpB}{#1}%
        \UL_new_table_aux:nnn%
      }%
    }%
    \long\gdef\UL_new_table:n#1{\UL_new_table:nn{#1}{ULnil}}




    % ============ Table ULea, \expandafter:nw
    % 
    % The |ULea| table puts |\expandafter| after each token (including braces
    % and spaces). Allows us to define |\expandafter:nw|, which expands what
    % follows its first argument once. 
    % 
    % |\expandafter:nw| takes 2-steps to act. For a 1-step version, use 
    % |\MEA_trigger:f\MEA_expandafter:nw|. 

    \long\gdef\UL_table_ULea_default#1{\UL_to_case_output:n{\expandafter#1}}%
    \long\gdef\UL_table_ULea_braces#1#2{%
      \expandafter\expandafter\expandafter\UL_to_case_output:n%
      \expandafter\expandafter\expandafter{%
        \expandafter\expandafter\expandafter\expandafter%
        \expandafter\expandafter\expandafter{%
          \UL_to_case:nn{#1}{#2}\expandafter}%
      }%
    }
    \let\MEA_trigger:f\romannumeral
    \def\MEA_expandafter:nw{\UL_to_case_aux:nn{ULea}}
    \def\expandafter:nw{\MEA_trigger:f\MEA_expandafter:nw}


    % ============ Table |ULec|, |\UL_expand_csname:n|
    % The |ULec| table expands only the 
    % |\csname ...\endcsname| constructions.
    % 
    \long\gdef\UL_table_ULec_default{\UL_to_case_output:n}%
    \long\gdef\UL_table_ULec_braces#1#2{%
      \expandafter\expandafter\expandafter\UL_to_case_output:n%
      \expandafter\expandafter\expandafter{%
        \expandafter\expandafter\expandafter{\UL_to_case:nn{#1}{#2}}%
      }%
    }
    \long\expandafter\gdef\csname%
      UL_table_ULec_\detokenize{\csname}\endcsname#1#2{%
      \expandafter:nw{\use_ii_iii_i:nnn{#1{#2}}}%
      \expandafter\UL_to_case_output:n\csname%
    }%

    \def\UL_expand_csname:n{\MEA_trigger:f\UL_to_case_aux:nn{ULec}}


    % ============ Table |ULexpandsome|, |\expandsome|
    % The |ULexpandsome| table expands only the tokens following |\expandthis|.
    % 
    \long\gdef\UL_table_ULexpandsome_default{\UL_to_case_output:n}%
    \long\gdef\UL_table_ULexpandsome_braces#1#2{%
      \expandafter\expandafter\expandafter\UL_to_case_output:n%
      \expandafter\expandafter\expandafter{%
        \expandafter\expandafter\expandafter{\UL_to_case:nn{#1}{#2}}%
      }%
    }
    \long\expandafter\gdef\csname%
      UL_table_ULexpandsome_\detokenize{\expandthis}\endcsname#1#2{%
      \expandafter:nw{#1{#2}}%
      %\expandafter\UL_to_case_output:n\csname%
    }%

    \def\expandsome{\MEA_trigger:f\UL_to_case_aux:nn{ULexpandsome}}


    % ============ The default table, ULnil
    \long\gdef\UL_table_ULnil{{default}{braces}{$}}%$
    \long\gdef\UL_table_ULnil_default{\UL_to_case_output:n}
    \long\gdef\UL_table_ULnil_braces#1#2{%
      \expandafter\expandafter\expandafter\UL_to_case_output:n%
      \expandafter\expandafter\expandafter{%
        \expandafter\expandafter\expandafter{\UL_to_case:nn{#1}{#2}}%
      }%
    }
    \UL_setup_cmd:nnpn{ULnil}{\NoCaseChange}#1{%
      \UL_to_case_output:n{#1}}


    % ============ Working on math mode.
    % 
    % We add \q_mark so that \UL_dollar_aux:nw can read to the next dollar
    % without unbracing the argument, so that ${...}$ --x-> $...$
    \long\expandafter\gdef\csname UL_table_ULnil_\detokenize{$}\endcsname#1#2{%$
        \UL_dollar_aux:nw{#1{#2}}\q_mark%
    }
    % Grab until the next dollar, so #2={\q_mark Math Stuff}. 
    % If \use_none:n #2 is empty, then we had only grabbed `\q_mark`, 
    % which means there was $$, and we need to redo the same business. 
    % Otherwise, we output, after stripping the \q_mark.
    \long\gdef\UL_dollar_aux:nw#1#2${%$%
      \expandafter\UL_if_empty:nTF\expandafter{\use_none:n#2}{% eats \q_mark
        \UL_bidollar:nw{#1}\q_mark%
      }{%
        \expandafter\UL_to_case_output:n\expandafter{%
          \expandafter$\use_none:n#2$}#1%
      }%
    }
    \long\gdef\UL_bidollar:nw#1#2$${%
      \expandafter\UL_to_case_output:n\expandafter{%
        \expandafter$\expandafter$\use_none:n#2$$}#1}



    % =========== Lowercase, Uppercase, Caesar
    \long\gdef\Lowercase{\UL_to_case:nn{lower}}
    \long\gdef\Uppercase{\UL_to_case:nn{upper}}
    \long\gdef\CaesarCipher{\UL_to_case:nn{caesar}}
    
    % Setup the uppercase and lowercase tables.
    \UL_new_table:n{lower}
    \UL_new_table:n{upper}

    \protected\long\gdef\UL_setup_lower_upper:n#1{%
      \UL_if_empty:nTF{#1}{}{%
        \UL_setup:nnn{upper}#1%
        \expandafter:nw{\UL_setup:nnn{lower}}\use_bii_bi:nn#1%
        \UL_setup_lower_upper:n%
      }%
    }
    % should become user-firendly.
    \UL_setup_lower_upper:n {{a}{A}} {{b}{B}} {{c}{C}} {{d}{D}} {{e}{E}} 
    {{f}{F}} {{g}{G}} {{h}{H}} {{i}{I}} {{j}{J}} {{k}{K}} {{l}{L}} {{m}{M}} 
    {{n}{N}} {{o}{O}} {{p}{P}} {{q}{Q}} {{r}{R}} {{s}{S}} {{t}{T}} {{u}{U}} 
    {{v}{V}} {{w}{W}} {{x}{X}} {{y}{Y}} {{z}{Z}} {{\ae}{\AE}} {{\oe}{\OE}} 
    {}


    % Just for fun, we define the Caesar cipher.
    \UL_new_table:n{caesar}
    \begingroup
      \lccode`\x=1\relax
      \loop
        \lccode`\X=\numexpr\lccode`\x+2\relax
        \lowercase{\UL_setup:nnn{caesar}{x}{X}}%
        \lccode`\x=\numexpr\lccode`\x+1\relax
      \unless\ifnum\lccode`\x>126\relax
      \repeat
    \endgroup
    \UL_setup:nnn{caesar}{ }{ }




    % ====== Various tests
    \long\gdef\checkoutput{\ifx\a\b\message{Correct}\else\show\WRONG\fi}

    \long\gdef\expandonce#1{% redefines #1 as #1 expanded once.
      \long\xdef#1{\unexpanded\expandafter\expandafter\expandafter{#1}}}
    \def\0{\1}\def\1{\2}\def\2{\3}\def\3{\4}\def\4{\5}


    % \Uppercase, \Lowercase, \NoCaseChange work (+ nesting)
    % Spaces and braces are fine.
    \long\gdef\a{\Uppercase{ Hello, { } W\Lowercase{O}r\NoCaseChange{lD}! }}
    \expandonce\a\expandonce\a\expandonce\a
    \long\gdef\b{ HELLO, { } W\Lowercase{O}RlD! }
    \checkoutput

    % Another test.
    \long\gdef\a{\Lowercase{He l%
        \NoCaseChange{\Uppercase{ Lp\NoCaseChange{ o}}}o }}
    \expandonce\a\expandonce\a\expandonce\a
    \long\gdef\b{he l\Uppercase{ Lp\NoCaseChange{ o}}o }
    \checkoutput
    \long\edef\a{\a}
    \long\gdef\b{he l LP oo }
    \checkoutput

    % Math works (both $$ and $). Nesting does not break, 
    % although we would wish for better (i.e. "Letter"-> "letter").
    \long\gdef\a{\Lowercase{{t}ExT, $$\frac{A}{B}$$ and $(\mbox{Letter $A$})$}}
    \expandonce\a\expandonce\a\expandonce\a
    \long\gdef\b{{t}ext, $$\frac{A}{B}$$ and $(\mbox{Letter $A$})$}
    \checkoutput

    \edef\a{\CaesarCipher{a{b}cdef@ ABCX}}
    \edef\b{c{d}efghB CDEZ}
    \checkoutput


    \long\gdef\a{\Uppercase{%
        \0{ a${} {{abd}+cd}$\0{b$${\d $0$}$$ }}%
        \NoCaseChange{ Ac dD\relax\0ii}i cd }%
    }
    \expandonce\a\expandonce\a\expandonce\a
    \long\gdef\b{\0{ A${} {{abd}+cd}$\0{B$${\d $0$}$$ }} %
      Ac dD\relax\0iiI CD }%
    \checkoutput



    % More on braces, spaces, and expansion (nothing is expanded, 
    % as we expect).
    \long\gdef\a{\Lowercase{ {} \0 { b{C} {dB\AE~}} \0{\0} }}
    \expandonce\a\expandonce\a\expandonce\a
    \long\gdef\b{ {} \0 { b{c} {db\ae ~}} \0{\0} }
    \checkoutput

    % Testing the ULec table (expanding only \csname)
    \long\gdef\a{\UL_expand_csname:n{ \hello 
        {\csname Hdsf\endcsname}##1\space \csname el\endcsname{ }lo, my name}}
    \expandonce\a\expandonce\a
    \long\gdef\b{ \hello {\Hdsf}##1\space \el{ }lo, my name}
    \checkoutput
    

    % Custom table.
    \UL_new_table:n{mytable}
    \UL_setup:nnn{mytable}{h}{Hello}
    \long\gdef\a{\UL_to_case:nn{mytable}{h{ h} {}\space \h}}
    \expandonce\a\expandonce\a\expandonce\a\expandonce\a
    \long\gdef\b{Hello{ Hello} {}\space \h}
    \checkoutput


    \def\mydo#1#2{(#1)-(#2)}
    \long\gdef\a{\expandsome{\0\0{\expandthis\mydo{\0\expandthis\0}\0\0}}}
    \expandonce\a\expandonce\a
    \long\gdef\b{\0\0{(\0\1)-(\0)\0}}
    \checkoutput

    \long\gdef\a{\Uppercase{\NoCaseChange{The quick brown fox jumps over the lazy dog.} The quick brown fox jumps over the lazy dog. \NoCaseChange{The quick brown fox jumps over the lazy dog.} The quick brown fox jumps over the lazy dog. \NoCaseChange{The quick brown fox jumps over the lazy dog.} The quick brown fox jumps over the lazy dog. \NoCaseChange{The quick brown fox jumps over the lazy dog.} The quick brown fox jumps over the lazy dog. \NoCaseChange{The quick brown fox jumps over the lazy dog.} The quick brown fox jumps over the lazy dog. \NoCaseChange{The quick brown fox jumps over the lazy dog.} The quick brown fox jumps over the lazy dog. \NoCaseChange{The quick brown fox jumps over the lazy dog.} The quick brown fox jumps over the lazy dog. }}
    \begingroup\tracingall\tracingonline=0\relax
    \expandonce\a\expandonce\a\expandonce\a
    \endgroup
    \long\gdef\b{The quick brown fox jumps over the lazy dog. THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG. The quick brown fox jumps over the lazy dog. THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG. The quick brown fox jumps over the lazy dog. THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG. The quick brown fox jumps over the lazy dog. THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG. The quick brown fox jumps over the lazy dog. THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG. The quick brown fox jumps over the lazy dog. THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG. The quick brown fox jumps over the lazy dog. THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG. }
    \checkoutput

    % % Questionable!
    % \usepackage{MultiExpand}
    % \long\gdef\ExpandAfter:nnw#1#2{%
    %   \unless\ifcsname\multiexpand\fi{3}%
    %   \UL_to_case:nn{ULea}{#2}%
    %   \unless\ifcsname\multiexpand\fi{#1}%
    % }
    % % Some test of \ExpandAfter:nnw.
    % \long\gdef\a{\ExpandAfter:nnw{3}{\0bc}\ExpandAfter:nnw{2}\0\0}
    % \expandonce\a  \expandonce\a
    % \long\gdef\b{\0bc\1\2}
    % \checkoutput
