Martin Scharrer
2009-04-27 21:41:17 UTC
Hi,
I recently had the idea about a switch case statement for use in LaTeX
packages. I needed to check user input (a string) and execute
different macros on different inputs. of a list. Because I could not
find a switch-case statement I implemented it using code like this:
\def\@tempa{foo}
\ifx\@tempa\***@input
...
\else
\def\@tempa{bar}
\ifx\@tempa\***@input
...
\fi\fi
Now I found the time to code a switch-case statement in plainTeX:
My idea about the syntax is:
\switch{<input value>}
\case{<case 1 value>}{<case 1 code}
\case{<case 2 value>}{<case 2 code}
...
\case{<case n value>}{<case n code}
\default{<default code>}
\endswitch
Instead of \endswitch there could also be \hctiws (switch reversed
like \fi for \if).
I also implemented versions of \switch and \case which expand there
argument: \eswitch, \ecase ('e' like 'edef'), or
check the definition instead the content: \switchx, \casex ('x' like
'ifx'). The different \switch and \case macros can be mixed.
The switch-statement stores the code in a macro similar to macros like
\@ifnextchar and uses a TeX group to localise its internal macros. The
code of the selected switch is then executed after the end of the
group. This makes the switch cascade-able and allows the case code to
include macros which read the tokens after the \endswitch.
Here my code. It is not yet fully tested. Comments are very welcome. I
might provide this as a package. Any suggestion about a name? Maybe
'switch' or 'swcase'. 'switchcase' might be too long.
%%%%%%%%%%% switch.tex %%%%%%%%%%%%%
\catcode`\@=\catcode`\A
% Normal (no expansion):
\def\switch#1{%
\begingroup
\let\***@exec\empty
\def\***@want{#1}%
\ignorespaces
}
\def\case#1#2{%
\def\***@might{#1}%
\ifx\***@might\***@want
\def\***@exec{#2}%
\expandafter\***@skiprest
\fi
\ignorespaces
}
% Expansion of the argument ('e' as in 'edef'):
\def\eswitch#1{%
\begingroup
\let\***@exec\empty
\edef\***@want{#1}%
\ignorespaces
}
\def\ecase#1#2{%
\edef\***@might{#1}%
\ifx\***@might\***@want
\def\***@exec{#2}%
\expandafter\***@skiprest
\fi
\ignorespaces
}
% Check definition not content ('x' as in 'ifx'):
\def\switchx#1{%
\begingroup
\let\***@exec\empty
\let\***@want#1\relax
\ignorespaces
}
\def\casex#1#2{%
\ifx\***@want#1\relax
\def\***@exec{#2}%
\expandafter\***@skiprest
\fi
\ignorespaces
}
% Default case. Identical for all different switch statements.
\def\default#1{%
\def\***@exec{#1}%
\***@skiprest
}
\def\***@skiprest#1\endswitch{%
\expandafter\***@realend
\expandafter{\***@exec}%
}
\def\***@realend#1{%
\endgroup
#1%
}
\def\endswitch{%
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Some Testcases:
\newlinechar=`^^J
\def\test#1{%
\switch{#1}
\case{test1}{\message{test1^^J}}
\case{test2}{\message{test2^^J}}
\case{test3}{\message{test3^^J}}
\case{test4}{\message{sub-switch 1:^^J }
\switch{abc}
\case{a}{\message{a^^J}}
\case{ab}{\message{ab^^J}}
\case{abc}{\message{abc^^J}}
\endswitch
}
\case{test5}{\message{sub-switch 2:^^J }\test{test1}}
\default{\message{default^^J}}
\endswitch
}
\message{^^J switch: ^^J}
\test{test1}
\test{test4}
\test{other}
\test{test5}
\def\testveca{test1}
\def\testvecb{test2}
\def\testvecc{test3}
\def\testvecd{test4}
\let\testwant\testvecb
\message{^^J switchx: ^^J}
\switchx{\testwant}
\casex{\testveca}{\message{testa^^J}}
\casex{\testvecb}{\message{testb^^J}}
\casex{\testvecc}{\message{testc^^J}}
\casex{\testvecd}{\message{testd^^J}}
\default{\message{default2^^J}}
\endswitch
\def\testwant{\testvecc}
\message{^^J eswitch: ^^J}
\eswitch{\testwant}
\ecase{\testveca}{\message{testa^^J}}
\ecase{\testvecb}{\message{testb^^J}}
\ecase{\testvecc}{\message{testc^^J}}
\ecase{\testvecd}{\message{testd^^J}}
\default{\message{default2^^J}}
\endswitch
% End TeX of LaTeX run
\csname bye\endcsname
\end{document}
%%%%%%%%%%% END OF CODE %%%%%%%%%%%%
I recently had the idea about a switch case statement for use in LaTeX
packages. I needed to check user input (a string) and execute
different macros on different inputs. of a list. Because I could not
find a switch-case statement I implemented it using code like this:
\def\@tempa{foo}
\ifx\@tempa\***@input
...
\else
\def\@tempa{bar}
\ifx\@tempa\***@input
...
\fi\fi
Now I found the time to code a switch-case statement in plainTeX:
My idea about the syntax is:
\switch{<input value>}
\case{<case 1 value>}{<case 1 code}
\case{<case 2 value>}{<case 2 code}
...
\case{<case n value>}{<case n code}
\default{<default code>}
\endswitch
Instead of \endswitch there could also be \hctiws (switch reversed
like \fi for \if).
I also implemented versions of \switch and \case which expand there
argument: \eswitch, \ecase ('e' like 'edef'), or
check the definition instead the content: \switchx, \casex ('x' like
'ifx'). The different \switch and \case macros can be mixed.
The switch-statement stores the code in a macro similar to macros like
\@ifnextchar and uses a TeX group to localise its internal macros. The
code of the selected switch is then executed after the end of the
group. This makes the switch cascade-able and allows the case code to
include macros which read the tokens after the \endswitch.
Here my code. It is not yet fully tested. Comments are very welcome. I
might provide this as a package. Any suggestion about a name? Maybe
'switch' or 'swcase'. 'switchcase' might be too long.
%%%%%%%%%%% switch.tex %%%%%%%%%%%%%
\catcode`\@=\catcode`\A
% Normal (no expansion):
\def\switch#1{%
\begingroup
\let\***@exec\empty
\def\***@want{#1}%
\ignorespaces
}
\def\case#1#2{%
\def\***@might{#1}%
\ifx\***@might\***@want
\def\***@exec{#2}%
\expandafter\***@skiprest
\fi
\ignorespaces
}
% Expansion of the argument ('e' as in 'edef'):
\def\eswitch#1{%
\begingroup
\let\***@exec\empty
\edef\***@want{#1}%
\ignorespaces
}
\def\ecase#1#2{%
\edef\***@might{#1}%
\ifx\***@might\***@want
\def\***@exec{#2}%
\expandafter\***@skiprest
\fi
\ignorespaces
}
% Check definition not content ('x' as in 'ifx'):
\def\switchx#1{%
\begingroup
\let\***@exec\empty
\let\***@want#1\relax
\ignorespaces
}
\def\casex#1#2{%
\ifx\***@want#1\relax
\def\***@exec{#2}%
\expandafter\***@skiprest
\fi
\ignorespaces
}
% Default case. Identical for all different switch statements.
\def\default#1{%
\def\***@exec{#1}%
\***@skiprest
}
\def\***@skiprest#1\endswitch{%
\expandafter\***@realend
\expandafter{\***@exec}%
}
\def\***@realend#1{%
\endgroup
#1%
}
\def\endswitch{%
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Some Testcases:
\newlinechar=`^^J
\def\test#1{%
\switch{#1}
\case{test1}{\message{test1^^J}}
\case{test2}{\message{test2^^J}}
\case{test3}{\message{test3^^J}}
\case{test4}{\message{sub-switch 1:^^J }
\switch{abc}
\case{a}{\message{a^^J}}
\case{ab}{\message{ab^^J}}
\case{abc}{\message{abc^^J}}
\endswitch
}
\case{test5}{\message{sub-switch 2:^^J }\test{test1}}
\default{\message{default^^J}}
\endswitch
}
\message{^^J switch: ^^J}
\test{test1}
\test{test4}
\test{other}
\test{test5}
\def\testveca{test1}
\def\testvecb{test2}
\def\testvecc{test3}
\def\testvecd{test4}
\let\testwant\testvecb
\message{^^J switchx: ^^J}
\switchx{\testwant}
\casex{\testveca}{\message{testa^^J}}
\casex{\testvecb}{\message{testb^^J}}
\casex{\testvecc}{\message{testc^^J}}
\casex{\testvecd}{\message{testd^^J}}
\default{\message{default2^^J}}
\endswitch
\def\testwant{\testvecc}
\message{^^J eswitch: ^^J}
\eswitch{\testwant}
\ecase{\testveca}{\message{testa^^J}}
\ecase{\testvecb}{\message{testb^^J}}
\ecase{\testvecc}{\message{testc^^J}}
\ecase{\testvecd}{\message{testd^^J}}
\default{\message{default2^^J}}
\endswitch
% End TeX of LaTeX run
\csname bye\endcsname
\end{document}
%%%%%%%%%%% END OF CODE %%%%%%%%%%%%