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\user@input ... \else \def\@tempa{bar} \ifx\@tempa\user@input ... \fi\fi
Now I found the time to code a switch-case statement in plainTeX:
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.
>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\user@input > ... >\else >\def\@tempa{bar} >\ifx\@tempa\user@input > ... >\fi\fi
>Now I found the time to code a switch-case statement in plainTeX:
>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.
> >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\user@input > > ... > >\else > >\def\@tempa{bar} > >\ifx\@tempa\user@input > > ... > >\fi\fi
> >Now I found the time to code a switch-case statement in plainTeX:
> >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.
> \def\switch#1{% > \initswitch > \def\switch@want{#2}% or \edef for \eswitch > \let\case\normalcase% or \expandingcase > \ignorespaces}
I had this idea too, but I decided that in some applications different switch and case statements need to be mixed, e.g. a \ecase inside \switch if the case value is given by a expression which must first be expanded. Also a non-expanding \case inside a \eswitch where only the user input muse be expanded. This way the whole thing is much more flexible.
> Or > \def\switch@skiprest#1\endswitch{% > \expandafter\endgroup\switch@exec > }
Thanks for that suggestion. I just learned something.
On Apr 27, 2:41 pm, Martin Scharrer <mar...@scharrer-online.de> wrote:
> 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.
In general, this is done with \csname
\csname IDENT:<sanitized_user_text>\endcsname
where the IDENT string is different from regular macros and for different switch uses.
> On Apr 27, 2:41 pm, Martin Scharrer <mar...@scharrer-online.de> wrote:
> > 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.
> In general, this is done with \csname
> \csname IDENT:<sanitized_user_text>\endcsname
> where the IDENT string is different from regular macros and > for different switch uses.
Thanks, I knew and use this in some packages, too. E.g. a lot in my new package 'tikz-timing' where the user input causes a diagram to be drawn. However, in cases where the user input must be checked in different places (with different case code) this method becomes, IMHO, a little extensive, because a lot of macros must be defined and cascaded switches are not easily possible. However, this solution with \@nameuse {IDENT:<sanit. user input> should be expandable, while my switch statement is not.
> 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\user@input > ... > \else > \def\@tempa{bar} > \ifx\@tempa\user@input > ... > \fi\fi
> > 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\user@input > > ... > > \else > > \def\@tempa{bar} > > \ifx\@tempa\user@input > > ... > > \fi\fi
On Apr 28, 2:27 am, Martin Scharrer <mar...@scharrer-online.de> wrote:
> On Apr 28, 10:01 am, Donald Arseneau <a...@triumf.ca> wrote: > > \csname IDENT:<sanitized_user_text>\endcsname > {IDENT:<sanit. user input> should be expandable, while my switch > statement is not.
It depends on how much sanitization is needed, which can be a problem.
I forget already, is \scantokens expandable? If so, it would be much better for this than the old \def...\meaning.
On Apr 28, 9:14 pm, Donald Arseneau <a...@triumf.ca> wrote:
> On Apr 28, 2:27 am, Martin Scharrer <mar...@scharrer-online.de> wrote:
> > On Apr 28, 10:01 am, Donald Arseneau <a...@triumf.ca> wrote: > > > \csname IDENT:<sanitized_user_text>\endcsname > > {IDENT:<sanit. user input> should be expandable, while my switch > > statement is not.
> It depends on how much sanitization is needed, which can be a problem.
> I forget already, is \scantokens expandable? If so, it would be much > better for this than the old \def...\meaning.
Are you thinking to use \scantokens to verbatim'ise the user input? In this case you need \catcode calls which are assignments (unexpandable) or aren't they?
You don't need sanitization in all cases. \csname expands the macros which allows the user to provide it's input as macro which is normally what you want. If a unexpandable macro is provided \csname will fail (at least I think so) and the user will become the appropriate error message. Then it is his/her problem.
> On Apr 28, 9:14 pm, Donald Arseneau <a...@triumf.ca> wrote:> On Apr 28, 2:27 am, Martin Scharrer <mar...@scharrer-online.de> wrote:
> > > On Apr 28, 10:01 am, Donald Arseneau <a...@triumf.ca> wrote: > > > > \csname IDENT:<sanitized_user_text>\endcsname > > > {IDENT:<sanit. user input> should be expandable, while my switch > > > statement is not.
> > It depends on how much sanitization is needed, which can be a problem.
> > I forget already, is \scantokens expandable? If so, it would be much > > better for this than the old \def...\meaning.
> Are you thinking to use \scantokens to verbatim'ise the user input? In > this case > you need \catcode calls which are assignments (unexpandable) or aren't > they?
Ah right, so still no better than \meaning.
> If a unexpandable macro is provided \csname will fail (at least I > think so) and the user will become the appropriate error message. Then > it is his/her problem.
Yes, it was sanitization of such things that I was thinking about. Your code using \def and \ifx works fine (I expect) with such strings whereas unsanitized \csname will fail.
On Mon, 27 Apr 2009 23:41:17 +0200, Martin Scharrer wrote: > 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\user@input > ... > \else > \def\@tempa{bar} > \ifx\@tempa\user@input > ... > \fi\fi
> Now I found the time to code a switch-case statement in plainTeX:
I the expl3 code we have case switches that look similar to this. From the documentation (in l3prg.dtx) for the function called \prg_case_int:nnn we have
% This function evaluates the first \meta{integer expr} and then compares it % to the values found in the list. Thus the expression % \begin{verbatim} % \prg_case_int:nnn{2*5}{ % {5}{Small} {4+6}{Medium} {-2*10}{Negative} % }{Other} % \end{verbatim} % evaluates first the term to look for and then tries to find this % value in the list of values. If the value is found, the code on its % right is executed after removing the remainder of the list. If the % value is not found, the \meta{else case} is executed. The example % above will return ``Medium''.
Others exist and the code is fairly simple. You might be able to find inspiration in the implementation or come up with suggestions for improvements.